package.json 指南

描述

package.json 文件必须是一个 JSON 格式的文件,而不是一个 JavaScript Object 对象。

本节内容将要介绍的大多数要点都与 config 里介绍过的配置设置有关。

name

如果你要发布一个包(package),那么 nameversion 是最重要的,也是必不可少的字段。nameversion 必须能组合成一个完全唯一的标识符。如果包产生了更新,那么 version 字段必须同时更新,用于产生一个新的唯一的 name-version 标识符。如果你没有打算发布你的包,那么 nameversion 字段是可选择的。

name 就是包的名称,简称包名。

一些规则:

  • 包名的长度必须小于或者等于 214 个字符。包括 scoped packages 的 scope。
  • scoped packages 的包名可以以一个点或者下划线开头。改规则不适用于 unscoped 包(非 scoped 包)。
  • 名称不允许包含大写字母。
  • 包名可以被当做 URL 的一部分、命令行的一个参数或者一个文件夹的名称。因此,包名不允许包含 non-URL-safe 的字符。

一些建议:

  • 不要用 node 核心模块的名字作为包名。
  • 名称中不要包含 "js" 或者 "node"。包会默认为 js,因为你正在编写一个 package.json 文件,如果你需要指定一个引擎时,可以使用 "engines" 字段。(下面会提到)
  • 包名会被当做参数传递给 require() 函数,所以名称应该尽量简短,但是需要保证一定的语意。
  • 命名一个包之前,你可能需要检查 npm 仓库是否已经包含了同名的包。https://www.npmjs.com/

名称可以选择在前面添加一个 scope,例如 @myorg/mypackage。点击 scope 获取更多细节。

version

如果你要发布一个包(package),那么 nameversion 是最重要的,也是必不可少的字段。nameversion 必须能组合成一个完全唯一的标识符。如果包产生了更新,那么 version 字段必须同时更新,用于产生一个新的唯一的 name-version 标识符。如果你没有打算发布你的包,那么 nameversion 字段是可选择的。

Version 值必须可以被 node-semver 解析。

description

包的描述,是一个字符串,可以帮助别人发现你的包,可以显示在 npm search 列表中。

keywords

与包有关的关键字,是一个字符串数组,可以帮助别人发现你的包,可以显示在 npm search 列表中。

homepage

包的主页 url。

例如:

"homepage": "https://github.com/owner/project#readme"

bugs

包的问题追踪的页面 url 地址,或者是可以发送 bug 信息的邮件地址。使用这个包的用户如果遇到了 bug 或者其他问题,可以给你发送问题详细信息。

它应该是这样的:

{
"url": "https://github.com/owner/project/issues",
"email": "project@hostname.com"
}

你可以指定 url 或者 email 字段中的至少一个字段。如果你只想提供一个 url,你可以指定 bugs 的值为一个普通字符串而不是一个 object。

如果提供了 url,那么它将会被 npm bugs 命令使用。

license

可以为你的包指定一个许可证,让别人知道使用该包是否有许可限制。

如果指定了一个常规的许可,例如 BSD-2-Clause 或者 MIT, 需要为正在使用的许可证添加当前的 SPDX 许可证标识符:

{ "license": "BSD-3-Clause" }

你可以查看SPDX 许可证 IDS 完整列表。通常你应该选择 OSI 认可的许可证。

如果包含多个许可,可以使用 SPDX 许可表达式语法 v2.0,像下面这样:

{ "license": "(ISC OR GPL-3.0)" }

如果你正在使用的许可,不在 SPDX 范围内,或者你正在使用一个自定义的许可证,那么你可以像下面这样指定:

{ "license": "SEE LICENSE IN <filename>" }

然后在包的根路径下包含 <filename> 文件。

一些很久之前的包使用 objects 或者包含许可 object 数组的 licenses 属性指定许可:

// Not valid metadata
{ "license" :
{
"type" : "ISC",
"url" : "https://opensource.org/licenses/ISC"
}
}

// Not valid metadata
{ "licenses" :
[
{
"type": "MIT",
"url": "https://www.opensource.org/licenses/mit-license.php"
},
{
"type": "Apache-2.0",
"url": "https://opensource.org/licenses/apache2.0.php"
}
]
}

这些风格目前已经被丢弃了。使用 SPDX 表达式代替:

{ "license": "ISC" }
{ "license": "(MIT OR Apache-2.0)" }

最后,如果你不希望在任何条款下授予他人使用私有或未发布的软件包的权利,可以这样指定:

