package.json 是一个用于描述和配置项目的重要文件,其中包含了许多字段和选项,可以影响项目的构建、依赖管理、脚本执行等方面。
描述配置
name
定义项目的名称,不能以”.”和”_”开头,不能包含大写字母(这是因为当软件包在npm上发布时,会基于此属性获得自己的URL,所以不能包含非URL安全字符(non-url-safe)
Tip: 我们平时开发的很多项目并不会发布在npm上,所以这个名称是否标准可能就不是那么重要,它不会影响项目的正常运行。如果需要发布在npm上,name字段一定要符合要求
version
定义项目的版本号,格式为:大版本号.次版本号.修订号 1.x.x
如果某个版本的改动较大,并且不稳定,可能无法满足预期的兼容性需求,就需要发布先行版本,先行版本通过会加在版本号的后面,通过“-”号连接以点分隔的标识符和版本编译信息:内部版本(alpha)、公测版本(beta)和候选版本(rc,即release candiate)
// 查看最新版本
npm view antd version
// 查看所有版本
npm view antd versions
repository
项目代码仓库地址
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git",
"directory": "packages/react"
}
keywords
一组项目的技术关键词,比如 Ant Design 组件库的 keywords 如下:
"keywords": [
"ant",
"component",
"components",
"design",
"framework",
"frontend",
"react",
"react-component",
"ui"
],
description
项目的描述,让别人能快速了解该项目。
author
author顾名思义就是作者,表示该项目包的作者。它有两种形式,一种是字符串格式:
"author": "xxx",
另一种是对象形式:
"author": {
"name" : "xxx",
"email" : "xxxxx@xx.com",
"url" : "xxx"
}
文件配置项
main
main 字段用来指定加载的入口文件,在 browser 和 Node 环境中都可以使用。如果我们将项目发布为npm包,那么当使用 require 导入npm包时,返回的就是main字段所列出的文件的module.exports 属性。如果不指定该字段,默认是项目根目录下的index.js。如果没找到,就会报错。
"main": "./src/index.js"
browser
browser字段可以定义 npm 包在 browser 环境下的入口文件。如果 npm 包只在 web 端使用,并且严禁在 server 端使用,使用 browser 来定义入口文件。
module
module字段可以定义 npm 包的 ESM 规范的入口文件,browser 环境和 node 环境均可使用。如果 npm 包导出的是 ESM 规范的包,使用 module 来定义入口文件。
"module": "./src/index.mjs",
当一个项目同时定义了 main,browser 和 module,像 webpack,rollup 等构建工具会感知这些字段,并会根据环境以及不同的模块规范来进行不同的入口文件查找。
"main": "./index.js",
"browser": "./browser/index.js",
"module": "./index.mjs"
files
files配置是一个数组,用来描述当把npm包作为依赖包安装时需要说明的文件列表。当npm包发布时,files指定的文件会被推送到npm服务器中,如果指定的是文件夹,那么该文件夹下面所有的文件都会被提交。避免安装时间太长。发布时默认会包括 package.json,license,README 和main
字段里指定的文件。忽略 node_modules,lockfile 等文件。
"files": [
"filename.js",
"directory/",
"glob/*.{js,json}"
]
type
在 node 支持 ES 模块后,要求 ES 模块采用 .mjs
后缀文件名。只要遇到 .mjs
文件,就认为它是 ES 模块。如果不想修改文件后缀,就可以在 package.json文件中,指定 type 字段为 module。
"type": "module"
exports
node 在 14.13 支持在 package.json 里定义 exports 字段,拥有了条件导出的功能。
exports 字段可以配置不同环境对应的模块入口文件,并且当它存在时,它的优先级最高。
使用exports
字段,您可以指定模块的不同导出路径,并控制在不同环境下(如ES模块和CommonJS模块)如何解析和导出模块。
"exports": {
".": {
"require": "./index.cjs",
"import": "./index.mjs"
},
"./feature": {
"require": "./feature.cjs",
"import": "./feature.mjs"
}
}
这样的配置在使用 import 'xxx'
和 require('xxx')
时会从不同的入口引入文件
还可以为包中的特定子路径定义导出路径。例如,如果您有一个lib
目录,并希望允许用户直接导入其中的模块,可以这样配置:
"exports": {"./lib/*": "./lib/*.js"}
这允许用户使用以下方式导入模块:
import feature from 'my-package/lib/feature';
workspaces
项目的工作区配置,用于在本地的根目录下管理多个子项目。可以自动地在 npm install 时将 workspaces 下面的包,软链到根目录的 node_modules 中,不用手动执行 npm link
操作。
workspaces 字段接收一个数组,数组里可以是文件夹名称或者通配符。比如:
"workspaces": [
"workspace-a"
]
表示在 workspace-a 目录下还有一个项目,它也有自己的 package.json。
通常子项目都会平铺管理在 packages 目录下,所以根目录下 workspaces 通常配置为:
"workspaces": [
"packages/*"
]
// workspaces 配置指向 packages 目录中的所有子目录,这些子目录都将被视为独立的包。
工作空间的优点
- 依赖共享:所有工作空间包共享相同的
node_modules
目录,从而避免重复安装相同的依赖项,节省磁盘空间和安装时间。 - 简化管理:可以通过根
package.json
文件来管理所有工作空间包的依赖和脚本,简化版本控制和发布流程。 - 跨包开发:允许在工作空间包之间轻松链接和引用,促进跨包开发和集成。
脚本配置
scripts
指定项目的一些内置脚本命令,这些命令可以通过 npm run 来执行。通常包含项目开发,构建 等 CI 命令,
除了运行基本的scripts命令,还可以结合pre和post完成前置和后续操作
"scripts": {
"build": "webpack",
"prebuild": "xxx", // build 执行之前的钩子
"postbuild": "xxx" // build 执行之后的钩子
}
当执行 npm run build
命令时,会按照 prebuild -> build -> postbuild 的顺序依次执行上方的命令
但是这样的隐式逻辑很可能会造成执行工作流的混乱,所以pnpm 从 7.14.0 版本开始 和 yarn2 都已经废弃掉了这种 pre/post 自动执行的逻辑,
如果需要手动开启,pnpm 项目可以设置 .npmrc
enable-pre-post-scripts=true。
enable-pre-post-scripts=true
config
config字段用来配置scripts运行时的配置参数
"config": {
"port": "3001"
}
// console.log(process.env.npm_package_config_port) // 3001
用户可以通过npm config set foo:port xxxx
命令来重写port的值。
依赖配置
dependencies
dependencies字段中声明的是项目的生产环境中所必须的依赖包。使用 npm install xxx
或则 npm install xxx --save
时,会被自动插入到该字段中。
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
}
这里每一项配置都是一个键值对(key-value), key表示模块名称,value表示模块的版本号。版本号遵循主版本号.次版本号.修订号的格式规定:
- 固定版本: 上面的react-scripts的版本4.0.3就是固定版本,安装时只安装这个指定的版本;
- 波浪号: 比如~4.0.3,表示安装4.0.x的最新版本(不低于4.0.3),也就是说安装时不会改变主版本号和次版本号;
- 插入号: 比如上面 react 的版本^17.0.2,表示安装17.x.x的最新版本(不低于17.0.2),也就是说安装时不会改变主版本号。如果主版本号为0,那么插入号和波浪号的行为是一致的;
- latest:安装最新的版本。
需要注意,不要把测试或者过渡性的依赖放在dependencies,避免生产环境出现意外的问题。
devDependencies
devDependencies中声明的是开发阶段需要的依赖包,如Webpack、Eslint、Babel等,用于辅助开发。它们不同于 dependencies,因为它们只需安装在开发设备上,而无需在生产环境中运行代码。当打包上线时并不需要这些包,所以可以把这些依赖添加到 devDependencies 中,这些依赖依然会在本地指定 npm install 时被安装和管理,但是不会被安装到生产环境中。
使用 npm install xxx -D
或者 npm install xxx --save-dev
时,会被自动插入到该字段中。
peerDependencies
有些情况下,我们的项目和所依赖的模块,都会同时依赖另一个模块,但是所依赖的版本不一样。比如,我们的项目依赖A模块和B模块的1.0版,而A模块本身又依赖B模块的2.0版。大多数情况下,这不是问题,B模块的两个版本可以并存,同时运行。但是,有一种情况,会出现问题,就是这种依赖关系将暴露给用户。
最典型的场景就是插件,比如A模块是B模块的插件。用户安装的B模块是1.0版本,但是A插件只能和2.0版本的B模块一起使用。这时,用户要是将1.0版本的B的实例传给A,就会出现问题。因此,需要一种机制,在模板安装的时候提醒用户,如果A和B一起安装,那么B必须是2.0模块。
peerDependencies字段就是用来供插件指定其所需要的主工具的版本。
"name": "chai-as-promised",
"peerDependencies": {
"chai": "1.x"
}
上面代码指定在安装chai-as-promised模块时,主程序chai必须一起安装,而且chai的版本必须是1.x。如果项目指定的依赖是chai的2.0版本,就会报错。
需要注意,从npm 3.0版开始,peerDependencies不再会默认安装了。
optionalDependencies
可选依赖,顾名思义,表示依赖是可选的,它不会阻塞主功能的使用,安装或者引入失败也无妨。这类依赖如果安装失败,那么 npm 的整个安装过程也是成功的。
比如我们使用 colors 这个包来对 console.log 打印的信息进行着色来增强和区分提示,但它并不是必需的,所以可以将其加入到 optionalDependencies,并且在运行时处理引入失败的逻辑。
使用 npm install xxx -O
或者 npm install xxx --save-optional
时,依赖会被自动插入到该字段中。
"optionalDependencies": {
"colors": "^1.4.0"
}
bundleDependencies
打包依赖。它的值是一个数组,在发布包时,bundleDependencies 里面的依赖都会被一起打包。
比如指定 react 和 react-dom 为打包依赖:
"bundleDependencies": [
"react",
"react-dom"
]
在执行 npm pack
打包生成 tgz 压缩包中,将出现 node_modules 并包含 react 和 react-dom。
需要注意的是,这个字段数组中的值必须是在 dependencies,devDependencies 两个里面声明过的依赖才行
普通依赖通常从 npm registry 安装,但当你想用一个不在 npm registry 里的包,或者一个被修改过的第三方包时,打包依赖会比普通依赖更好用。
overrides
overrides 可以重写项目依赖的依赖,及其依赖树下某个依赖的版本号,进行包的替换。 overrides 支持任意深度的嵌套。
比如某个依赖 A,由于一些原因它依赖的包 foo@1.0.0 需要替换,我们可以使用 overrides 修改 foo 的版本号:
"overrides": {
"foo": "1.1.0-patch"
}
当然这样会更改整个依赖树里的 foo,我们可以只对 A 下的 foo 进行版本号重写:
"overrides": {
"A": {
"foo": "1.1.0-patch",
}
}
engines
可能对npm包的版本或者Node版本有特殊要求,如果不满足条件就可能无法将项目跑起来。为了让项目开箱即用,可以在engines字段中说明具体的版本号:
"engines": {
"node": ">=8.10.3 <12.13.0",
"npm": ">=6.9.0"
}
packageManager
packageManager
是一个配置选项,用于指定项目使用的包管理器。
"packageManager": "pnpm",
// "packageManager": "pnpm@8.6.2",
// npm: 使用 npm 作为包管理器。
// yarn: 使用 Yarn 作为包管理器。
// pnpm: 使用 pnpm 作为包管理器
如果您的项目在不同的开发者或团队之间共享,并且有些开发者使用 Yarn,而有些开发者使用 npm,您可以通过指定 packageManager
来确保所有开发者在依赖管理和脚本执行时的一致性。
也可以通过@ 来指定版本
发布配置
是和项目发布相关的配置
private
如果是私有项目,不希望发布到公共 npm 仓库上,可以将 private 设为 true。
"private": true
publishConfig
publishConfig 就是 npm 包发布时使用的配置。
比如在安装依赖时指定了 registry 为 taobao 镜像源,但发布时希望在公网发布,就可以指定 publishConfig.registry。
"publishConfig": {
"registry": "https://registry.npmjs.org/"
}
通常情况下,publishConfig会配合private来使用,如果只想让模块发布到特定npm仓库,就可以这样来配置:
"private": true,
"publishConfig": {
"tag": "1.1.0",
"registry": "https://registry.npmjs.org/",
"access": "public"
}
配置项说明
- access: 发布包的访问级别。可能的值包括:
public
: 公开访问,所有人都可以访问。restricted
: 限制访问,需要授权才能访问(通常需要设置特定的 npm 配置)。private
: 私有包,不会发布到公共注册表(通常用于企业内部使用)。
- tag: 发布时的标签。默认情况下是
latest
,表示推荐使用的稳定版本。您也可以指定其他标签,如next
或beta
,用于发布预览或测试版本。 - registry: 发布的注册表地址。默认情况下是 npm 的公共注册表 (
https://registry.npmjs.org/
),但您可以设置为其他私有注册表的地址。
使用场景
- 私有包管理: 如果您在使用私有 npm 注册表或企业内部的包管理系统,可以通过
publishConfig
设置正确的注册表和访问级别。 - 多版本控制: 对于具有复杂发布流程或多个稳定性级别的项目,使用不同的标签(如
next
、beta
)可以帮助您管理不同版本的发布。
os
os字段可以让我们设置该npm包可以在什么操作系统使用,不能再什么操作系统使用。如果我们希望开发的npm包只运行在linux,为了避免出现不必要的异常,建议使用Windows系统的用户不要安装它,这时就可以使用os配置:
"os" ["linux"] // 适用的操作系统
"os" ["!win32"] // 禁用的操作系统
cpu
指定项目只能在特定的 CPU 体系上运行。
"cpu" ["x64", "AMD64"] // 适用的cpu
"cpu" ["!arm", "!mips"] // 禁用的cpu
第三方配置
一些第三方库或应用在进行某些内部处理时会依赖这些字段,使用它们时需要安装对应的第三方库。
types 或者 typings
用于指定 TypeScript 项目中的类型定义文件。它通常指向一个 TypeScript 类型定义文件或模块入口文件。
"typings": "types/index.d.ts",
eslintConfig
eslint的配置可以写在单独的配置文件.eslintrc.json 中,也可以写在package.json文件的eslintConfig配置项中。
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
},
}
unpkg
unpkg
是一个用于提供 npm 包的 CDN(内容分发网络)服务,它允许您直接访问和使用 npm 上发布的包,无需安装到本地或者配置构建工具。
"unpkg": "dist/vue.js"
通过 unpkg
,您可以直接在浏览器或 Node.js 中引入和使用 npm 包。假设您想要使用 lodash
这个包,可以通过以下方式在浏览器中引入:
<script src="https://unpkg.com/lodash"></script>
指定版本
也可以指定具体的版本号来加载包,例如:
<script src="https://unpkg.com/lodash@4.17.21"></script>
优势和适用场景
- 无需安装依赖:直接通过 CDN 引入包,无需在本地安装 npm 包或配置构建工具。
- 快速加载:利用 CDN 加速服务,包的加载速度通常很快。
- 调试和学习:在浏览器中直接引入包,方便快速测试和学习新的库或工具。
jsdelivr
与 unpkg 类似
"jsdelivr": "dist/index.min.js",
browserslist
设置项目的浏览器兼容情况。babel 和 autoprefixer 等工具会使用该配置对代码进行转换
通常情况下,browserslist
的配置信息可以放在项目的根目录下的 .browserslistrc
文件中,或者直接写在 package.json
文件的 browserslist
字段中。
"browserslist": [
"> 1%",
"last 2 versions"
]
常见的配置选项包括:
最近版本:例如 last 2 versions
表示支持最近两个主流浏览器版本。
全球使用率:例如 1%
表示支持全球使用量超过 1% 的浏览器。
特定浏览器版本:例如 Firefox >= 60
表示支持 Firefox 浏览器的版本大于或等于 60。
排除特定浏览器:例如 not IE 11
表示不支持 IE 11 浏览器。
特定地区覆盖率:例如 cover 99.5% in CN
表示在中国市场上支持覆盖率达到 99.5% 的浏览器。
sideEffects
sideEffects
是一个用来告知 JavaScript 模块系统哪些模块是“有副作用”的标志。这个字段通常用于优化打包工具如 Webpack,在构建过程中决定是否可以安全地剔除未使用的模块。
sideEffects
字段可以是一个布尔值或者是一个字符串数组,用来指定哪些模块有副作用(即模块导入后会影响全局状态或执行代码),从而防止它们被打包工具过度优化(例如在生产环境下删除未使用的代码)。
false
:表示所有模块都没有副作用,可以安全地进行无用代码删除优化。这在一些库和工具中很常见,因为它们的导入不会影响到全局状态。
true
:表示所有模块都有副作用,无论是否使用。这在大多数应用程序中是默认的,因为它们的模块可能会动态导入或执行一些需要全局影响的操作。
字符串数组:列出具体有副作用的模块路径。例如:
{
"sideEffects": [
"./src/some-side-effectful-module.js",
"./src/another-side-effectful-module.js"
]
}
使用场景
优化打包:在开发 JavaScript 应用程序或库时,使用 sideEffects
字段可以帮助打包工具更智能地处理模块的导入和优化,减少打包后的体积。
库和工具:对于一些导入但不直接使用的模块,可以显式地指定它们没有副作用,以帮助打包工具更有效地进行优化。
动态加载:当应用程序需要动态地加载模块时,sideEffects
字段可以帮助打包工具知道哪些模块可能被动态引入,以便进行适当的处理。
例子:
如果 Ant Design 的 package.json 里不设置 sideEffects,那么 webapck 构建打包时会认为这段代码只是引入了但并没有使用,可以 tree-shaking 剔除掉,最终导致产物缺少样式。
所以 Ant Design 在 package.json 里设置了如下的 sideEffects,来告知 webpack,这些文件具有副作用,引入后不能被删除。
"sideEffects": [
"dist/*",
"es/**/style/*",
"lib/**/style/*",
"*.less"
]
lint-staged
lint-staged 是用于对 git 的暂存区的文件进行操作的工具,它允许您定义在提交代码前应该运行的脚本。这些脚本通常用于执行代码风格检查、格式化、单元测试等任务,
{
"name": "my-package",
"version": "1.0.0",
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
],
"*.css": [
"stylelint --fix",
"git add"
],
"*.json": [
"prettier --write",
"git add"
]
},
"scripts": {
"lint-staged": "lint-staged"
},
"devDependencies": {
"eslint": "^8.0.0",
"stylelint": "^15.0.0",
"prettier": "^2.0.0",
"lint-staged": "^12.0.0"
}
}
lint-staged 通常配合 husky 这样的 git-hooks 工具一起使用。git-hooks 用来定义一个钩子,这些钩子方法会在 git 工作流程中比如 pre-commit,commit-msg 时触发,可以把 lint-staged 放到这些钩子方法中。
其他npm相关
npm link
npm link
是 Node.js 包管理工具 npm 提供的一个命令,用于在本地开发中将一个本地模块链接到全局安装的 npm 模块目录中。这个命令在开发和测试自己的 npm 包或在不同项目之间共享本地模块时特别有用。
使用场景和功能
- 本地开发模块:当您正在开发一个 npm 包,并且希望在其他项目中测试它时,可以使用
npm link
将该模块链接到全局安装,以便在其他项目中像使用正常 npm 包一样使用它。 - 共享本地模块:如果有多个项目需要使用同一个本地模块,而不想每次都手动复制和粘贴文件,可以使用
npm link
来建立一个链接,从而在多个项目中共享这个模块的最新版本。
当完成本地npm包调试后,记得将链接断开。
另外一种方法 yalc 使用方法
建议优先使用Yalc, yalc 的方案是在本地模拟一个 npm 仓库,使用真实的 npm package 代替各种 link ,除了不会发布到真实远端仓库外,都和真实发包无异。
但用npm link引入的依赖由于资源文件不在项目下,webpack不会对其做预编译,导致实际构建或者运行时会报错,此时如果直接将文件复制进依赖目录则能正常运行,yalc能解决此类问题。
咨询方案 获取更多方案详情