前端工程化基石:package.json 40+ 字段逐一拆解

每个前端项目的根目录下几乎都有一个 package.json,但你真的了解它的每个字段吗?本文将从基础字段高级配置 ,逐一拆解 package.json 中的所有字段,帮你彻底搞懂它。


一、必填字段

1.1 name --- 包名

json 复制代码
{
  "name": "@packageName/sdk"
}

规则:

  • 长度不超过 214 个字符
  • 不能以 ._ 开头
  • 不能包含大写字母
  • 不能包含 URL 不安全字符(如空格、~ 等)
  • 支持 scope (作用域),格式为 @scope/name,常用于组织级别的包管理,例如 @vue/cli@babel/core

作用:
name 是包的唯一标识符。当你执行 npm install xxx 时,xxx 就是这个字段的值。配合 version,它们共同构成了包的"身份证"。


1.2 version --- 版本号

json 复制代码
{
  "version": "1.6.7"
}

必须遵循 Semantic Versioning(语义化版本) 规范,格式为 MAJOR.MINOR.PATCH

含义 示例场景
MAJOR 不兼容的 API 变更 重构了核心 API
MINOR 向下兼容的功能新增 新增了一个工具函数
PATCH 向下兼容的问题修复 修复了一个边界 Bug

还支持预发布标签:1.0.0-alpha.11.0.0-beta.21.0.0-rc.1


二、描述信息字段

2.1 description --- 包描述

json 复制代码
{
  "description": "packageDescription"
}

简短描述包的功能,会展示在 npm search 的搜索结果中,也是 npm 官网搜索排序的权重因子之一。

2.2 keywords --- 关键词

json 复制代码
{
  "keywords": ["cloud", "sdk", "vue", "plugin", "micro-frontend"]
}

字符串数组,用于 npm 官网的搜索优化(SEO),帮助其他开发者更快找到你的包。

2.3 homepage --- 项目主页

json 复制代码
{
  "homepage": "https://github.com/user/project#readme"
}

项目官网或文档地址,会展示在 npm 包详情页的侧边栏。

2.4 bugs --- Bug 反馈地址

json 复制代码
{
  "bugs": {
    "url": "https://github.com/user/project/issues",
    "email": "bugs@example.com"
  }
}

也可以简写为字符串:"bugs": "https://github.com/user/project/issues"

2.5 license --- 开源协议

json 复制代码
{
  "license": "MIT"
}

常见协议:

协议 特点
MIT 极其宽松,几乎无限制
Apache-2.0 允许商用,需保留版权,提供专利许可
GPL-3.0 传染性协议,衍生作品也需开源
ISC 类似 MIT,更简洁
UNLICENSED 私有包,不允许他人使用

2.6 author --- 作者

json 复制代码
{
  "author": {
    "name": "张三",
    "email": "zhangsan@example.com",
    "url": "https://zhangsan.dev"
  }
}

也支持简写形式:"author": "张三 <zhangsan@example.com> (https://zhangsan.dev)"

2.7 contributors --- 贡献者

json 复制代码
{
  "contributors": [
    { "name": "李四", "email": "lisi@example.com" },
    "王五 <wangwu@example.com>"
  ]
}

格式同 author,是一个数组。

2.8 funding --- 赞助信息

json 复制代码
{
  "funding": {
    "type": "opencollective",
    "url": "https://opencollective.com/project"
  }
}

也支持数组形式,用于声明多个赞助渠道。执行 npm fund 可查看项目的赞助信息。


三、入口文件字段

这是 package.json 中最核心也最容易混淆的一组字段,直接决定了别人引用你的包时,加载的是哪个文件。

3.1 main --- CommonJS 入口

json 复制代码
{
  "main": "dist/cloud-sdk.umd.js"
}

作用:

Node.js 和旧版打包工具默认读取的入口。当执行 require('your-package') 时,实际加载的就是 main 指向的文件。

3.2 module --- ESModule 入口

json 复制代码
{
  "module": "dist/cloud-sdk.esm.js"
}

