如何把CommonJS项目改成ESM模块系统
(最初发布于 deno.com/blog。)
ECMAScript 模块(“ESM”)是编写和共享 JavaScript 的官方现代化方式——它在多种环境中都得到了支持(例如浏览器、现代运行时如 Deno),并且提供了更好的开发体验(例如异步加载和无需全局变量即可直接导出)。虽然 CommonJS 许多年以来一直是标准,但支持 CommonJS 实际上正在阻碍 JavaScript 社区的发展。
所有新的 JavaScript 代码都应使用 ESM 编写,以确保未来的兼容性。然而,出于与较新包兼容的原因,许多遗留的代码库需要现代化改造。这篇文章中,我们将教你如何把一个旧的 CommonJS 项目迁移到支持 ESM 的项目,并推荐一些工具来帮助你更顺利地完成这个迁移过程。
- 模块导入和导出
[更新 package.json](https://deno.com/blog/convert-cjs-to-esm#update-packagejson)
[package.json](https://deno.com/blog/convert-cjs-to-esm#update-packagejson)
- 其他变更
- 迁移工具
- 接下来做什么
注释:模块引入和输出想要用现代的方式编写 JavaScript 和 TypeScript,而不必处理繁琐的配置或模板代码吗?
试试Deno,它是一个“开箱即用”的默认安全的一站式工具链,无需额外配置,支持原生的TypeScript和Web 标准 API。
下面是将 CommonJS 的导入和导出更新为 ESM 的方法。
在出口方面:
// 添加数字函数
// function addNumbers(num1, num2) {
// 导出添加数字函数
export function addNumbers(num1, num2) {
return num1 + num2;
};
// 导出模块
// module.exports = {
// addNumbers,
// }
在进口这一方面:
- const { addNumbers } = require("./add_numbers");
+ import { addNumbers } from "./add_numbers.js";
console.log(addNumbers(2, 2));
(注:-
和 +
符号用于表示代码中的更改)
注意,在 ESM 中,模块路径必须包含文件扩展名。完整的导入路径可以减少歧义,确保每次解析时都能正确导入文件。此外,这与浏览器如何处理模块导入的方式相同,使得编写可预测且易于维护的同构代码变得更加容易。
那条件导入呢?如果你用的是 Node.js v14.8 或更高版本(或者 Deno),就可以用顶级 await 来让 import
变成同步的。
- const module = boolean ? require("module1") : require("module2"); // 根据布尔值条件,使用require加载模块
+ const module = await (boolean ? import("module1") : import("module2")); // 根据布尔值条件,使用异步import加载模块,await确保异步操作完成
编辑一下 package.json
文件
如果你使用 package.json
,你可能需要做一些调整来支持 ESM:
{
"name": "my-project",
"type": "类型",
"main": "index.js",
"exports": "./index.js",
// ...
}
在 ESM 中,开头的 "./"
是必需的,因为每个引用路径都必须包含完整路径,包括目录和文件扩展名。
此外,"main"
和 "exports"
都定义了项目的入口。然而,"exports"
是较 "main"
更现代的选择,它支持多个入口点和环境间的条件解析,允许作者清晰地定义包的公共接口,并防止定义在 "exports"
之外的其他入口。
{
"name": "my-project",
"type": "模块类型",
"exports": {
".": "./index.js",
"./other": "./other.js"
}
}
最后,另一种让 Node 运行 ESM 文件的方式是使用 .mjs
文件扩展名。如果你只想将单个文件转换为 ESM,这非常有用。但如果你的目标是转换整个代码库为 ESM,那么更简单的方法是修改 package.json
文件中的 type
。
由于在 ESM 中 JavaScript 会自动进入严格模式(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode),你可以从代码库中移除所有 "use strict";
。
- "use strict";
CommonJS 还支持一些 ESM 中没有的内置全局变量(例如 __dirname
和 __filename
)。一种简单的解决办法是使用一个简单的 shim 来填补这些值的空缺:
// Node 20.11.0+, Deno 1.40.0+ 版本以上
const __dirname = import.meta.dirname;
const __filename = import.meta.filename;
// 之前是
const __dirname = new URL(".", import.meta.url).pathname;
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
迁移工具包
虽然上述内容谈到将 CommonJS 代码库转到 ESM 所需的更改,还有一些工具可以帮助完成这一转换。
使用VSCode,你可以快速将所有 CommonJS 的导入和导出语句转换为 ESM。只需将鼠标悬停在 require
上,然后点击“快速修复”选项,该文件中的所有这些语句都将更新为 ESM。
VSCode提供了一个将CommonJS模块引入转换成ESM模块导入的快速解决方案。
你会发现 VSCode 可以自动替换导入和导出的正确关键字,但是这些指定符缺少文件扩展名。你可以通过运行[**deno lint --fix**](https://docs.deno.com/runtime/manual/tools/linter/)
快速添加它们。Deno 的代码检查器自带了一个 no-sloppy-imports
规则,当导入路径中缺少文件扩展名时,该规则会显示代码检查错误。
为了更端到端地将 CommonJS 转换为 ESM,有几种转译选项。例如,可以使用 npm 包 cjs2esm 和 cjstoesm,以及名为 babel-plugin-transform-commonjs 的 Babel 插件。不过,这些工具可能不再活跃维护且可能功能不全,所以在评估这些工具时,请注意这一点。
下一步会是啥ESM 是 JavaScript 中分享代码的标准方式,所有新的 JavaScript 代码都应当支持 ESM。选择现在支持 CommonJS 对模块作者和不希望处理遗留兼容性问题的开发人员来说可能会非常痛苦。事实上,我们的开源现代 JavaScript 注册表 JSR 明确禁止使用 CommonJS。我们鼓励每个人都为提升 JavaScript 生态系统贡献自己的力量。
🚨️试试今天的 Deno 2 吧。🚨️
Deno 兼容 Node/npm,内置包管理器,一体化零配置工具套件 ,原生 TypeScript 支持功能 ,等等。
共同学习,写下你的评论
评论加载中...
作者其他优质文章