ECMAScript Modules (ESM) 是 JavaScript 的一种模块化规范,自 Node.js 12 版本开始引入支持

ECMAScript Modules (ESM) 是 JavaScript 的一种模块化规范,自 Node.js 12 版本开始引入支持。与传统的 require() 功能不同,它使用 import 关键字来导入模块,不允许直接通过 require() 导入 .mjs 扩展的 ESM 文件,因为这些文件是为了利用现代 JavaScript 的模块导出和加载方式设计的。

动态导入 (dynamic import()) 可以在 CommonJS 和 ESM 中使用。这意味着即使在编写传统的 CommonJS 模块时,也可以通过 import() 动态加载 ES 模块,增加了代码的灵活性。

举个例子:

// 使用 dynamic import
async function loadModule() {
   
  try {
   
    const importedModule = await import('./my-esm-file.mjs');
    // 使用导入的模块
    console.log(await importedModule.default());
  } catch (error) {
   
    console.error('Failed to load ESM module:', error);
  }
}

loadModule();

在这个例子中,我们不能直接 require('./my-esm-file.mjs'),而是使用 import 并等待其异步加载完成。
要在Node.js中启用对ESM (ECMAScript 模块) 的支持,你可以考虑以下几个步骤:

  1. 更新Node.js版本:确保你使用的Node.js版本至少是14或更高,因为这些版本开始支持在顶层作用域中使用await语句。

    nvm install node --lts # 如果你使用nvm管理node版本
    npm i -g node # 或者全局安装最新版本
    
  2. 确认package.json配置:检查你的package.json文件中的type字段,如果它是 "module",说明你的项目已经设置了以ESM模式运行。确保main字段指向正确的CommonJS入口点,以便Node.js能够识别并执行它。

    {
         
      "type": "commonjs", // 或者删除 type 字段,默认为 commonjs
      "main": "index.js"
    }
    
  3. 逐步引入ESM:如果你的代码中存在顶层的 await import(),尝试将其移动到模块内部,或者创建一个专门用于导入外部库的函数。

    // 原始错误代码(不推荐)
    await import('source-map-support');
    
    // 更改为:
    if (process.env.NODE_ENV !== 'production') {
         
      const sourceMapSupport = await import('source-map-support');
      sourceMapSupport.install();
    }
    
  4. 使用--experimental-modules标志:在早期版本的Node.js中,可以通过命令行参数临时启用ESM支持:

    node --experimental-modules yourfile.js
    

请注意,尽管上述步骤可以解决问题,但最好还是升级到Node.js 14以上,因为它已经完全支持ESM作为标准特性。长期来看,保持项目的ESM兼容性是最佳实践。

Index View on single page View as JSON View another version ▼ 

Edit on GitHub 

Table of Contents

ECMAScript Modules
    Introduction

    Enabling
        package.json "type" field
        Package Scope and File Extensions
        --input-type flag

    Packages

        Package Entry Points
            Main Entry Point Export
            Subpath Exports
            Package Exports Fallbacks
            Exports Sugar
            Conditional Exports
            Nested conditions
            Self-referencing a package using its name

        Dual CommonJS/ES Module Packages
            Dual Package Hazard

            Writing Dual Packages While Avoiding or Minimizing Hazards
                Approach #1: Use an ES Module Wrapper
                Approach #2: Isolate State

    import Specifiers

        Terminology
            data: Imports
    import.meta

    Differences Between ES Modules and CommonJS
        Mandatory file extensions
        No NODE_PATH
        No require, exports, module.exports, __filename, __dirname
        No require.resolve
        No require.extensions
        No require.cache
        URL-based paths

    Interoperability with CommonJS
        require
        import statements
        import() expressions
    CommonJS, JSON, and Native Modules
    Builtin modules
    Experimental JSON Modules
    Experimental Wasm Modules

    Experimental Loaders

        Hooks
            resolve hook
            getFormat hook
            getSource hook
            transformSource hook
            getGlobalPreloadCode hook
            dynamicInstantiate hook

        Examples
            HTTPS loader
            Transpiler loader

    Resolution Algorithm
        Features
        Resolver Algorithm
        Customizing ESM specifier resolution algorithm

ECMAScript Modules

Stability: 1 - Experimental

Introduction

ECMAScript modules are the official standard format to package JavaScript code for reuse. Modules are defined using a variety of import and export statements.

Node.js fully supports ECMAScript modules as they are currently specified and provides limited interoperability between them and the existing module format, CommonJS.

Node.js contains support for ES Modules based upon the Node.js EP for ES Modules and the ECMAScript-modules implementation.

Expect major changes in the implementation including interoperability support, specifier resolution, and default behavior.
Enabling

The --experimental-modules flag can be used to enable support for ECMAScript modules (ES modules).

Once enabled, Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements within ES module code:

Files ending in .mjs.

Files ending in .js when the nearest parent package.json file contains a top-level field "type" with a value of "module".

Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=module.

Node.js will treat as CommonJS all other forms of input, such as .js files where the nearest parent package.json file contains no top-level “type” field, or string input without the flag --input-type. This behavior is to preserve backward compatibility. However, now that Node.js supports both CommonJS and ES modules, it is best to be explicit whenever possible. Node.js will treat the following as CommonJS when passed to node as the initial input, or when referenced by import statements within ES module code:

Files ending in .cjs.

Files ending in .js when the nearest parent package.json file contains a top-level field "type" with a value of "commonjs".

Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=commonjs.

package.json “type” field

Files ending with .js will be loaded as ES modules when the nearest parent package.json file contains a top-level field “type” with a value of “module”.

The nearest parent package.json is defined as the first package.json found when searching in the current folder, that folder’s parent, and so on up until the root of the volume is reached.

// package.json
{
“type”: “module”
}

In same folder as above package.json

node --experimental-modules my-app.js # Runs as ES module

If the nearest parent package.json lacks a “type” field, or contains “type”: “commonjs”, .js files are treated as CommonJS. If the volume root is reached and no package.json is found, Node.js defers to the default, a package.json with no “type” field.

import statements of .js files are treated as ES modules if the nearest parent package.json contains “type”: “module”.

// my-app.js, part of the same example as above
import ‘./startup.js’; // Loaded as ES module because of package.json

Package authors should include the “type” field, even in packages where all sources are CommonJS. Being explicit about the type of the package will future-proof the package in case the default type of Node.js ever changes, and it will also make things easier for build tools and loaders to determine how the files in the package should be interpreted.

Regardless of the value of the “type” field, .mjs files are always treated as ES modules and .cjs files are always treated as CommonJS.
Package Scope and File Extensions

A folder containing a package.json file, and all subfolders below that folder down until the next folder containing another package.json, is considered a package scope. The “type” field defines how .js files should be treated within a particular package.json file’s package scope. Every package in a project’s node_modules folder contains its own package.json file, so each project’s dependencies have their own package scopes. A package.json lacking a “type” field is treated as if it contained “type”: “commonjs”.

The package scope applies not only to initial entry points (node --experimental-modules my-app.js) but also to files referenced by import statements and import() expressions.

// my-app.js, in an ES module package scope because there is a package.json
// file in the same folder with “type”: “module”.

import ‘./startup/init.js’;
// Loaded as ES module since ./startup contains no package.json file,
// and therefore inherits the ES module package scope from one

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bol5261

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值