前奏
package.json
是我们最常见的配置文件,在工作中经常与其打交道。它可以帮助该 npm 包的使用者能更好的理解和使用该 npm 包。小柒详细的梳理了一下package.json
中各个配置。
必须属性
name
name
是一个包的唯一标识,不得和其他包名重复,必须小于等于214个字符,不能以 . 和 _ 开头,不能包含大写字母。
我们可以通过执行 npm view packageName
可以查看包名是否被占用。
version
格式按照主版本号.次版本号.修订号的形式。如果是不稳定可以发内部版本(alpha)、公测版本(beta)、候选版本(rc)(2.0.1-alpha)。参与过公司内部的组件库构建的小伙伴们应该最清楚不过了。
描述信息
description
该字段以字符串形式描述项目。
keywords
该字段以字符串数组的形式描述这个项目的关键词。
{
"keywords": ['lint', 'react','ts']
}
写好 description
和 keywords
可以使我们的 npm 包获得更多曝光。
author
描述该 npm 包作者。
{
"author":'xiaoqi'
// 或者
"author": {
"name" : "xiaoqi",
"email" : "xxxxx@xx.com",
"url" : "https://juejin.cn/user/1275089220808040"
}
}
contributors
描述项目贡献者。与 author
不同的是它是数组形式。
homepage
以字符串形式描述项目的主页地址。
repository
描述代码仓库地址。
{
"repository": "https://github.com/facebook/react.git"
// 或者
"repository": {
"type": "git",
"url": "https://github.com/facebook/react.git"
}
}
bugs
描述项目提交问题的地址。
{
"bugs": {
"url" : "https://github.com/facebook/react/issues",
"email" : "xxxxx@xx.com"
}
}
依赖配置
注意:声明在 dependencies
和 devDependencies
中的包,与打包工具将不将这些包打包没有关系。
dependencies:
声明项目在生产环境时所需要的依赖包。安装某个依赖包时,需判断生产环境下是否需要,再进行安装。
npm i xxx 或 npm i xxx --save 或 npm i xxx -S (小柒推荐)
该值是一个对象,记录了依赖包的名称和版本号。
dependencies: {
"clsx": "1.1.1"
"swiper": "^6.4.8"
}
前面说过,版本号一般遵循 主版本号.次版本号.修订号。我们安装的 npm 包的时候会碰到这样几种形式的版本号。
-
latest: 安装最新版本
-
^: 比如上述的 swiper 安装 6.x.x 的最新版本,但是不低于6.4.8 。这种形式是小柒在所开发的项目中,见的最多的一种形式。
-
~:比如 ~6.4.8。表示安装6.4.x 的最新版本,但是不低于6.4.8。
-
固定版本号
上面的 clsx 就是固定版本号。有时候某个依赖包的最新版本有问题的时候,可以指定安装固定的稳定版本。
devDependencies
声明项目在开发时才需要用到的依赖包。比如 eslint
、typescript
、vite
、prettier
这些都是开发是采用的辅助包,生产环境下不需要这些代码。
如果当前项目被当作依赖包被引用时,在对方使用 npm install --production
时不会安装devDependencies
中的包。
npm i xxx --save-dev 或 npm i xxx -D
dependencies: {
"eslint": "latest",
"typescript": "^4.4.4"
}
peerDependencies
适用的场景一般是插件或者组件库。
比如要在项目 A(主项目) 中实现某个功能,而这个功能相对独立且复杂的时候,我们可以把这部分功能提出来新起一个项目 B 来维护它,在项目 A 中以依赖包的形式去引入项目 B(依赖项目)。这和我们在项目引入别人的ui组件库是一样的道理。
那 peerDependencies 可以帮我们解决什么问题呢?
避免项目 A 安装了与项目B所依赖的核心包版本不一致的问题
比如项目 B 必须安装 react
和 react-dom
并且必须是 16.8.0 以上的才能运行,否则就会报错。那如果项目A中未安装或者安装了低版本的 react
、react-dom
依赖包,这样就会错误的发生。
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
我们在项目 B 的 package.json
文件下的添加 peerDependencies
字段,并声明所依赖的核心包及版本号(dependencies
中不再声明,如果声明了可以忽略 peerDependencies
字段)。这样相当于告知了项目A:“你要想安装我,就必须安装 react
和 react-dom
这两个包,并且版本要大于16.8.0,否则你可能会报错”。
小柒在写业务的时候如果项目A够大,项目B生产环境所依赖的包项目A基本都会安装,那小柒一般会将这些依赖包都写入 peerDependencies
字段, dependencies
中不再声明这些依赖包,直接让项目 A 去安装。
bundledDependencies
如果希望某些依赖包在打包发布的时候也被一起打包,可以在 bundledDependencies
中声明该包。注意这些包提前是在 dependencies
中声明过的。
{
"name": "my_test",
"version": "1.0.0",
"bundledDependencies": [
"react", "react-dom"
],
}
npm pack 后会生成 my_test-1.0.0.tgz
。这样 react
、react-dom
也会在 npm install my_test-1.0.0.tgz
时被下载。
optionalDependencies
另一种 dependencies
。如果在项目中,npm在安装dependencies
过程中可能因为出错会退出安装,对于在 optionalDependencies
中声明的模块的来说,即使出错了,也不会导致 npm install
中断退出。另外 optionalDependencies
会覆盖 dependencies
中的同名依赖包,不需要在两个地方都声明。
engines
描述模块运行的环境。这个场景比较适用于维护老项目,比如该项目对 node
版本 和 npm
版本都有要求,否则运行不起来。这样在 engines
中声明之后,会提醒开发者升级到指定的版本。
"engines": {
"node": ">= 11"
"npm": "~6.0.1"
}
脚本配置
scripts
用于配置运行脚本命令的缩写。
"scripts": {
"dev": "node index.js",
}
这样可以通过 npm run dev
来运行。该字段的好处是大大提升开发效率。
config
配置脚本中使用的环境变量。
{
"name" : "my_test",
"config": {"port": 3000}
}
这样在 scripts
的脚本中就可以使用 process.env.npm_package_config_port
来获取这个值。我们可以通过 nom config set
来修改这个值。
npm config set my_test:port 8000
目录、文件相关
files
该字段以数组的形式表示描述了发布 npm 包时所推送的文件列表。
{
"files": [
"dist",
"lib",
"es"
]
}
如果发布时,某些文件不想被发布,可以在根目录配置一个.npmignore
文件来排除一些文件(类似于.gitignore
文件),此时即使文件名被写入在 files
字段中也不会被发布。如果有.gitignore
文件,没有.npmignore
文件将会使用.gitignore
文件来代替。
main
指定程序加载的入口文件,在 browser
和 node
环境中都可以使用。没有指定该字段,默认是根目录的 index.js
文件。如果我们的包以 npm 形式被安装,那么 require 导入的 npm 包时,实际上就是导入的 mian 字段指定文件中的module.export
暴露出来的模块。
"main": "./src/index.js"
browser
如果 npm 包只能在 browser 端使用,使 browser 字段代替 main 字段来指定入口文件。
{
"browser": "./src/index.js"
}
bin
指定命令行工具的入口文件。这个字段在编写 node
工具的时候常常会用到,比如常见的 cli
工具。比如现在有一个my-cli
的 工具,其 package.json
中的 bin
字段为:
{
"bin": {
"my-cli": "./bin/index.js"
}
}
当我们执行 my-cli 命令的时候就会执行bin/index.js
文件中的代码。
如果是全局安装 my-cli 包,会在 /usr/local/bin
下 创建一个以 my-cli 为名字的 symlink
,指向全局安装的 my-cli 包的/bin/index.js 文件,可以直接使用 my-cli 命令来运行。
如果是本地安装 my-cli 包, 会在 node_modules/.bin
下建立名字为 my-cli 的symlink,执行本地安装的 my-cli 包的 /bin/index.js 文件。由于 node_modules/.bin/
目录会在运行时加入系统的 PATH
变量,可以直接使用 npm run my-cli
运行。(所有 node_modules/.bin/目录下的命令,都可以用npm run xx 的格式运行。)
man
用来给 Linux 下的 man 命令查找文档地址,是个单一文件或者文件数组。man 文件必须以数字结尾,或者如果被压缩了,以 .gz 结尾。数字表示文件将被安装到 man 的哪个部分。
{
"name": "my_test",
"version": "1.1.0",
"description": "",
"main": "index.js",
"man": "./man/doc.1"
}
通过 man my_test
命令可以 ./man/doc.1 文件的内容。
directories
该字段用来规范项目的目录。一个 node 模块是基于 CommonJS
模块化规范实现的,严格按照 CommonJS 规范,项目目录下除了package.json
文件以外,还需要包含以下目录:
-
bin
: 存放可执行二进制文件的目录 -
lib
:存放js代码的目录 -
doc
:存放文档的目录 -
test
:存放单元测试用例代码的目录…
在实际项目中我们可能没有严格按照上面的规范来命名,此时可以通过使用 directories 字段来指定项目的目录结构与上述规结构的对应关系。
"directories": {
"lib": "src/lib/",
"bin": "src/bin/",
"man": "src/man/",
}
发布配置
preferGlobal
如果你的 npm 包是需要全局安装,可以将这个字段设置为true,如果用户在本地安装了,会给出警告。
private
如果设置 private
为 true,可以防止将私有库发布到 npm 服务器。
{
"private": true
}
如果只想将包发布到某个私有的 npm 源或者只想发布某个 tag,可以配合 publishConfig
字段来配置相关信息。
publishConfig
{
"private": true,
"publishConfig": {
"tag": "1.1.0",
"registry": "https://registry.npmjs.org/",
"access": "public"
}
}
更多配置 npm.config
os
这个字段可以告知用户该 npm 包可以在什么操作系统使用。
"os": ["linux"]
"os": ["!win32"] // 禁用win32
cpu
与 os
类似,可以用 cpu
属性更精准的告知用户使用该包的 cpu 环境。
"cpu" : [ "x64", "ia32" ]
license
用于指定开源协议。不同的协议表示使用你代码的人拥有的的权利。作者可以根据自己的作品选择合适的协议,为使用者开放哪些权限。
"license": "MIT"
MIT
:只要用户在项目副本中包含了版权声明和许可声明,他们就可以拿你的代码做任何想做的事情,你也无需承担任何责任。Apache
:类似于MIT
,同时还包含了贡献者向用户提供专利授权相关的条款。GPL
:修改项目代码的用户再次分发源码或二进制代码时,必须公布他的相关修改。
第三方配置
还有其他比较常用的字段: typings
、eslintConfig
、gitHooks
、lint-staged
等,但非官方所出的字段,小柒这里不展开。
尾声
参考文章