{ "license": "UNLICENSED" }

也可以考虑设置 "private": true ,防止意外发布。

人员字段:author, contributors

author 是一个 person,contributors 是一个 person 数组。 person 是一个包含 name 属性和可选择的 urlemail 属性的 object。像这样:

{
"name": "Barney Rubble",
"email": "b@rubble.com",
"url": "http://barnyrubble.tumblr.com/"
}

或者你可以用下面的字符串简写,npm 会替你解析下面的字符串:

"Barney Rubble <b@rubble.com> (http://barnyrubble.tumblr.com/)"

emial 和 url 是可选择的字段。

npm 会用你的 npm 用户信息,设置一个顶级的 maintainers 字段。

funding

你可以指定一个包含 URL 的 object,该 object 提供了资助你的包的开发的最新信息,可以是一个字符串 URL,也可以是一个数组:

"funding": {
"type" : "individual",
"url" : "http://example.com/donate"
}

"funding": {
"type" : "patreon",
"url" : "https://www.patreon.com/my-account"
}

"funding": "http://example.com/donate"

"funding": [
{
"type" : "individual",
"url" : "http://example.com/donate"
},
"http://example.com/donateAlso",
{
"type" : "patreon",
"url" : "https://www.patreon.com/my-account"
}
]

用户可以使用 npm fund 命令,列出项目所有依赖包的 funding url。也可以使用 npm fund <projectname> 列出指定包的 funding url(当有多个 URLS,第一个会被访问)。

files

可选择的 files 字段,是一个文件匹配字符串,当你的包被安装为一个项目依赖时,被 files 字段指定的文件将会被包含。文件匹配采用的语法类似于 .gitignore 文件。忽略该字段,等价于 ["*"],表示包含所有文件。

一些特殊的文件,会被包含或者排除,无论它们是否被 files 字段指定(看下面)。

你还可以在包根目录或者子目录下提供一个 .npmignore 文件,与 .gitignore 类似,它会防止文件被包含。如果 .npmignore 在包的根目录下,它不会覆盖 files 字段内容,但是如果 .npmignore 在子目录下,则会覆盖 files 字段内容。如果有 .gitignore 文件,却没有 .npmignore 文件,那么会默认使用 .gitignore 文件内容作为 .npmignore 的内容。

files 字段指定的文件,不能通过 .npmignore 或者 .gitignore 排除。

一些文件会永远被包含在包内,无论怎么设置:

  • package.json
  • README
  • CHANGES / CHANGELOG / HISTORY
  • LICENSE / LICENCE
  • NOTICE
  • "main" 字段指定的文件

README, CHANGES, LICENSE & NOTICE 可以是任意文件扩展名。

一些文件会永远被排除在包外,无论怎么设置:

  • .git
  • CVS
  • .svn
  • .hg
  • .lock-wscript
  • .wafpickle-N
  • .DS_Store
  • npm-debug.log
  • .npmrc
  • node_modules
  • config.gypi
  • package-lock.json
  • 所有包含 * 字符的文件 (与 Windows 不兼容)

main

main 字段是一个模块 ID,只是了你的程序的入口点。如果你的包名为 foo,用户安装了你的包,并且使用 require("foo") 导入你的包,然后你的程序的 package.json 文件的 main 字段指定的文件导出的对象将会被返回。

它应该是一个相对于包的根路径的 module ID。

对于大多数模块来说,有一个主脚本,而没有太多其他的东西,是最有意义的。

browser

如果你的包打算被用于客户端程序,那么 browser 字段应该被指定,而不是 main 字段。这可以提示用户,它或许依赖于一些基础的在nodejs 环境下没有的东西(比如 window)。

"browser": "./lib/browser/main.js"

bin

很多包拥有一个或者多个可执行文件,并且希望安装在 PATH 中。npm 可以很简单的实现这个(实际上,就是使用这个特性安装的 npm 可执行文件)。

为了使用这个特性,需要在 package.json 文件中指定 bin 字段,它表示命令与本地文件名称的映射关系。当进行全局安装时,npm 将这个文件与 prefix/bin 进行符号连接(symlink),进行本地安装时,会将这个文件与 node_modules/.bin/ 进行符号连接。

例如,myapppackage.json 包含以下内容:

{ "bin": { "myapp": "./cli.js" } }

当你全局安装 myapp 时, npm 会从 cli.js 脚本创建一个符号连接至 usr/local/bin/myapp 目录。

