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": "[email protected]"
}
}
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": "[email protected]",
"url": "https://tjholowaychuk.com"
},
"author": "TJ Holowaychuk <[email protected]> (https://tjholowaychuk.com)",
"contributors": [
{
"name": "Douglas Christopher Wilson",
"email": "[email protected]"
}
]
}
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"
}
}
条件导出的优先级(从高到低):
import- ES Module 环境require- CommonJS 环境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.jsonREADME.mdLICENSEmain字段指定的文件
默认排除的文件:
.gitnode_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": "[email protected]",
"url": "https://yourwebsite.com"
},
"contributors": [
{
"name": "Contributor Name",
"email": "[email protected]"
}
],
"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"
}
}