科技微讯

CommonJS require vs. ES6 import

这个笔记记录 Node.js 引入模块的两种方案及其语法。

CommonJS

CommonJS 是 Node.js 默认使用的模块导出和引入方式,使用 module.exportsrequire 关键词。注意 exports 只是 module.exports 的替身,真正被导出的是 module.exports 对象。

const module = { exports: {} };
const exports = module.exports;
return module.exports;

ES6 module

早在 2017 年,Node.js 8.9.0 就开始探索性地通过 --experimental-modules 支持 ES module,但当时 .js 后缀还无法使用 exportimport,需要改为 .mjs。2019 年 Node.js 提出了一套新的 ES module 方案,这时 .js 终于支持 export import,新方案还在 package.json 增加了 "type":"module" 配置项。新方案从 Node.js 12 开始支持,但依然需要 --experimental-modules 开启。

2019 年 11 月 Node.js 13.2.0 发布,执行 ES module 终于不再需要 --experimental-modules,但会在 console 打印 ExperimentalWarning: The ESM module loader is experimental. 警告信息。

2020 年 4 月发布的 Node.js 14 删除了这条警告信息,但官方表示 ES module 依然处于 experimental 阶段。直到 2020 年 11 月发布的 Node.js 15.3.0 才终于把对 ES module 的支持标记为 stable 状态

Node.js 的 LTS 版本号都是偶数,官方也建议大多数开发者使用 LTS 版本,大多数云函数服务内置的 Node.js runtime 也是 12.x、14.x、16.x 这些偶数版本,所以我们可以认为从 Node.js 16 开始,我们才终于可以放心地使用 ES module。

下面是一个 module,这个例子展示了 export 的多种方法:

const a = 1;
export default a; //default export
export const b = 2; //name export 一个变量
const c = 3;
const d = 4;
export { c as _c, d }; //name export 多个变量,注意 as 关键词
export * as utilities from "./utilities"; //re-export

以下是对这个 module 的多种 import 方法:

import module from "./module.mjs"; //这样写会拿到 default export
console.log(module); //1
import * as module from "./module.mjs"; //这样写会拿到 export 的所有值
console.log(module.default); //1
console.log(module.a); //undefined
console.log(module.b); //2
console.log(module.c); //undefined
console.log(module._c); //3
import { b, _c } from "./module.mjs"; //这样写会拿到部分值
console.log(b, _c); //2, 3
import { b as _b, _c as __c } from "./module.mjs"; //改名
console.log(_b, __c); //2, 3

Node.js 默认使用 CommonJS,要开启 ES module,主要有两种方法:

empty import

有时候不需要 import 什么东西,只是需要执行这个 module,这时候可以使用 empty import。

Empty import: only loads the module, doesn’t import anything. The first such import in a program executes the body of the module. 出处

这些 module 也不会 export 什么东西,只是可能会给全局变量增加一些属性。

Some modules do not export any variables and only have side-effects, such as mutating the global window (global variables) or prototypes (e.g. polyfills). To execute the body of these modules, they can be imported without specifying any variable names. It will be executed only once, because modules in JavaScript are singletons. 出处

在 React 应用中我们经常 empty import 一个 css 文件,再比如使用 prism

import "prismjs";
import "prismjs/components/prism-bash.min";
import "prismjs/components/prism-javascript.min";
import "prismjs/components/prism-json.min";
import "prismjs/components/prism-jsx.min";

相关笔记:

暂无评论