跳到主要内容

package.json 完整指南

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

文件结构概览

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

  • 必需字段nameversion
  • 元信息字段descriptionkeywordsauthorlicense
  • 入口点字段mainmoduleexportsbin
  • 依赖字段dependenciesdevDependenciespeerDependencies
  • 脚本字段scripts
  • 配置字段configenginesoscpu
  • 发布字段privatepublishConfigfiles

必需字段

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"
}
}

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

  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"]
}

可用值:darwinlinuxwin32freebsdsunos 等。

cpu

指定支持的 CPU 架构。

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

可用值:x64arm64armia32mips 等。

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": "[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"
}
}