跳到主要内容

package.json 完整指南

package.json 是 Node.js 项目的核心配置文件,它定义了项目的基本信息、依赖关系、脚本命令和各种配置选项。理解 package.json 的每个字段对于管理 Node.js 项目至关重要。

文件结构概览​

一个完整的 package.json 文件包含多个字段,可以分为以下几类:

  • 必需字段:name、version
  • 元信息字段:description、keywords、author、license 等
  • 入口点字段:main、module、exports、bin 等
  • 依赖字段:dependencies、devDependencies、peerDependencies 等
  • 脚本字段:scripts
  • 配置字段:config、engines、os、cpu 等
  • 发布字段:private、publishConfig、files 等

必需字段​

name​

包的名称,是包的唯一标识符。

{
"name": "my-package",
"name": "@myorg/my-package"
}

命名规则:

  • 必须是小写字母
  • 可以包含字母、数字、连字符(-)和下划线(_)
  • 长度不超过 214 字符
  • 不能以点(.)或下划线(_)开头
  • 不能包含大写字母
  • 不能使用 Node.js 核心模块名称

Scoped package(作用域包)使用 @scope/name 格式,用于组织内部包或避免命名冲突。

version​

包的版本号,遵循语义化版本规范。

{
"version": "1.0.0",
"version": "2.1.0-beta.1"
}

版本号格式:主版本号.次版本号.修订号[-预发布标识]

元信息字段​

description​

包的简短描述,用于 npm 搜索结果中显示。

{
"description": "A fast and flexible web framework for Node.js"
}

keywords​

关键词数组,用于 npm 搜索优化。

{
"keywords": ["node", "framework", "web", "http", "rest"]
}

homepage​

项目主页 URL。

{
"homepage": "https://expressjs.com"
}

bugs​

问题追踪地址。

{
"bugs": {
"url": "https://github.com/expressjs/express/issues",
"email": "support@expressjs.com"
}
}

license​

许可证类型。

{
"license": "MIT",
"license": "Apache-2.0",
"license": "ISC",
"license": "BSD-3-Clause",
"license": "UNLICENSED"
}

常用开源许可证:

  • MIT:最宽松,允许任意使用
  • Apache-2.0:提供专利保护
  • ISC:类似 MIT,措辞更简洁
  • BSD-3-Clause:不允许使用项目名称推广

author 和 contributors​

作者和贡献者信息。

{
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca",
"url": "https://tjholowaychuk.com"
},
"author": "TJ Holowaychuk <tj@vision-media.ca> (https://tjholowaychuk.com)",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
}
]
}

repository​

代码仓库信息。

{
"repository": {
"type": "git",
"url": "https://github.com/expressjs/express.git"
},
"repository": "github:expressjs/express",
"repository": "gitlab:user/repo",
"repository": "bitbucket:user/repo"
}

入口点字段​

main​

CommonJS 模块的入口文件,Node.js 默认使用此字段。

{
"main": "index.js",
"main": "dist/index.js"
}

当用户执行 require('my-package') 时,Node.js 会加载 main 指定的文件。

module​

ES Module 的入口文件,打包工具(如 webpack、rollup)优先使用此字段。

{
"module": "index.mjs",
"module": "dist/index.esm.js"
}

types​

TypeScript 类型定义文件入口。

{
"types": "index.d.ts",
"types": "dist/index.d.ts"
}

exports​

现代的入口点定义方式,支持条件导出,可以更精细地控制不同环境下的导出内容。

{
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"default": "./dist/index.js"
},
"./feature": {
"import": "./dist/feature.mjs",
"require": "./dist/feature.js"
},
"./package.json": "./package.json"
}
}

条件导出的优先级(从高到低):

  1. import - ES Module 环境
  2. require - CommonJS 环境
  3. default - 默认回退

更多条件:

  • types - TypeScript 类型导入
  • node - Node.js 环境
  • deno - Deno 环境
  • browser - 浏览器环境
  • development - 开发环境
  • production - 生产环境

bin​

定义可执行命令,安装包时会创建符号链接到全局或本地的 bin 目录。

{
"bin": {
"my-cli": "./bin/cli.js",
"my-tool": "./bin/tool.js"
},
"bin": "./bin/cli.js"
}

可执行文件需要在开头添加 shebang:

#!/usr/bin/env node

console.log('Hello from my-cli');

browser​

浏览器环境的入口点或替代模块。

{
"browser": {
"./lib/fs.js": "./lib/fs-browser.js",
"./lib/net.js": false
},
"browser": "./dist/browser.js"
}

依赖字段​

dependencies​

生产环境依赖,运行时必需。

{
"dependencies": {
"express": "^4.18.2",
"lodash": "^4.17.21",
"axios": ">=1.0.0 <2.0.0"
}
}

devDependencies​

开发环境依赖,仅开发和测试时需要。

