如何在 ESM 中引入 CommonJS 模块

373 阅读1分钟

简介

随着越来越多的 Node.js 项目采用 ESM 作为模块系统,一些较旧的 CommonJS 模块依然被广泛使用。由于这两者的模块系统存在一些差异,我们可能会面临引入 CommonJS 模块到 ESM 项目中的挑战。

这种兼容性问题主要表现为:

  • ESM 模块系统使用 importexport,而 CommonJS 使用 requiremodule.exports
  • Node.js 对文件扩展名(如 .js, .mjs, .cjs)的处理方式不同,可能会导致加载错误。

前提条件

统一模块类型:项目设置为 ESM 模块(package.json 中设置 "type": "module"),所有.js文件默认视为ESM模块,使用.cjs扩展名表示CommonJS模块。

// cjs-file.cjs
module.exports = {
  sayHi(name) {
    console.log(`Hi, ${name} from CommonJS`);
  }
};

在 ESM 中引入 CommonJS 模块的几种方式

方式 1:直接使用 import 默认导入

Node.js 遇到 .cjs 文件时,会强制将其作为 CommonJS 模块处理,即使在 ESM 环境中也允许默认导入。

步骤

  • 确保 CommonJS 模块使用 .cjs 后缀。
// esm-file.js
import cjs from './cjs-file.cjs';

cjs.sayHi('Alice');

优点

  • 减少冗余代码,简洁直观

方式 2:使用 createRequire方法

通过调用createRequire(path)方法,允许你使用同步的 require() 来导入模块。

步骤

  1. 确保 CommonJS 模块使用 .cjs 后缀。
  2. 使用 createRequire 方法来引入 CommonJS 模块。
// esm-file.js
import { createRequire } from 'module';
const require = createRequire(import.meta.url);

const cjs = require('./cjs-file.cjs');
cjs.sayHi('Alice');

优点

  • 同步加载,代码简单直观。
  • 兼容性好,适用于大多数 Node.js 项目。

方式 3:使用动态 import()(异步加载)

当你需要在特定时机导入时,可以使用动态 import() 来加载 CommonJS 模块。由于 import() 是异步的,你需要使用 await.then() 来处理加载。

// esm-file.js
const cjsModule = await import('./cjs-file.js');  // 动态导入
cjsModule.sayHi('Alice');

优点

  • 灵活性高,可以按需加载模块。

欢迎各位伙伴交流与补充