跳到主要内容

package.json 文件中常用字段

· 阅读需 8 分钟
XingHunm
Tech Enthusiast

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 的好处:

  1. 避免重复安装:确保整个项目只有一个 React 版本
  2. 版本一致性:强制使用兼容的版本
  3. 减小包体积:不会将依赖打包到你的库中
  4. 灵活性:通过 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 或默认入口。
  • 【是否同时写】建议三者并存: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 runyarn runpnpm run 执行的脚本命令。这是项目自动化的核心。

{
"scripts": {
"start": "node server.js",
"build": "webpack --mode production",
"test": "jest",
"dev": "webpack-dev-server --mode development",
"lint": "eslint src/"
}
}

常用脚本类型

  • 开发脚本devstartserve
  • 构建脚本buildcompilebundle
  • 测试脚本testtest:watchtest:coverage
  • 代码质量lintformattype-check
  • 发布脚本prepublishOnlypublish

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 字段,能够帮你:

  1. 提升包的兼容性:通过 peerDependenciesenginesexports 确保在不同环境下正常运行
  2. 优化性能:利用 sideEffectsmodule 实现更好的 tree-shaking
  3. 改善开发体验:完善的 typesscripts 配置让开发更高效
  4. 增强可发现性:合理的 keywordsrepositorylicense 让包更容易被找到和信任

最佳实践建议

{
"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 包将具备现代化的特性,为用户提供更好的使用体验。