logo科技微讯

Node.js 两种模块方案:require、import 的区别和语法

作者:科技微讯
日期:2022-11-18
📝 笔记

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

CommonJS

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

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

ES Module

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

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

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

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

You also need to make sure you're on the latest minor version of Node.js. At minimum Node.js 16. 出处

下面是一个 ES 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

以下是对这个 ES 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,要开启 ESM,主要有两种方法:

  • 把文件后缀改为 .mjs,只有 .mjs 文件会变成 ESM,其他都是 CommonJS;
  • 在 package.json 中添加 "type":"module",除了 .cjs 其他都是 ESM;

sindresorhus 用的是第二种方案,但他不会兼容 CommonJS,所以不会有 .cjs

ES modules、CommonJS 的部分区别

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";

相关笔记:

  • Typescript 引入模块的三种写法:Typescript 可以用在前端项目,也可以用在 Node.js 后端项目,在 Next.js、Gatsby.js 等前端框架的页面中,往往可以同时使用 CommonJS、ESM 模块,因为这些前端框架已经内置了一些配置,最后都会用 babel、swc 等 compiler 把代码转换为浏览器支持的格式,而如果用在后端 Node.js,则不一定能同时使用 import 和 require;
  • Node.js 项目配置 Typescript 的方法:这个笔记整理了在 Typescript 下使用 ESM 的配置方法;
donation赞赏
thumbsup0
thumbsdown0
暂无评论