在NodeJs项目中使用ECMAScript module
随着 Nodejs v16
成为长期稳定支持的版本,ESM
也随之成为 NodeJs
正式支持的标准化模块系统,这允许我们通过 ESM
来开发我们的 NodeJs
项目,并在项目中通过ESM
来导入其他的ESM
包。
创建项目
我们以新建一个 NodeJs 项目为例, 它有如下的结构:
./my-esm-package
├── lib
│ ├── resolve.js
│ └── index.js
└── package.json
这个项目的功能是导出一个 resolve 方法,是 path.resolve
的封装实现。
export * from './resolve.js'
import path from 'path'
export const resolve = (...arg) => path.resolve(...arg)
package.json
在 package.json
中,我们需要进行以下声明:
声明
type
字段值为module
这个字段声明了你的包将作为一个
ECMAScript module
被NodeJs
加载并解析,并允许使用.mjs
格式的文件。声明
exports
字段该字段描述了 项目如何导出模块给到其他包使用。
默认导出
package.json{ "exports": "./lib/index.js" }
即当使用
import { resolve } from 'my-esm-package'
时,默认引入的文件是lib/index.js
。导出多个模块
package.json{ "exports": { ".": "./lib/index.js", "resolve": "./lib/resolve.js" } }
声明了导出了两种模块:一个是默认导出,使用
"."
作为key;一个是具名导出。当使用
import { resolve } from 'my-esm-package'
时,默认引入的文件是lib/index.js
。当使用
import { resolve } from 'my-esm-package/resolve'
时,引入的文件是lib/resolve.js
。exports
还支持其他形式的值,这里暂不赘述。
声明
engines
字段由于
Nodejs
并不是全版本支持esm
的,而是从v14.16.0
版本开始试验性的支持,并到了v16
版本才作为正式支持, 且当前v16
版本作为目前的长期稳定支持的版本。这个项目运行环境的NodeJs
版本,最低应该推荐使用v16
以上的版本。 即它的值应该为{ "node": ">=16" }
到这里,这个项目的package.json
文件,包含以下内容:
{
"name": "my-esm-package",
"description": "My first esm package.",
"type": "module",
"exports": {
".": "./lib/index.js",
"resolve": "./lib/resolve.js"
},
"engines": {
"node": ">=16"
}
}
编写项目代码
由于是一个
esm
项目,所以理所当然的不能项目中使用require()
/module.exports
来导入导出模块。 而是应该全部使用import
/export
的方式来导入导出模块。不需要在项目代码中 使用
use strict
。由于
esm
项目中,NodeJs
不再支持__dirname
/__filename
,所以有相关场景需要使用时,需要使用其他的方式来实现相同功能:
import { dirname, basename } from 'path'
import { fileURLToPath } from 'url'
const _dirname = typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url))
const _filename = typeof __filename !== 'undefined' ? __filename : basename(fileURLToPath(import.meta.url))
TypeScript
如果在项目中使用了 TypeScript
,那么除了需要遵循以上的内容,还需要在 tsconfig.json
配置文件中补充以下配置:
{
"module": "node16",
"moduleResolution": "node16"
}
并且,应该将 .ts
文件,编译为 .js
文件,package.json
配置的 exports
导出的,是编译后的 .js
文件。
最后
当完成了以上步骤,就可以得到一个NodeJs ESM
项目。它也只能在另一个支持 esm
的项目中使用。