{
"devDependencies": {
"jest": "^29.5.0",
"typescript": "^5.0.0",
"eslint": "^8.0.0",
"@types/node": "^20.0.0"
}
}

peerDependencies​

同伴依赖,要求宿主项目提供。常用于插件开发。

{
"peerDependencies": {
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"@types/react": {
"optional": true
}
}
}

peerDependenciesMeta 用于标记可选的同伴依赖。

optionalDependencies​

可选依赖,安装失败不会阻止项目运行。

{
"optionalDependencies": {
"fsevents": "^2.3.0"
}
}

典型场景:平台特定的原生模块。

bundledDependencies​

打包依赖,发布时会将这些依赖打包在一起。

{
"bundledDependencies": [
"my-private-package",
"another-package"
],
"bundleDependencies": ["my-private-package"]
}

overrides​

强制覆盖依赖版本(npm 8.3+)。

{
"overrides": {
"lodash": "4.17.21",
"express": {
"debug": "4.3.4"
}
}
}

resolutions​

强制覆盖依赖版本(yarn)。

{
"resolutions": {
"lodash": "4.17.21",
"**/debug": "4.3.4"
}
}

脚本字段​

scripts​

定义可通过 npm run 执行的脚本命令。

{
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"build": "webpack --mode production",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"lint": "eslint src/",
"lint:fix": "eslint src/ --fix",
"format": "prettier --write .",
"clean": "rm -rf dist node_modules",
"prepublishOnly": "npm test && npm run build",
"postinstall": "node scripts/postinstall.js"
}
}

生命周期脚本​

脚本名称触发时机
prepare发布前、安装后、Git 操作后
prepublishOnly发布前(仅 npm publish)
prepack打包前
postpack打包后
preinstall安装前
postinstall安装后
preuninstall卸载前
postuninstall卸载后
preversion版本变更前
version版本变更后(修改文件)
postversion版本变更后(推送 Git)
pretest测试前
test测试时
posttest测试后
prestart启动前
start启动时
poststart启动后
prerestart重启前
restart重启时
postrestart重启后
prestop停止前
stop停止时
poststop停止后

config​

脚本中可使用的配置变量。

{
"config": {
"port": "3000",
"env": "development"
},
"scripts": {
"start": "node server.js --port $npm_package_config_port"
}
}

配置字段​

engines​

指定运行环境版本要求。

{
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0",
"yarn": ">=1.22.0"
}
}

默认情况下,版本不匹配只会警告。设置 engineStrict: true 会阻止安装。

engineStrict​

强制检查 engines 版本要求。

{
"engineStrict": true
}

os​

指定支持的操作系统。

{
"os": ["darwin", "linux"],
"os": ["!win32"]
}

可用值:darwin、linux、win32、freebsd、sunos 等。

cpu​

指定支持的 CPU 架构。

{
"cpu": ["x64", "arm64"],
"cpu": ["!x32"]
}

可用值:x64、arm64、arm、ia32、mips 等。

private​

标记为私有包,防止意外发布。

{
"private": true
}

workspaces​

定义单体仓库的工作区。

{
"workspaces": [
"packages/*",
"apps/*",
"!**/test/**"
]
}

type​

定义包的模块类型。

{
"type": "module",
"type": "commonjs"
}
  • module:.js 文件作为 ES Module 处理
  • commonjs:.js 文件作为 CommonJS 处理(默认)

imports​

定义内部模块别名(Node.js 12+)。

{
"imports": {
"#utils": "./src/utils/index.js",
"#utils/*": "./src/utils/*.js",
"#config": {
"import": "./src/config.mjs",
"require": "./src/config.cjs"
}
}
}

使用方式:

import { helper } from '#utils/helper.js';

发布字段​

files​

指定发布时要包含的文件(白名单)。

{
"files": [
"dist",
"lib",
"bin",
"README.md",
"LICENSE"
]
}

默认包含的文件:

  • package.json
  • README.md
  • LICENSE
  • main 字段指定的文件

默认排除的文件:

  • .git
  • node_modules
  • .npmignore 中列出的文件
  • 测试文件
  • 配置文件

publishConfig​

发布时的配置覆盖。

{
"publishConfig": {
"registry": "https://npm.mycompany.com",
"access": "public",
"tag": "beta"
}
}

directories​

定义目录结构(旧规范,部分已弃用)。

{
"directories": {
"lib": "lib",
"bin": "bin",
"man": "man",
"doc": "doc",
"example": "example",
"test": "test"
}
}

man​

定义 man 手册文件。

{
"man": ["./man/my-package.1", "./man/my-package.2"]
}

TypeScript 相关字段​

typesVersions​

为不同 TypeScript 版本提供不同的类型定义。

{
"types": "dist/index.d.ts",
"typesVersions": {
">=4.0": {
"*": ["dist/ts4.0/*"]
},
"*": {
"*": ["dist/*"]
}
}
}