作用:

这不是 Node.js 官方字段,而是由打包工具(Webpack、Rollup、Vite)约定的。当打包工具发现 module 字段时,会优先使用它,因为 ESM 格式支持 Tree Shaking,能有效减小打包体积。

3.3 browser --- 浏览器入口

json 复制代码
{
  "browser": "dist/cloud-sdk.browser.js"
}

当包需要在浏览器中运行,且浏览器版本与 Node 版本实现不同时使用。打包工具在构建浏览器端代码时会优先读取此字段。

也支持对象形式,用于替换特定模块:

json 复制代码
{
  "browser": {
    "./lib/server-utils.js": "./lib/browser-utils.js",
    "fs": false
  }
}

3.4 types / typings --- TypeScript 类型入口

json 复制代码
{
  "types": "dist/index.d.ts"
}

指定 TypeScript 类型声明文件的入口路径。typestypings 等价,推荐用 types

3.5 exports --- 条件导出(重点!)

json 复制代码
{
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/cloud-sdk.esm.js",
      "require": "./dist/cloud-sdk.umd.js"
    },
    "./utils": {
      "types": "./dist/utils.d.ts",
      "import": "./dist/utils.esm.js",
      "require": "./dist/utils.cjs.js"
    }
  }
}

这是 Node.js 12.11+ 引入的现代模块解析方案 ,是 mainmodulebrowser 的"终极替代方案"。

核心能力:

特性 说明
条件导出 根据环境(import / require / node / browser / default)返回不同文件
子路径导出 允许 import { foo } from 'pkg/utils' 形式的子路径引用
封装隔离 未在 exports 中声明的路径,外部无法访问,保护内部实现

条件匹配的优先级(从上到下):

json 复制代码
{
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "node": {
        "import": "./dist/node.mjs",
        "require": "./dist/node.cjs"
      },
      "browser": "./dist/browser.js",
      "default": "./dist/index.js"
    }
  }
}

注意: types 条件必须放在最前面,否则 TypeScript 可能无法正确解析类型。

3.6 type --- 模块系统声明

json 复制代码
{
  "type": "module"
}
含义
"module" .js 文件默认作为 ESModule 处理
"commonjs"(默认值) .js 文件默认作为 CommonJS 处理

设置为 "module" 后:

  • .js → ESM
  • .cjs → CommonJS(强制)
  • .mjs → ESM(强制)

四、文件管控字段

4.1 files --- 发布包含的文件

json 复制代码
{
  "files": ["dist", "README.md", "LICENSE"]
}

白名单机制 ,指定 npm publish 时需要包含的文件和目录。类似 .gitignore 的反向操作。

始终包含的文件(无法排除):

  • package.json
  • README(任何大小写和扩展名)
  • LICENSE / LICENCE
  • CHANGELOG
  • main 字段指向的文件

始终排除的文件(无法包含):

  • .git
  • node_modules
  • .npmrc
  • package-lock.json

技巧: 也可以用 .npmignore 做黑名单控制,但 files 字段优先级更高,两者同时存在时以 files 为准。

4.2 directories --- 项目目录结构

json 复制代码
{
  "directories": {
    "lib": "src/lib",
    "bin": "bin",
    "man": "man",
    "doc": "docs",
    "example": "examples",
    "test": "test"
  }
}

声明项目的目录结构。实际使用较少,主要是一种语义化描述。


五、脚本与命令字段

5.1 scripts --- NPM 脚本

json 复制代码
{
  "scripts": {
    "dev": "vite build --watch",
    "build": "vite build",
    "lint": "eslint src",
    "lint:fix": "eslint src --fix",
    "format": "prettier --write src",
    "prepare": "husky install",
    "preinstall": "npx only-allow pnpm"
  }
}

通过 npm run <script-name> 执行。部分脚本名有特殊含义:

生命周期脚本:

