package.json 的 "exports" 字段显式声明公共入口和子路径导出规则,取代 main/module/types 等字段,默认屏蔽未声明子路径;支持 ESM/CommonJS/类型声明、条件导出及通配符(需谨慎使用)。

在 Node.js 中,package.json 的 "exports" 字段用于**显式声明包的公共入口和子路径导出规则**,它会完全取代传统的 main、module、types 等字段(除非在 exports 中显式代理),并**默认屏蔽所有未声明的子路径访问**(比如 require('pkg/internal/utils') 会报错)。这是实现“封装性”和“意图明确导出”的关键机制。
基础写法:定义默认入口和命名子路径
以下是一个典型配置,支持 ESM 和 CommonJS,并导出多个子路径:
{
"name": "my-lib",
"type": "module",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./utils": {
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs"
},
"./constants": "./dist/constants.js",
"./package.json": "./package.json"
}
}
说明:
-
"."是默认入口,对应import 'my-lib'或require('my-lib'); -
"./utils"是一个显式允许的子路径,对应import 'my-lib/utils'; -
"./package.json"是常见需求——允许消费者读取自身 package.json(如获取 version); - 未列出的路径(如
./src/xxx、./lib/internal)全部被禁止,Node.js 会抛出ERR_PACKAGE_PATH_NOT_EXPORTED错误。
支持类型声明(TypeScript)
若提供 TypeScript 类型,需在对应子路径中同时声明 types(或 types 字段):
"./utils": {
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs",
"types": "./dist/types/utils.d.ts"
}
注意:types 不是标准字段,但 TypeScript 和主流工具(如 VS Code、tsc)识别它。也可用条件导出统一处理:
"./utils": {
"types": "./dist/types/utils.d.ts",
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs"
}
禁止所有子路径(仅保留主入口)
如果只想暴露根入口,**不声明任何 ./xxx 条目即可**。但要注意:即使没写 "./package.json",也建议显式添加,否则 import pkg from 'my-lib/package.json' 也会失败:
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./package.json": "./package.json"
}
高级:条件导出 + 模式匹配(Node.js ≥ 18.12)
可使用 "*" 通配符(需配合 "default" 回退)实现灵活子路径,但要谨慎——它会放宽封装性:
"exports": {
".": "./dist/index.js",
"./features/*": "./dist/features/*.js",
"./": "./dist/" // ❌ 危险!等价于开放全部子路径
}
更安全的写法是只对明确模式放行:
-
"./features/*"允许import 'pkg/features/a'→ 解析为dist/features/a.js; - 避免裸
"./"或"*",否则破坏封装意图; - 通配路径仍受文件存在性检查,不存在的
features/xxx仍会报错。


