打包工具相关字段​

sideEffects​

标记包是否有副作用,用于 tree-shaking 优化。

{
"sideEffects": false,
"sideEffects": ["*.css", "*.vue"]
}
  • false:所有文件都是无副作用的,可以安全地 tree-shake
  • 数组:指定有副作用的文件

module 字段​

ES Module 入口,打包工具优先使用。

{
"module": "dist/index.esm.js"
}

esnext 字段​

ES Next 入口,包含最新的 ES 特性。

{
"esnext": "dist/index.esnext.js",
"es2015": "dist/index.es2015.js",
"es2017": "dist/index.es2017.js"
}

unpkg 和 jsdelivr​

CDN 入口文件。

{
"unpkg": "dist/umd/index.js",
"jsdelivr": "dist/umd/index.js"
}

browserlist​

浏览器兼容性配置。

{
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}

eslintConfig 和 prettier​

内联配置(推荐使用独立配置文件)。

{
"eslintConfig": {
"extends": ["eslint:recommended", "prettier"],
"env": {
"node": true,
"es2022": true
}
},
"prettier": {
"semi": true,
"singleQuote": true,
"tabWidth": 2
}
}

jest 和 babel​

测试和编译配置。

{
"jest": {
"testEnvironment": "node",
"coverageDirectory": "coverage",
"testMatch": ["**/__tests__/**/*.js"]
},
"babel": {
"presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-transform-runtime"]
}
}

完整示例​

{
"name": "@myorg/my-package",
"version": "1.0.0",
"description": "A comprehensive Node.js package example",
"keywords": ["node", "package", "example"],
"homepage": "https://github.com/myorg/my-package#readme",
"bugs": {
"url": "https://github.com/myorg/my-package/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/myorg/my-package.git"
},
"license": "MIT",
"author": {
"name": "Your Name",
"email": "your@email.com",
"url": "https://yourwebsite.com"
},
"contributors": [
{
"name": "Contributor Name",
"email": "contributor@email.com"
}
],
"type": "module",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./feature": {
"import": "./dist/feature.mjs",
"require": "./dist/feature.js"
},
"./package.json": "./package.json"
},
"bin": {
"my-cli": "./bin/cli.js"
},
"files": [
"dist",
"bin",
"README.md",
"LICENSE"
],
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsup src/index.ts --format cjs,esm --dts",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"lint": "eslint src/",
"lint:fix": "eslint src/ --fix",
"format": "prettier --write .",
"clean": "rm -rf dist node_modules",
"prepublishOnly": "npm test && npm run build",
"release": "npm version patch && npm publish"
},
"dependencies": {
"express": "^4.18.2",
"lodash": "^4.17.21"
},
"devDependencies": {
"@types/express": "^4.17.17",
"@types/lodash": "^4.14.195",
"@types/node": "^20.0.0",
"eslint": "^8.0.0",
"prettier": "^3.0.0",
"tsup": "^7.0.0",
"tsx": "^4.0.0",
"typescript": "^5.0.0",
"vitest": "^1.0.0"
},
"peerDependencies": {
"typescript": ">=4.7.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
},
"optionalDependencies": {
"fsevents": "^2.3.0"
},
"engines": {
"node": ">=18.0.0"
},
"os": ["darwin", "linux", "win32"],
"cpu": ["x64", "arm64"],
"sideEffects": false,
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"browserslist": [
"node >= 18"
]
}

最佳实践​

1. 使用精确的版本范围​

对于关键依赖,考虑使用更严格的版本范围:

{
"dependencies": {
"critical-package": "1.2.3",
"stable-package": "~1.2.3",
"normal-package": "^1.2.3"
}
}

2. 合理区分依赖类型​

  • dependencies:运行时必需
  • devDependencies:开发工具、测试框架、类型定义
  • peerDependencies:插件对宿主的要求
  • optionalDependencies:平台特定依赖

3. 使用 exports 字段​

现代包推荐使用 exports 字段,提供更好的封装:

{
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
}
}

4. 设置 sideEffects​

对于库包,设置 sideEffects: false 以支持 tree-shaking:

{
"sideEffects": false
}

5. 使用 workspaces 管理多包​

{
"private": true,
"workspaces": ["packages/*"]
}

6. 提供完整的元信息​

{
"name": "@myorg/my-package",
"description": "Clear description of what the package does",
"keywords": ["relevant", "keywords"],
"repository": "github:myorg/my-package",
"bugs": "https://github.com/myorg/my-package/issues",
"homepage": "https://github.com/myorg/my-package#readme",
"license": "MIT"
}

7. 使用 engines 约束环境​

{
"engines": {
"node": ">=18.0.0"
}
}

8. 合理使用脚本​

{
"scripts": {
"preversion": "npm test",
"version": "npm run build && git add dist",
"postversion": "git push && git push --tags"
}
}