你应该使用 esm
Markdown 标题应该有链接 ID #682
总结:
您现在就可以在节点中使用 JavaScript 模块而无需进行转换,只需npm -S esm
使用node -r esm foo.js
. 运行您的应用程序即可。将其添加"esm": "auto"
到 package.json 的顶层,以便在同一应用程序中轻松透明地加载模块和 cjs。
如果您一直读到这里,请继续阅读,了解我们如何走到这一步。
历史
历史上,JavaScript 仅限于浏览器。开发人员使用了许多技术来构建代码,所有这些技术基本上都是对全局变量的抽象。在这些解决方案中,一种名为 CommonJS(或“cjs”)的广受欢迎的方案应运而生。
const { foo } = require('./bar')
const baz = foo + "qux"
module.exports = {
quux: [baz]
}
CJS 在 JS 开发者中广受欢迎,主要是因为它是 NodeJS 使用的模块系统。前端开发者可以使用webpack等工具将基于 CJS 的应用程序打包成浏览器可以加载和运行的单文件脚本。
一个代码库可以(经过一定程度的工具争论)在服务器和客户端上运行的概念导致了诸如服务器端渲染、NativeScript/React Native 以及 webpack、babel等工具的激增,而其他工具则成为JS 开发不可协商的先决条件。
2015年,ECMAScript 6版本发布,其中包含语言级模块的语法。
import { foo } from './bar.js'
const baz = foo + "qux"
export const quux = [baz]
这些模块是静态的和仅限顶层的,这意味着您无法执行以下操作。
const moduleName = "foo" + "bar"
if (baz) {
// nope!
import { quz } from moduleName
}
CJS 用户已经习惯了。另一方面,JS 模块是静态可分析的,这意味着像Rollup这样的新型工具可以分析 JS 文件,并执行诸如 tree-shaking(从 bundles 中移除未使用代码的过程)之类的有用操作。这有助于开发人员减少代码编写量,从而提高网站对用户的加载速度。
附注:动态导入模块的提案已进入第 3 阶段,并已在多个浏览器中可用
模块如何加载以及模块图(表示模块之间功能关系的逻辑结构)的具体细节留给了实现者,即浏览器供应商和节点维护者。
浏览器厂商率先制定了加载器规范,但对于已经有模块系统的node来说情况就比较复杂了,截止到今天,虽然已经很接近了,但还没有最终的方案出现。
转译
当 ES2015 规范(当时称为 ES6 或“harmony”)发布时,一个名为 5-to-6(后来更名为 Babel)的项目应运而生,它可以让 JS 程序员使用 ES6 的强大新功能编写应用程序,同时提供旧版浏览器和 Internet Explorer 可以支持的代码。
将一种语言或一种语言的某个版本翻译成另一种语言或语言的某个版本的过程称为transpiling,它是 trans*lating 和 com*piling 的混合词。
Babel 已经发展成为 JavaScript 的一把“瑞士军刀”。它可以兼容各种 JavaScript 版本,甚至兼容各种不同的语言,并将它们整合成可在浏览器中运行的代码。
问题
Babel 为 Web 开发者带来了巨大的益处。它使得新功能或拟议功能能够在浏览器实现之前就被大规模地探索,这有助于揭示这些功能的一些特殊情况,从而形成更完善的规范。此外,它在 Web 开发从面向对象/过程式范式向更具函数式范式的巨变中也发挥了巨大作用。Babel 也构成了当今 Web 开发者可用的各种工具和产品的基础……
...但没有必要这样做,而且有时这可能会带来一些问题。
转译的成本
开发人员 Jamie K. 说得很好:
为现代浏览器(包括 IE8)提供大型、一刀切的打包方案的商业可行性正在迅速减弱。差异化服务等现代技术使我们能够为性能强大的浏览器提供优化、精简的 ES2018 代码包,同时为性能较差的浏览器保留臃肿、经过转译的打包方案。此外,对于那些并非绝对需要支持 IE11 的应用来说,支持老旧且不安全的浏览器实际上是不负责任的,因为用户可以而且应该使用最新、最好的浏览器。
原则和认知负荷
在 Node 的世界里,转译也伴随着成本。维护 Babel 配置并非易事。更重要的是,转译会巧妙地传达出“这段代码本身不行,需要额外处理才能行”的信息,即使 CJS 领先一步,我们也不应该对原生模块说这样的话。
esm
:一个简单的解决方案
esm
是由微软开发者、lodash 开发者John-David Dalton等人开发的一款优秀软件包。它是一个模块加载器,可以在运行时转换 ES 模块,而不是对其进行转译。
有了esm
,难以捉摸的“互操作性”就变得轻而易举了。您可以毫不费力地混合搭配原生模块和 CJS 模块。
你甚至可以使用大多数命令行 Node 应用!例如,优秀的tape
测试库没有提供开箱即用的模块支持,但你可以轻松地添加它,如下所示:
npx tape -r 'esm' './**/*.test.js'
概括
下次您有一个 node.js 项目时,在您开始编写 babel 配置以转换模块之前,请esm
尝试一下。