脚本名 触发时机
preinstall 安装依赖之前执行
install 安装依赖时执行
postinstall 安装依赖之后执行
prepare npm install 之后、npm publish 之前执行
prepublishOnly 仅在 npm publish 之前执行
prepack 打 tarball 之前(npm pack / npm publish
postpack 打 tarball 之后

pre/post 钩子:

任何自定义脚本都可以加 pre / post 前缀:

json 复制代码
{
  "scripts": {
    "prebuild": "rimraf dist",
    "build": "vite build",
    "postbuild": "echo 构建完成"
  }
}

执行 npm run build 会依次执行:prebuildbuildpostbuild

注意: pnpm 和 yarn 现代版本默认不会自动执行 pre/post 钩子,需手动配置开启。

5.2 bin --- 可执行文件

json 复制代码
{
  "bin": {
    "create-uver": "./bin/create.js"
  }
}

当用户全局安装(npm install -g)或通过 npx 执行时,系统会创建软链接到 bin 指定的文件。

如果只有一个可执行文件,可以简写为:

json 复制代码
{
  "name": "create-uver",
  "bin": "./bin/create.js"
}

此时命令名就是 name 字段的值。

5.3 man --- 帮助手册

json 复制代码
{
  "man": ["./man/doc.1", "./man/doc.2"]
}

指定 man 命令的文档文件路径,文件必须以数字结尾或以 .gz 压缩。


六、依赖管理字段

6.1 dependencies --- 生产依赖

json 复制代码
{
  "dependencies": {
    "lodash-es": "^4.17.21",
    "vue": "^3.4.0",
    "vue-router": "^4.5.0"
  }
}

项目运行时必须的依赖,npm install 默认安装,最终会被打包进产物中。

6.2 devDependencies --- 开发依赖

json 复制代码
{
  "devDependencies": {
    "typescript": "^5.3.3",
    "vite": "^6.3.5",
    "eslint": "^9.3.4",
    "prettier": "^3.2.5"
  }
}

仅开发阶段需要的依赖(构建工具、Linter、测试框架等)。其他项目安装你的包时不会 安装 devDependencies

6.3 peerDependencies --- 宿主依赖

json 复制代码
{
  "peerDependencies": {
    "vue": "^3.0.0",
    "react": "^18.0.0"
  }
}

声明"我需要宿主环境提供这个依赖" ,而不是自己安装一份。最经典的场景是 UI 组件库 ------ element-plus 声明 peerDependencies: { "vue": "^3.0.0" },因为它不应该自带一份 Vue。

npm 版本 行为
npm 3-6 仅发出警告
npm 7+ 自动安装 peerDependencies

6.4 peerDependenciesMeta --- 宿主依赖元信息

json 复制代码
{
  "peerDependencies": {
    "vue": "^3.0.0",
    "react": "^18.0.0"
  },
  "peerDependenciesMeta": {
    "react": {
      "optional": true
    }
  }
}

标记某个 peerDependency 为可选,未安装时不会报警告。

6.5 optionalDependencies --- 可选依赖

json 复制代码
{
  "optionalDependencies": {
    "fsevents": "^2.3.0"
  }
}

安装失败时不会导致整个 npm install 失败。典型场景:fsevents 仅在 macOS 下可用。

6.6 bundleDependencies / bundledDependencies --- 捆绑依赖

json 复制代码
{
  "bundleDependencies": ["lodash", "chalk"]
}

npm pack 时会将这些依赖打包进 tarball。适用于需要确保特定版本依赖的场景,或内网环境发布。

6.7 overrides(npm)/ resolutions(yarn)--- 依赖覆盖

npm(overrides):

json 复制代码
{
  "overrides": {
    "source-map": "^0.7.4"
  }
}

yarn(resolutions):

json 复制代码
{
  "resolutions": {
    "source-map": "^0.7.4"
  }
}

pnpm(pnpm.overrides):

json 复制代码
{
  "pnpm": {
    "overrides": {
      "source-map": "^0.7.4"
    }
  }
}

强制将依赖树中所有匹配的包替换为指定版本。常用于修复深层依赖的安全漏洞或兼容性问题。

版本号范围速查

| 符号 | 含义 | 示例 | 匹配范围 |
|------|------|-----------|------------------|--------------------|--------|
| ^ | 兼容版本 | ^1.2.3 | >=1.2.3 <2.0.0 |
| ~ | 近似版本 | ~1.2.3 | >=1.2.3 <1.3.0 |
| >= | 大于等于 | >=1.2.3 | >=1.2.3 |
| * | 任意版本 | * | 所有版本 |
| 无符号 | 精确版本 | 1.2.3 | 仅 1.2.3 |
| ` | | ` | 或 | ^1.0.0 || ^2.0.0 | 满足任一条件 |


七、发布配置字段

7.1 private --- 私有包

json 复制代码
{
  "private": true
}

设置为 true 后,npm publish 会直接拒绝发布。用于防止 monorepo 根目录或内部项目被意外发布到公共 npm。

7.2 publishConfig --- 发布配置

json 复制代码
{
  "publishConfig": {
    "registry": "http://jfrog.gdu-tech.com/artifactory/api/npm/gdu-npm-package/",
    "access": "public",
    "tag": "latest"
  }
}
字段 说明
registry 发布到指定 npm 仓库(私有源)
access "public""restricted",scope 包默认 restricted
tag 发布时的 dist-tag,默认 latest

7.3 repository --- 仓库信息

json 复制代码
{
  "repository": {
    "type": "git",
    "url": "https://github.com/user/project.git",
    "directory": "packages/cloud-sdk"
  }
}

directory 字段在 monorepo 中非常有用,指明包在仓库中的具体位置。

npm 官网会根据此字段在包详情页展示源码链接。


八、环境约束字段

8.1 engines --- 运行环境要求

json 复制代码
{
  "engines": {
    "node": ">=18.0.0",
    "pnpm": ">=9.15.0",
    "npm": ">=8.0.0"
  }
}

声明项目所需的 Node.js 和包管理器版本。默认仅作为建议,如需强制校验:

  • npm:.npmrc 中设置 engine-strict=true
  • yarn: 自动强制检查
  • pnpm: 自动强制检查

8.2 os --- 操作系统限制

json 复制代码
{
  "os": ["darwin", "linux", "!win32"]
}

限制包可运行的操作系统。! 前缀表示排除。

8.3 cpu --- CPU 架构限制

json 复制代码
{
  "cpu": ["x64", "arm64", "!ia32"]
}

限制包可运行的 CPU 架构。

8.4 packageManager --- 指定包管理器

json 复制代码
{
  "packageManager": "pnpm@9.15.0"
}

Node.js 16.9+ 引入的 Corepack 特性。声明项目使用的包管理器及精确版本,搭配 corepack enable,其他包管理器会被拦截。


九、Monorepo 相关字段

9.1 workspaces --- 工作空间

npm/yarn:

json 复制代码
{
  "workspaces": [
    "packages/*",
    "business/*"
  ]
}

pnpm 使用独立的 pnpm-workspace.yaml

yaml 复制代码
packages:
  - 'packages/*'
  - 'business/*'

工作空间允许在一个仓库中管理多个包,共享 node_modules,实现包之间的互相引用。

9.2 pnpm --- pnpm 专有配置

json 复制代码
{
  "pnpm": {
    "overrides": {
      "source-map": "^0.7.4"
    },
    "peerDependencyRules": {
      "ignoreMissing": ["@babel/*"],
      "allowedVersions": {
        "vue": "3"
      }
    },
    "neverBuiltDependencies": ["fsevents"],
    "patchedDependencies": {
      "express@4.18.2": "patches/express@4.18.2.patch"
    }
  }
}

pnpm 的专属扩展配置项,功能非常丰富:

字段 说明
overrides 强制覆盖依赖版本
peerDependencyRules 控制 peerDep 检查行为
neverBuiltDependencies 跳过某些包的 postinstall 脚本
patchedDependencies 声明补丁文件,搭配 pnpm patch 使用

十、工具链配置字段

许多工具支持直接在 package.json 中配置,免去创建额外配置文件。

10.1 lint-staged

json 复制代码
{
  "lint-staged": {
    "*.{js,ts,vue}": ["eslint --fix", "prettier --write"],
    "*.{json,md,yaml,yml}": ["prettier --write"]
  }
}

配合 husky 在 git commit 前对暂存文件执行 lint 和格式化。

10.2 browserslist

json 复制代码
{
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead",
    "not ie 11"
  ]
}

