跳到主要内容

Node 项目支持 ESModule

1. 通过 webpack 完成 ES Module 资源构建

  1. 安装 webpack 包 npm i webpack webpack-cli -D

  2. 创建 webpack 配置文件 webpack.config.js

    const path = require('path')

    module.exports = {
    mode: 'development',
    entry: './transESModule/index.js',
    output: {
    filename: 'core.js',
    path: path.join(__dirname, '/dist'),
    },
    // 注意这里要修改为 node 以支持 Node 内置库的使用
    target: 'node',
    }
  3. 添加构建指令 package.json

    "scripts": {
    "build": "webpack",
    "dev": "webpack -w"
    },
  4. 执行打包构建 npm run build

  5. 修改node引用文件

    #!/usr/bin/env node

    require('../dist/core')
  6. 添加bable将高级语法进行转换支持低版本node

    https://webpack.docschina.org/loaders/babel-loader/

    • 安装库 npm i -D bable-loader @bable/core @bable/preset-env @babel/plugin-transform-runtime @babel/runtime-corejs3

    • 修改 webpack 配置文件

      module.exports = {
      module: {
      rules: [
      {
      test: /\.m?js$/,
      exclude: /node_modules/,
      use: {
      loader: 'babel-loader',
      options: {
      presets: ['@babel/preset-env'],
      plugins: [
      [
      '@babel/plugin-transform-runtime',
      {
      corejs: 3,
      regenerator: true,
      useESModules: true,
      helpers: true,
      },
      ],
      ],
      },
      },
      },
      ],
      }
      }

2. 通过 Node 原生支持 ES Module

Node.js 从 v16 开始为 ESM 提供默认支持。 在早期版本中,需要使用 --experimental-modules 选项来激活该功能。

默认情况下,Node 不支持以 .js 扩展名结尾的内部文件的导入和导出。 可以将文件后缀设为 .mjs,其中 ESM 始终可用,或者修改 package.json 文件使其包含 "type":"module"

{
...
"type": "module",
...
}

对于专门使用 ESM 的项目,选择后一种方法通常更方便。 Node 使用 type 字段来确定项目的默认模块系统。 该模块系统始终用于处理普通的 .js 文件。 当不手动设置时,CJS 是默认的模块系统,以最大限度地与现有的 Node 代码生态系统兼容。 具有 .cjs.mjs 扩展名的文件将始终分别被视为 CJS 和 ESM 格式的源码。

从 ESM 导入 CommonJS 模块

可以使用常规导入语句在 ESM 文件中导入 CJS 模块:

// cjs-module.cjs
module.exports.helloWorld = () => console.log("Hello World");

// esm-module.mjs
import component from "./cjs-module.cjs";
component.helloWorld();

// 或者使用下面的方式
import { helloWorld } from "./cjs-module.cjs";
helloWorld();

从 CJS 导入 ESM 模块

当我们想在现有 CJS 代码中使用新的 ESM 模块时,事情会变得更加棘手。 我们不能在 CJS 文件中使用 import 语句。 然而动态 import() 语法确实有效,并且可以与 await 配合从而相对方便地访问模块:

// esm-module.mjs
const helloWorld = () => console.log("Hello World");
export { helloWorld };

// esm-module-2.mjs
export default = () => console.log("Hello World");

// cjs-module.cjs
const loadHelloWorld = async () => {
const { helloWorld } = await import("./esm-module.mjs");
return helloWorld;
};
const helloWorld = await loadHelloWorld();
helloWorld();

const loadHelloWorld2 = async() => {
const helloWorld2 = await import("./esm-module-2.mjs");
return helloWorld2;
};
const helloWorld2 = await loadHelloWorld2();
helloWorld2();

此结构可用于异步访问 ESM 模块的默认导出和命名导出。