背景
我们都知道 JS 模块化的演变经历了一个漫长的过程,从最初的 CommonJS,到后来的 AMD 和 CMD,再到今天的 ES6 模块化方案。优胜劣汰,对于 JS 这门语言来说,主要用于 Node.js 的模块化方案 CommonJS 活了下来,而 ES6 推出的模块化方案更是赢得了大家的认可,大有可能成为未来 JS 的主要模块化方案。
CommonJS 模块方案在 Node.js 很常用,但随着 Node.js 也开始支持 ES6 的模块化方案,不少第三方库转为了使用 ES6 模块方案,本文将介绍如何在 Node.js 上使用 TypeScript 和 ES6 模块。
给 package.json 添加 type 属性
Node.js 新增支持了 package.json
的 type
属性,可以设置为 "module"
或 "commonjs"
,不设置则默认为 "commonjs"
,这里要设置为 "module"
{
"name": "my-package",
"type": "module",
"//": "...",
"dependencies": {
}
}
设置为 module
时将 .js
文件视为 ES6 模块
设置为 commonjs
时将 .js
文件视为 CommonJS 模块
详细阅读:
ECMAScript Modules in Node.js
tsconfig.json 配置
{
"compilerOptions": {
"module": "node16",
"moduleResolution": "node16",
"strict": true,
"removeComments": true,
"preserveConstEnums": true,
"outDir": "dist"
},
"ts-node": {
"esm": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
-
module 表示我们在 ts 文件中引入模块时使用什么方式,这里设置为 node16
使用相对路径引入自定义模块,需要添加后缀名,要注意,引入的文件是 ./foo.ts,但这里要写 .js 后缀,因为 ts 文件最后会编译为 js 文件
// 引入第三方模块
import fetch from "node-fetch";
// 相对路径引入自定义模块
import { helper } from "./foo.js";
-
moduleResolution 表示寻找模块的方式,这里设置为 node16
-
ts-node 配置 esm 属性,这样 ts-node 直接运行 ts 文件时可以正确处理 ES6 模块,如果不使用 ts-node,可以不设置
详细阅读:
Modules
Module Resolution
在 ES 模块中引入 CommonJS 模块
如果我们使用的第三方模块是 CommonJS 的方式编写的,那么在 ES6 模块中也可以引入 CommonJS 模块。
ES6 模块的 import 命令可以加载 CommonJS 模块,但是只能整体加载,不能只加载单一的输出项。
// 正确
import packageMain from 'commonjs-package';
// 报错
import { method } from 'commonjs-package';
这是因为 ES6 模块需要支持静态代码分析,而 CommonJS 模块的输出接口是 module.exports,是一个对象,无法被静态分析,所以只能整体加载。
加载单一的输出项,可以写成下面这样。
import packageMain from 'commonjs-package';
const { method } = packageMain;
详细阅读:
Node.js 如何处理 ES6 模块