本文主要梳理一下Node中关于模块化的一些字段
Node.js 运行时如何加载模块
1.type
{
"type": "module"
}
可选值
"module"→ ES Module(ESM)"commonjs"(默认)→ CommonJS(CJS)
| 文件 | type=module | type=commonjs |
|---|---|---|
.js | ESM | CJS |
.mjs | ESM | ESM |
.cjs | CJS | CJS |
2.main
旧时代入口(CommonJS 入口)
{
"main": "index.js"
}
3.module
不是 Node 标准字段!是给打包工具(webpack/rollup)用的ESM入口
{
"module": "dist/index.esm.js"
}
4.exports
官方推荐,完全替代 main + module
- 控制入口
- 区分 ESM / CJS
- 控制子路径导出
{
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
}
}
访问方式
import x from 'pkg'
import y from 'pkg/utils'
// 下面这样是不允许的
import z from 'pkg/dist/xxx' ❌
5.types/typings
给 TypeScript 用的类型入口
{
"types": "dist/index.d.ts"
}
TypeScript / 构建工具如何解析模块
这些字段不在 package.json,而是在 tsconfig.json。有些字段名和package.json里是一样的,注意区分
1.module
{
"compilerOptions": {
"module": "ESNext"
}
}
决定 TS 编译输出的模块格式,常见:
CommonJSESNextNodeNext
2.moduleResolution
{
"compilerOptions": {
"moduleResolution": "NodeNext"
}
}
决定 TS 如何解析 import 路径
常见模式
① node(旧)
- 不支持 ESM package 规则
- 忽略
exports
👉 已逐渐淘汰
node16
②模拟 Node 16 行为:
- 支持
type - 支持
exports - 根据
.js/.mjs/.cjs判断
③ nodenext(推荐)
👉 完整模拟 Node ESM 行为
支持:
exportsimports- 条件导出
- ESM / CJS 混用
👉 写现代库必须用这个
总结
1️⃣ Node 运行规则
typeexportsmain
👉 决定:代码怎么执行
2️⃣ 构建 / TS 规则
modulemoduleResolution
👉 决定:代码怎么被编译 & 找到依赖
最佳实践
package.json
{
"type": "module",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"types": "./dist/index.d.ts"
}
tsconfig.json
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"outDir": "dist"
}
}