package.json 文件中常用字段
package.json 是 Node.js 项目的核心配置文件,它定义了项目的元数据、依赖关系、脚本命令等关键信息。深入理解 package.json 中的各个字段,对于 Node.js 开发者来说至关重要——它不仅影响项目的构建和发布流程,还直接关系到包的兼容性、性能优化和开发体验。
本文将详细介绍 package.json 中最重要的 12 个字段,帮助你更好地管理和优化你的 Node.js 项目。
1. peerDependencies - 对等依赖管理
peerDependencies 字段用于声明你的包所依赖的宿主环境中应该存在的包及其版本。它告诉使用你的包的开发者:"我的包需要与这些特定版本的包协同工作"。
使用场景
这个字段主要用于以下场景:
- 插件开发:如 webpack 插件、babel 插件
- UI 组件库:如基于 React、Vue 的组件库
- 框架扩展:如 Express 中间件
实际案例
假设你正在开发一个 React 组件库,如果使用 dependencies:
{
"dependencies": {
"react": "^18.2.0"
}
}
问题:使用你组件库的项目可能已经安装了不同版本的 React(如 16.0.0),这会导致:
node_modules中存在多个 React 版本- 版本冲突和兼容性问题
- 包体积增大
更好的解决方案是使用 peerDependencies:
{
"peerDependencies": {
"react": "^18.2.0"
},
"peerDependenciesMeta": {
"react": {
"optional": false // 默认值,表示必须安装
}
}
}
优势
使用 peerDependencies 的好处:
- 避免重复安装:确保整个项目只有一个 React 版本
- 版本一致性:强制使用兼容的版本
- 减小包体积:不会将依赖打包到你的库中
- 灵活性:通过
peerDependenciesMeta可以标记某些依赖为可选
2. sideEffects - Tree Shaking 优化
sideEffects 字段是现代打包工具进行 Tree Shaking 优化的重要标识。它告诉打包工具哪些模块是"纯净"的,可以安全地移除未使用的代码。
什么是副作用?
副作用(Side Effects)是指模块在被导入时会执行一些影响全局状态的代码,例如:
- 修改全局变量
- 添加 polyfills
- 导入 CSS 文件
- 执行初始化代码
配置示例
标记为无副作用(推荐用于纯函数库):
{
"name": "my-package",
"version": "1.0.0",
"sideEffects": false
}
也可以指定具有副作用的特定文件:
{
"sideEffects": ["./src/polyfills.js", "*.css", "*.scss"]
}
这对于现代打包工具(如 webpack、vite)进行代码优化非常重要。
3. module
定义 npm 包的 ESM 规范(ES Module,import/export 语法)的入口文件,browser 环境和 node 环境均可使用。这个字段主要用于支持 ES6 模块语法的打包工具(如 webpack、rollup)。
{
"name": "my-package",
// main字段兼容旧工具链
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js"
}
当打包工具支持时,会优先使用 module 字段指定的 ESM 版本,这有助于更好的 tree-shaking 优化。
注意:Node.js 并不会识别 module 字段,它是社区约定的,主要用于 webpack、rollup、vite 等现代打包工具优先选择 ESM(ES Module)版本进行打包和优化。
4. types - TypeScript 类型声明
types 字段指定 TypeScript 类型声明文件的位置,让使用你的包的 TypeScript 项目能获得完整的类型提示和静态检查。
{
"name": "my-package",
"version": "1.0.0",
"types": "./types/index.d.ts"
"main": "dist/index.js",
"scripts": {
"build": "tsc"
}
}
说明
- 类型声明文件通常具有
.d.ts扩展名 - 用于描述 JavaScript 代码的类型信息
- TypeScript 编译器会自动使用这些类型进行静态检查
- 如果不指定,TypeScript 会查找与
main同名的.d.ts文件
5. main - 包的主入口
指定包的主入口文件。当其他模块通过 require() 或 import 导入你的包时,会加载该文件。
main 是最基本的入口字段,主要用于 CommonJS 规范,是旧版 Node.js 及部分工具链查找包入口的默认字段。
{
"name": "my-package",
"version": "1.0.0",
"main": "dist/index.js"
}
如果不指定 main 字段,Node.js 会默认查找根目录下的 index.js 文件。
与 module 的关系(简明):
- 【main 是什么】CommonJS 入口。旧版 Node/工具链用它来
require('pkg');当没有exports时,它是 Node 的主要入口。 - 【module 是什么】ESM 构建提示,供打包器(webpack/rollup/vite 等)优先采用以便 tree‑shaking。Node 运行时不读取
module字段。 - 【有无优先级】
- 打包器 import:优先
exports.import,否则尝试module,再不行用main。 - Node require:优先
exports.require,否则用main(或index.*规则)。 - Node import:优先
exports.import;没有exports时不会看module,会依据type/扩展名解析main或默认入口。
- 打包器 import:优先
- 【是否同时写】建议三者并存:
main兼容旧链路,module提示打包器走 ESM,exports做条件导出(含子路径)。 - 【实践建议】同时产出 CJS/ESM 构建;在
exports中指明 import/require;types指向.d.ts。若设置"type": "module",main应指向 ESM 产物。 - 【常见坑】只有
module没有main会让旧工具找不到入口;只有main没有exports/module难以获得良好 tree‑shaking 和条件导出;module指到源码会导致消费者二次编译。
6. exports - 现代化导出管理
exports 字段提供了更现代和精确的方式来定义包的导出,支持条件导出、子路径导出等高级功能。它是 Node.js 12+ 和现代打包工具的首选方案。
{
"name": "my-package",
"exports": {
".": {
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js"
},
// import utils from "your-lib/utils";Node.js 会解析到 ./dist/utils.js。
"./utils": "./dist/utils.js"
}
}
这样可以为 ESM 和 CommonJS 提供不同的入口文件,同时支持子路径导入。
7. files - 发布文件控制
指定发布到 npm 时包含的文件和目录列表。通过精确控制发布内容,可以显著减小包体积并提高下载速度。
{
"name": "my-package",
"files": ["dist", "lib", "README.md", "package.json"]
}
使用说明
- 如果不指定,npm 会包含所有文件(除了
.npmignore或.gitignore中排除的) - 建议只包含必要的文件:构建产物、类型文件、README 等
- 可以使用
npm pack --dry-run预览将被发布的文件
8. engines - 环境版本要求
指定包运行所需的 Node.js 版本或其他运行时环境的版本要求。这有助于避免在不兼容的环境中出现问题。
{
"name": "my-package",
"engines": {
"node": ">=14.0.0",
"npm": ">=6.0.0"
}
}
注意事项
- 这只是提示性信息,不会强制阻止安装
- 如需强制检查,可在
.npmrc中设置engine-strict=true - 建议设置合理的版本范围,避免过于严格
9. scripts - 项目自动化脚本
定义可以通过 npm run、yarn run 或 pnpm run 执行的脚本命令。这是项目自动化的核心。
{
"scripts": {
"start": "node server.js",
"build": "webpack --mode production",
"test": "jest",
"dev": "webpack-dev-server --mode development",
"lint": "eslint src/"
}
}
常用脚本类型
- 开发脚本:
dev、start、serve - 构建脚本:
build、compile、bundle - 测试脚本:
test、test:watch、test:coverage - 代码质量:
lint、format、type-check - 发布脚本:
prepublishOnly、publish
10. keywords - SEO 优化关键词
用于描述包功能的关键词数组,直接影响在 npm 官网和开发工具中的搜索排名。选择合适的关键词可以显著提高包的可发现性。
{
"name": "my-ui-library",
"keywords": ["react", "ui", "components", "typescript", "design-system"]
}
11. repository - 代码仓库链接
指定代码仓库的位置和类型。这不仅方便用户查看源代码和提交 issue,还可以让 npm 官网自动显示仓库链接。
{
"repository": {
"type": "git",
"url": "https://github.com/username/my-package.git"
}
}
12. license - 开源许可证
指定包的开源许可证类型。这对于明确使用权限和法律责任非常重要,也是开源项目的基本要求。
{
"license": "MIT"
}
常见许可证类型
- MIT:最宽松的许可证,允许几乎任何用途
- Apache-2.0:类似 MIT,但提供专利保护
- GPL-3.0:Copyleft 许可证,衍生作品必须开源
- ISC:与 MIT 类似但更简洁
- BSD-3-Clause:允许修改和重新分发
总结
掌握这 12 个 package.json 字段,能够帮你:
- 提升包的兼容性:通过
peerDependencies、engines、exports确保在不同环境下正常运行 - 优化性能:利用
sideEffects、module实现更好的 tree-shaking - 改善开发体验:完善的
types、scripts配置让开发更高效 - 增强可发现性:合理的
keywords、repository、license让包更容易被找到和信任
最佳实践建议
{
"name": "awesome-package",
"version": "1.0.0",
"description": "一个很棒的工具包",
"keywords": ["utility", "typescript", "modern"],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/username/awesome-package.git"
},
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.esm.js",
"require": "./dist/index.cjs.js",
"types": "./dist/index.d.ts"
}
},
"files": ["dist", "README.md"],
"engines": {
"node": ">=16.0.0"
},
"scripts": {
"build": "rollup -c",
"test": "vitest",
"type-check": "tsc --noEmit",
"lint": "eslint src/",
"prepublishOnly": "npm run build && npm run test"
},
"sideEffects": false,
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"react": {
"optional": false
}
}
}
通过合理配置这些字段,你的 npm 包将具备现代化的特性,为用户提供更好的使用体验。