声明目标浏览器范围,影响 Babel、PostCSS Autoprefixer、SWC 等工具的编译输出。

10.3 sideEffects

json 复制代码
{
  "sideEffects": false
}

告知打包工具(Webpack/Rollup/Vite)该包的所有模块都没有副作用,可以安全 Tree Shaking。

也可以指定有副作用的文件:

json 复制代码
{
  "sideEffects": ["*.css", "*.scss", "./src/polyfill.js"]
}

这是优化打包体积最关键的字段之一 。如果你的库设置了 "sideEffects": false,使用者只 import 了一个函数,打包工具就敢放心地把其余代码全部删掉。

10.4 config

json 复制代码
{
  "config": {
    "port": "8080"
  }
}

可以在 npm scripts 中通过 npm_package_config_port 环境变量读取,用户可以用 npm config set project:port 3000 覆盖。

10.5 其他工具内联配置

以下工具都支持在 package.json 中直接配置:

工具 字段名 说明
ESLint(旧版) eslintConfig ESLint 配置
Prettier prettier 代码格式化配置
Babel babel 编译器配置
Jest jest 测试框架配置
Stylelint stylelint CSS Lint 配置
commitlint commitlint Commit 消息规范
unplugin-auto-import auto-import 自动导入配置

十一、不常见但有用的字段