如果你只有一个可执行文件,那么你可以提供一个字符串,像这样:

{
"name": "my-program",
"version": "1.2.5",
"bin": "./path/to/program"
}

上面的写法,等价于:

{
"name": "my-program",
"version": "1.2.5",
"bin": { "my-program": "./path/to/program" }
}

最后,请确保 bin 字段引用的文件内容以 #!/usr/bin/env node 开头,用于指示该脚本的执行需要 node。

directories

通过该字段描述包的文档结构,很少使用。

  1. directories.lib
  2. directories.bin
  3. directories.man
  4. directories.doc
  5. directories.example
  6. directories.test

repository

说明包的代码仓库在哪里。如果 git 仓库在 Github 上,使用 npm docs 命令,会跳转到仓库页面。

"repository": {
"type" : "git",
"url" : "https://github.com/npm/cli.git"
}

"repository": {
"type" : "svn",
"url" : "https://v8.googlecode.com/svn/trunk/"
}

如果是 Github,Github gist Bitbucker 或者 GitLab 仓库,你可以使用简写的方式:

"repository": "npm/npm"

"repository": "github:user/repo"

"repository": "gist:11081aaa281"

"repository": "bitbucket:user/repo"

"repository": "gitlab:user/repo"

如果 package.json 文件不在项目的根目录下,你可以指定包所在的目录:

"repository": {
"type" : "git",
"url" : "https://github.com/facebook/react.git",
"directory": "packages/react-dom"
}

scripts

scripts 属性是一个包含脚本命令的字典,这些命令在包的生命周期的不同时间运行。

scripts 页面可以获得更多详细信息。

config

config 对象可以被用来配置 scripts 的参数,例如:

{
"name": "foo",
"config": { "port": "8080" }
}

有一个 start 命令,并且可以通过 npm_package_config_port 变量引用设置的 port。用户也可以通过 npm config set foo:port 8001 覆盖配置。

可以在 configscripts 获取更多信息。

dependencies

指定项目依赖,值为包名加上版本号。

版本号可以指定一个范围,有以下语法。

  • version:精确的版本,例如 1.0.0
  • >version:大于 version
  • >=version:大于等于
  • <version: 小于
  • <=version: 小于等于
  • ~version: 允许补丁级别的变化,例如 ~1.2.3 表示 >=1.2.3 <1.3.0
  • ^version:允许不更改最左侧非0版本号数字的变化,例如 ^1.2.3 表示 >=1.2.3 <2.0.0
  • 1.2.x
  • http://...
  • *
  • version1 - version2 等同于 >=version1 <=version2

可以在 semver 获取更多关于 version 的信息。

{
"dependencies": {
"foo": "1.0.0 - 2.9999.9999",
"bar": ">=1.0.2 <2.1.2",
"baz": ">1.0.2 <=2.3.4",
"boo": "2.0.1",
"qux": "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0",
"asd": "http://asdf.com/asdf.tar.gz",
"til": "~1.2",
"elf": "~1.2.3",
"two": "2.x",
"thr": "3.3.x",
"lat": "latest",
"dyl": "file:../dyl"
}
}

可以使用 URL 代替版本号。

也可以使用本地路径。

{
"name": "baz",
"dependencies": {
"bar": "file:../foo/bar"
}
}

devDependencies

适用于开发环境的依赖包。

peerDependencies

防止包重复安装的字段。

举个例子,假设你的程序依赖了 A、B 和 C 三个包,同时 B 和 C 又依赖了 A,那么当你安装 A、B、C 时,B 和 C 又会重复安装 A,所以可以将 A 添加到 C 的 peerDependencies 字段下,这样当你的程序安装依赖时,A 只会被安装一次,B 和 C 不会重复安装 A。

一般用于指定当前包兼容的宿主版本,例如我们要编写一个 webpack 插件,当前插件兼容的 webpack 为 3.x, 此时我们可以这样指定:

{
"peerDependencies": {
"webpack": "3.x"
}
}

bundledDependencies

打包依赖,在发布时会将这个对象指定的包,一起打包到最终要发布的包里。

optionalDependencies

可选依赖包,如果一些包,即使安装失败,项目仍然能够正常运行,或者希望 npm 继续运行,就可以使用该字段指定可选包。

engines

可以指定一些运行环境,例如 node 和 npm:

{
"engines": {
"node": ">=0.10.3 <0.12",
"npm": "~1.0.20"
}
}

参考