package.json exports / 子入口 / 平台分支的统一规范
package.json 的 exports 字段决定:
import '@skyroc/utils/storage' 能否解析;.d.ts;本仓库的所有发布包都遵循一份统一的 exports 模板,避免下游用法分裂。
{
"type": "module",
"main": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"exports": {
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"./package.json": "./package.json"
}
}要点:
type: "module" 全仓统一;types / default 顺序固定(types 必须在最前,Node 16+ 要求);./package.json 便于工具读取版本 / 依赖;require 字段(不发 CJS)。库提供多个独立子模块时(如 @skyroc/utils、@skyroc/hooks、@skyroc/service):
"exports": {
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"./color": {
"types": "./dist/color.d.mts",
"default": "./dist/color.mjs"
},
"./storage": {
"types": "./dist/storage.d.mts",
"default": "./dist/storage.mjs"
},
"./package.json": "./package.json"
}每个子入口都需要 tsdown 在 entry 中列出,否则 dist 不存在对应文件。
跨平台共享包(如 @skyroc/hooks)通过子入口区分平台:
"exports": {
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"./web": {
"types": "./dist/web.d.mts",
"default": "./dist/web.mjs"
},
"./native": {
"types": "./dist/native.d.mts",
"default": "./dist/native.mjs"
}
}不使用
"browser" / "react-native"条件字段,因为这种「同入口、按 condition 分发」的方式:
- VS Code 类型推断有时挑不出正确平台;
- bundler 可能误判 SSR 环境;
- 调试难度高。
统一约定:跨平台代码用显式子路径(
./web、./native),不用 condition 字段。
部分包还需要暴露非 TS 内容(CSS / 模板 / mock):
"exports": {
".": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" },
"./style.css": "./dist/style.css",
"./mock": { "types": "./dist/mock.d.mts", "default": "./dist/mock.mjs" }
}例子:
@skyroc/web-ui/style.css — 设计系统全局样式;@skyroc/web-admin-notification/mock — 通知中心 mock 数据;@skyroc/tailwind-plugin/preset — UnoCSS preset;@skyroc/web-admin-styles/reset.css — 仅 reset 部分。最常见的 bug:exports 里有 ./color,但 tsdown.config.ts 没把它列入 entry,结果 dist/color.mjs 根本不存在,安装方解析失败。
exports 的每一个子路径,都必须在 tsdown.config.ts 的 entry 里有同名一项,两者一一对应。tsdown 配置写法见 构建体系。
| 项 | 含义 |
|---|---|
dependencies | 直接依赖,被 npm 安装;tsdown 默认 external |
peerDependencies | 由消费方提供(React、antd 等) |
devDependencies | 仅本包开发用,不影响下游 |
tsdown external 显式列表 | 必要时手动追加 |
约定:
react / react-dom 一律 peerDependencies;antd 一律 peerDependencies(仅在 ui-antd 等强绑包出现);@skyroc/* 一律 dependencies(外部化即可);tsdown / vite)写到 dependencies。"sideEffects": false // 纯 ESM 包
"sideEffects": ["*.css", "*.scss", "*.svg"] // 仅样式 / 资源有副作用| 包类型 | sideEffects |
|---|---|
| 纯函数 / 类型 / Hook | false |
| 注入 CSS / 全局副作用(runtime / styles / theme) | 数组列出 |
| 应用 | 不需要 |
错误的 sideEffects: false 会让 bundler 把 CSS 摇掉,导致样式丢失。
"files": [
"dist",
"README.md"
]发布到 npm 时只包含 dist、README.md、package.json(后者自动)。不要打包 src / __tests__ / tsconfig.json。
公开包:
"publishConfig": {
"access": "public"
}私有包:
"private": true@skyroc scope 默认私有,需要发布的包必须显式 access: "public"。
新建 / 修改 exports 后:
entry 与 exports 一一对应;types / default 顺序正确;./package.json;sideEffects 设置正确(默认 false 但 CSS 包要列);files: ["dist"];./web / ./native;pnpm build 产物存在;import 验证;pnpm publint(如已接入)通过。| 错误 | 原因 |
|---|---|
ERR_PACKAGE_PATH_NOT_EXPORTED | exports 没暴露子路径 |
| TS 找不到类型 | types 字段缺失或顺序错误 |
| 产物找不到 | tsdown entry 没列 |
| 双 ESM 实例 | 该包没把 @skyroc/* 标 external |
| RN 报 DOM API 错 | 错把 web-only 代码放进主入口 |
Last updated on