11.1 flat --- 扁平化依赖(yarn)

json 复制代码
{
  "flat": true
}

强制 yarn 安装依赖时使用扁平结构,如果有版本冲突会提示用户选择。

11.2 preferGlobal --- 建议全局安装(已废弃)

json 复制代码
{
  "preferGlobal": true
}

npm 5+ 已废弃此字段,但部分老项目可能还在使用。

11.3 deprecated --- 废弃提示

不是在 package.json 中设置的字段,而是通过 npm deprecate 命令发布:

bash 复制代码
npm deprecate my-package@"<2.0.0" "请升级到 2.x 版本"

安装时会显示黄色警告。


十二、字段优先级总结

入口文件解析优先级

不同工具对入口字段的解析优先级不同:

Node.js(>=12.11):

css 复制代码
exports > main

Webpack 5:

java 复制代码
exports > browser > module > main

Vite / Rollup:

java 复制代码
exports > module > main

TypeScript:

css 复制代码
exports["."]["types"] > types > typings > main(.d.ts)

一张图看清全貌

bash 复制代码
package.json
├── 📋 基本信息
│   ├── name            # 包名
│   ├── version         # 版本号
│   ├── description     # 描述
│   ├── keywords        # 关键词
│   ├── license         # 协议
│   ├── author          # 作者
│   └── contributors    # 贡献者
│
├── 📦 入口文件
│   ├── main            # CJS 入口
│   ├── module          # ESM 入口
│   ├── browser         # 浏览器入口
│   ├── types           # TS 类型入口
│   ├── exports         # 条件导出(现代方案)
│   └── type            # 模块系统声明
│
├── 📁 文件管控
│   ├── files           # 发布白名单
│   └── directories     # 目录结构声明
│
├── ⚙️ 脚本与命令
│   ├── scripts         # NPM 脚本
│   ├── bin             # 可执行文件
│   └── man             # 帮助手册
│
├── 📚 依赖管理
│   ├── dependencies          # 生产依赖
│   ├── devDependencies       # 开发依赖
│   ├── peerDependencies      # 宿主依赖
│   ├── peerDependenciesMeta  # 宿主依赖元信息
│   ├── optionalDependencies  # 可选依赖
│   ├── bundleDependencies    # 捆绑依赖
│   └── overrides/resolutions # 依赖覆盖
│
├── 🚀 发布配置
│   ├── private         # 私有标记
│   ├── publishConfig   # 发布配置
│   └── repository      # 仓库信息
│
├── 🔒 环境约束
│   ├── engines         # Node/npm 版本要求
│   ├── os              # 操作系统限制
│   ├── cpu             # CPU 架构限制
│   └── packageManager  # 包管理器声明
│
├── 🏗️ Monorepo
│   ├── workspaces      # 工作空间
│   └── pnpm            # pnpm 专有配置
│
└── 🔧 工具链配置
    ├── lint-staged     # 暂存文件 lint
    ├── browserslist    # 目标浏览器
    ├── sideEffects     # 副作用声明
    └── config          # 自定义配置

十三、最佳实践

1. 库开发的标准 package.json 模板

json 复制代码
{
  "name": "@scope/my-lib",
  "version": "1.0.0",
  "description": "A modern library",
  "type": "module",
  "main": "dist/index.cjs",
  "module": "dist/index.mjs",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  },
  "files": ["dist"],
  "sideEffects": false,
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
    "lint": "eslint src",
    "test": "vitest"
  },
  "peerDependencies": {
    "vue": "^3.0.0"
  },
  "peerDependenciesMeta": {
    "vue": { "optional": true }
  },
  "engines": {
    "node": ">=18.0.0"
  },
  "publishConfig": {
    "access": "public"
  },
  "license": "MIT"
}

2. Monorepo 根目录模板

json 复制代码
{
  "name": "my-monorepo",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "packageManager": "pnpm@9.15.0",
  "engines": {
    "node": ">=18.0.0"
  },
  "scripts": {
    "dev": "pnpm --filter app dev",
    "build": "pnpm -r build",
    "lint": "eslint .",
    "prepare": "husky install"
  },
  "devDependencies": {
    "eslint": "^9.0.0",
    "husky": "^9.0.0",
    "lint-staged": "^15.0.0",
    "prettier": "^3.0.0",
    "typescript": "^5.0.0"
  },
  "lint-staged": {
    "*.{js,ts,vue}": ["eslint --fix", "prettier --write"]
  }
}

3. 常见误区

误区 正解
vite/webpack 放到 dependencies 构建工具应放在 devDependencies
不设置 files 字段 会把整个项目(含源码)都发布上去
exportstypes 条件放在后面 TypeScript 要求 types 必须在第一个
不设置 sideEffects 使用者无法有效 Tree Shaking
不设置 engines 用户在低版本 Node 上可能出现诡异问题
不设置 private: true monorepo 根目录可能被意外 npm publish

结语

package.json 看似简单,实则承载了包的身份信息、入口解析、依赖管理、构建配置、发布流程等方方面面。理解每一个字段的含义和使用场景,不仅能帮你写出更规范的 npm 包,还能在排查 "模块找不到"、"类型丢失"、"打包体积过大" 等问题时快速定位根因。

希望这篇文章能成为你的 package.json 随身手册,收藏备用!


如果觉得有帮助,别忘了点个赞 👍 收藏一下,后续还会更新更多前端工程化干货。

相关推荐
东风破_18 分钟前
LLM 为什么记不住你?无状态、messages 和上下文管理
javascript·人工智能
梨子同志26 分钟前
qiankun
前端
梨子同志35 分钟前
Nginx
前端
梨子同志37 分钟前
NestJS
前端
梨子同志1 小时前
Next.js
前端
搭贝1 小时前
低代码平台私有化部署架构与信创全栈适配实战
低代码·架构·rxjava
谭光志1 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
Hilaku1 小时前
前端架构师的克制:什么时候该坚决对新技术说不?
前端·javascript·程序员
陈随易1 小时前
前端项目部署只要30秒
前端·后端·程序员
本末倒置1832 小时前
从 Vue CLI 迁移到 Rsbuild 后,JSX 突然全挂了?一次排查记录
前端