如何使用package.json文件
最近在整理之前写的模块的时候,发现很多模块的package.json写的并不是那么规范,所以查阅了一些资料,了解了一下关于如何使用package.json,列出来供大家参考
本文参考了这三篇文章
属性列表
概述
这篇文档告诉了你package.json里面,包含了那些字段。这个文件必须是个json文件,而不仅是一个js对象。文档中很多属性和设置可以通过npm-config来生成。
name(必填字段)
package.json中有两个字段是必填字段。name字段和version字段。缺少这两个字段则无法安装npm模块。每个npm模块也是依赖这两个字段作为唯一标识。如果你的npm模块有所修改,那么对应的version字段也应该有所改变。
name字段就是你的npm模块的名称。
name字段需要符合以下规则:
name必须<= 214 个字节,包括模块的前缀
不得以“_” 或者 “.” 作为name的开头
不能有大写字符
因为name字段会成为URL的一部分,或是命令行的一个实参,也有可能是个文件夹的名字,所以不能包含no-URL-safe(URL非法)字符。
一些建议:
不要用和node核心模块一样的名称
不要把“js”和”node”字段包含在name中。因为你实际在编写json文件,而包含这些字段会被认为是个js文件而非npm模块,如果你需要指定某些引擎的话,可以在“engines”字段中填写。
name会被写在require()的参数中,所以name最好简短且明确。
创建一个name的时候,最好去https://www.npmjs.com/查查名称是否被占用。
name可以有一些前缀如 例如 @myorg/mypackage.可以在npm-scope的中查看详情。
version(必填字段)
package.json中有两个字段是必填字段。name字段和version字段。缺少这两个字段则无法安装npm模块。每个npm模块也是依赖这两个字段作为唯一标识。如果你的npm模块有所修改,那么对应的version字段也应该有所改变。
version字段必须可以被node-semver这个模块解析,是个和npm捆绑在一起的包。
这里有关于版本号形式的含义nodejs中每个版本形式的含义
description
一段字符串,用来描述这个npm模块的作用,通过npm search的时候回用到。
keywords
一个由字符串组成的数组,也有助于别人通过npm search的时候快速找到你的包。
homepage
这个项目的主页URL。 注意:这里和url属性不是一个东西,如果你填了url属性,npm的注册工具会认为你把项目发布到别的地方了,就不会去npm官方仓库去找。
bugs
包含你的项目的issue和email地址,如果别人在使用你的包的时候遇到了问题,可以通过这里找到你并提交问题。
它的格式如下:
{
"url" : "https://github.com/owner/project/issues",
"email" : "project@hostname.com"
}
url和email你可以选填其中一个或者两个,如果只填一个,可以直接写成字符串,而不是一个对象。
如果提供了url, 使用npm bugs命令的时候会用到。
license
给你的模块定一个协议,让大家知道这个模块的使用权限。例如:遵循BSD-2-Clause or MIT协议。添加一个SPDX许可如下:
{ "license" : "BSD-3-Clause" }
这里查看SPDX协议完整列表。理想情况下,你应该选一个OSI许可(开源许可)。
如果你的模块遵循多种许可,可以使用SPDX协议2.0的语法,如下:
{ "license" : "(ISC OR GPL-3.0)" }
如果你使用的是许可证还没有分配一个SPDX标识符,或者如果您使用的是一个定制的许可证,使用这样的字符串值:
{ "license" : "SEE LICENSE IN <filename>" }
然后在模块的顶部include 这个<filename>的文件。
一些旧的模块使用许可对象或一个“许可证”属性,其中包含许可对象数组:
// Not valid metadata
{ "license" :
{ "type" : "ISC"
, "url" : "http://opensource.org/licenses/ISC"
}
}
// Not valid metadata
{ "licenses" :
[
{ "type": "MIT"
, "url": "http://www.opensource.org/licenses/mit-license.php"
}
, { "type": "Apache-2.0"
, "url": "http://opensource.org/licenses/apache2.0.php"
}
]
}
上面的样式现在已经弃用。现在使用SPDX表达式,是这样的:
{ "license": "ISC" }
{ "license": "(MIT OR Apache-2.0)" }
最后,如果你不希望别人在任何条件下有任何使用你的包的权限,你可以这样:
{ "license": "UNLICENSED"}
也考虑设置"private": true,来防止模块的意外发布
people fields: author, contributors
用户相关的属性:author是一个作者,contributors是一个包含一堆作者的数组。每个person有一些描述的字段,如下:
{ "name" : "Barney Rubble"
, "email" : "b@rubble.com"
, "url" : "http://barnyrubble.tumblr.com/"
}
也可以用下面的格式简写,npm会自动解析:
"Barney Rubble <b@rubble.com> (http://barnyrubble.tumblr.com/)"
email和url属性实际上都是可以省略的。描述用户信息的还有一个"maintainers"(维护者)属性。
files
file字段是一个包含在你项目里的文件的数组,里面的内容是文件名或者文件夹名。如果是文件夹,那么里面的文件也会被包含进来,除非你设置了ignore规则。你也可以在模块根目录下创建一个".npmignore"文件(windows下无法直接创建以"."开头的文件,使用linux命令行工具创建如git bash),写在这个文件里边的文件即便被写在files属性里边也会被排除在外,这个文件的写法".gitignore"类似。
以下文件始终包含在内,无论是否设置:
package.json
README (and its variants)
CHANGELOG (and its variants)
LICENSE / LICENCE
相反,以下文件通常会被忽略:
.git
CVS
.svn
.hg
.lock-wscript
.wafpickle-N
*.swp
.DS_Store
._*
npm-debug.log
main
main字段规定了程序的主入口文件。如果你的模块命名为foo,用户安装后,就会通过require("foo")来引用该模块,返回的内容就是你的模块的 module.exports指向的对象。
这是一个相对于你的模块文件夹的模块ID,对于大多数的模块,有个主脚本就足够了。
bin
很多模块有一个或多个可执行文件需要配置到PATH路径下。npm就是通过这个特性安装,使得npm可执行。
要用这个功能,给package.json中的bin字段一个命令名到文件位置的map。初始化的时候npm会将他链接到prefix/bin(全局初始化)或者./node_modules/.bin/(本地初始化)。
例如:一个myapp模块可能是这样:
{ "bin" : { "myapp" : "./cli.js" } }
所以,当你安装myapp,npm会从cli.js文件创建一个到/usr/local/bin/myapp路径下。
如果你只有一个可执行文件,并且名字和包名一样。那么你可以只用一个字符串,比如:
{ "name": "my-program"
, "version": "1.2.5"
, "bin": "./path/to/program" }
和下面是一样的效果:
, "version": "1.2.5"
, "bin" : { "my-program" : "./path/to/program" } }
man
用来给Linux下的man命令查找文档地址,是个单一文件或者文件数组。 如果是单一文件,安装完成后,他就是man + <pkgname>的结果,和此文件名无关,例如:
{ "name" : "foo"
, "version" : "1.2.3"
, "description" : "A packaged foo fooer for fooing foos"
, "main" : "foo.js"
, "man" : "./man/doc.1"
}
通过man foo命令会得到 ./man/doc.1 文件的内容。如果man文件名称不是以模块名称开头的,安装的时候会给加上模块名称前缀。因此,下面这段配置:
{ "name" : "foo"
, "version" : "1.2.3"
, "description" : "A packaged foo fooer for fooing foos"
, "main" : "foo.js"
, "man" : [ "./man/foo.1", "./man/bar.1" ]
会创建一些文件来作为man foo和man foo-bar命令的结果。man文件必须以数字结尾,或者如果被压缩了,以.gz结尾。数字表示文件将被安装到man的哪个部分。
{ "name" : "foo"
, "version" : "1.2.3"
, "description" : "A packaged foo fooer for fooing foos"
, "main" : "foo.js"
, "man" : [ "./man/foo.1", "./man/foo.2" ]
}
会创建 man foo 和 man 2 foo 两条命令。
directories
CommonJs通过directories来制定一些方法来描述模块的结构,看看npm的package.json文件npm's package.json ,会看到有directories标示出doc, lib, and man。
目前这个配置没有任何作用,将来可能会整出一些花样来。
directories.lib
告诉用户模块中lib目录在哪,这个配置目前没有任何作用,但是对使用模块的人来说是一个很有用的信息。
directories.bin
如果你在这里指定了bin目录,这个配置下面的文件会被加入到bin路径下,如果你已经在package.json中配置了bin目录,那么这里的配置将不起任何作用。
directories.man
指定一个目录,目录里边都是man文件,这是一种配置man文件的语法糖。
directories.doc
在这个目录里边放一些markdown文件,可能最终有一天它们会被友好的展现出来(应该是在npm的网站上)
directories.example
放一些示例脚本,或许某一天会有用 - -!
repository
指定你的代码存放的地方。这个对希望贡献的人有帮助。如果git仓库在github上,那么npm docs命令能找到你。
如下:
"repository" :
{ "type" : "git"
, "url" : "https://github.com/npm/npm.git"
}
"repository" :
{ "type" : "svn"
, "url" : "https://v8.googlecode.com/svn/trunk/"
}
URL应该是公开的(即便是只读的)能直接被未经过修改的版本控制程序处理的url。不应该是一个html的项目页面。因为它是给计算机看的。
若你的模块放在GitHub, GitHub gist, Bitbucket, or GitLab的仓库里,npm install的时候可以使用缩写标记来完成:
"repository": "npm/npm"
"repository": "gist:11081aaa281"
"repository": "bitbucket:example/repo"
"repository": "gitlab:another/repo"
scripts
scripts属性是一个对象,里边指定了项目的生命周期个各个环节需要执行的命令。key是生命周期中的事件,value是要执行的命令。
具体的内容有 install start stop 等,详见npm-scripts.
config
用来设置一些项目不怎么变化,跨版本的项目配置,例如port等。用法如下:
{ "name" : "foo"
, "config" : { "port" : "8080" } }
然后有一个start命令引用npm_package_config_port环境变量,用户也可以用如下方式改写:npm config set foo:port
8001
See npm-config and npm-scripts for more on package configs.
dependencies
dependencies属性是一个对象,配置模块依赖的模块列表,key是模块名称,value是版本范围,版本范围是一个字符,可以被一个或多个空格分割。
dependencies也可以被指定为一个git地址或者一个压缩包地址。
不要把测试工具或transpilers写到dependencies中。 对比下面的devDependencies。
下面是一些写法,详见https://docs.npmjs.com/misc/s...
version 精确匹配版本
>version 必须大于某个版本
>=version 大于等于
<version 小于
<=versionversion 小于
~version "约等于",具体规则详见semver文档
^version "兼容版本"具体规则详见semver文档
1.2.x 仅一点二点几的版本
http://... 见下面url作为denpendencies的说明
*任何版本
"" 空字符,和*相同
version1 - version2 相当于 >=version1 <=version2.
range1 || range2 范围1和范围2满足任意一个都行
git... 见下面git url作为denpendencies的说明
user/repo See 见下面GitHub仓库的说明
tag 发布的一个特殊的标签,见npm-tag的文档 https://docs.npmjs.com/gettin...
path/path/path 见下面本地模块的说明
下面的写法都是可行的:
{ "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"
}
}
URLs依赖
在版本范围的地方可以写一个url指向一个压缩包,模块安装的时候会把这个压缩包下载下来安装到模块本地。
Git URLs依赖
git URL可以写成这样:
git://github.com/user/project.git#commit-ish
git+ssh://user@hostname:project.git#commit-ish
git+ssh://user@hostname/project.git#commit-ish
git+http://user@hostname/project/blah.git#commit-ish
git+https://user@hostname/project/blah.git#commit-ish
commit-ish 可以是任意tag,hash,或者可以检出的分支,默认是master分支。
github URLs
支持github的 username/modulename 的写法,#后边可以加后缀写明分支hash或标签,如下:
{
"name": "foo",
"version": "0.0.0",
"dependencies": {
"express": "visionmedia/express",
"mocha": "visionmedia/mocha#4727d357ea"
}
}
本地路径
npm2.0.0版本以上可以提供一个本地路径来安装一个本地的模块,通过npm install xxx --save 来安装,格式如下:
../foo/bar
~/foo/bar
./foo/bar
/foo/bar
package.json 生成的相对路径如下:
{
"name": "baz",
"dependencies": {
"bar": "file:../foo/bar"
}
这种属性在离线开发或者测试需要用npm install的情况,又不想自己搞一个npm server的时候有用,但是发布模块到公共仓库时不应该使用这种属性。
devDependencies
如果别人只想使用你的模块,而不需要开发和测试所需要的依赖的时候,这种情况下,可以将开发测试依赖的包,写到devDependencies中。
这些模块会在npm link或者npm install的时候被安装,也可以像其他npm配置一样被管理,详见npm的config文档。
对于一些跨平台的构建任务,例如把CoffeeScript编译成JavaScript,就可以通过在package.json的script属性里边配置prepublish脚本来完成这个任务,然后需要依赖的coffee-script模块就写在devDependencies属性种。
例如:
{ "name": "ethopia-waza",
"description": "a delightfully fruity coffee varietal",
"version": "1.2.3",
"devDependencies": {
"coffee-script": "~1.6.3"
},
"scripts": {
"prepublish": "coffee -o lib/ -c src/waza.coffee"
},
"main": "lib/waza.js"
}
prepublish脚本会在publishing前运行,这样用户就不用自己去require来编译就能使用。并且在开发模式中(比如本地运行npm install)会运行这个脚本以便更好地测试。
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": "tea-latte",
"version": "1.3.5",
"peerDependencies": {
"tea": "2.x"
}
}
上面这个配置确保再npm install的时候tea-latte会和2.x版本的tea一起安装,而且它们两个的依赖关系是同级的:
├── tea-latte@1.3.5
└── tea@2.2.0
这个配置的目的是让npm知道,如果要使用此插件模块,请确保安装了兼容版本的宿主模块。
bundledDependencies
指定发布的时候会被一起打包的模块。
optionalDependencies
如果一个依赖模块可以被使用, 但你也希望在该模块找不到或无法获取时npm不中断运行,你可以把这个模块依赖放到optionalDependencies配置中。这个配置的写法和dependencies的写法一样,不同的是这里边写的模块安装失败不会导致npm install失败。但是需要自己处理模块缺失的情况,例如:
try {
var foo = require('foo')
var fooVersion = require('foo/package.json').version
} catch (er) {
foo = null
}
if ( notGoodFooVersion(fooVersion) ) {
foo = null
}
// .. then later in your program ..
if (foo) {
foo.doFooThings()
}
optionalDependencies 中的配置会覆盖dependencies中同名的配置,最好只在一个地方写。
engines
你可以指定项目的node的版本:
{ "engines" : { "node" : ">=0.10.3 <0.12" } }
和dependencies一样,如果你不指定版本范围或者指定为*,任何版本的node都可以。也可以指定一些npm版本可以正确的安装你的模块,例如:
{ "engines" : { "npm" : "~1.0.20" } }
记住,除非用户设置engine-strict标记,F否则这个字段只是建议值。
engineStrict
注意:这个属性已经弃用,将在npm 3.0.0 版本干掉。
os
指定你的模块只能在哪个操作系统上跑:
"os" : [ "darwin", "linux" ]
也可以指定黑名单而不是白名单:
"os" : [ "!win32" ]
操作系统是由process.platform来判断的,这个属性允许黑白名单同时存在,虽然没啥必要.
cpu
如果你的代码只能运行在特定的cpu架构下,你可以指定一个:
"cpu" : [ "x64", "ia32" ]
也可以设置黑名单:
"cpu" : [ "!arm", "!mips" ]
cpu架构通过 process.arch 判断
preferGlobal
如果你的模块主要是需要全局安装的命令行程序,就设置它为true,就会提供一个warning,这样来只在局部安装的人会得到这个warning。
它不会真正的防止用户在局部安装,只是防止该模块被错误的使用引起一些问题。
private
如果这个属性被设置为true,npm将不会发布它。
这是为了防止一个私有模块被无意间发布出去。如果你想让模块被发布到一个特定的npm仓库,如一个内部的仓库,可与在下面的publishConfig中配置仓库参数。
publishConfig
这是一个在publish-time时会用到的配置集合。当你想设置tag、registry或access时特别有用,所以你可以确保一个给定的包无法在没有被打上"latest"标记时就被发布到全局公共的registry。
任何配置都可以被覆盖,当然可能只有"tag", "registry"和"access"和发布意图有关。
参考npm-config来查看那些可以被覆盖的配置项列表。
DEFAULT VALUES
npm会根据包的内容设置一些默认值。
"scripts": {"start": "node server.js"}
如果模块根目录下有一个server.js文件,那么npm start会默认运行这个文件。
"scripts":{"preinstall": "node-gyp rebuild"}
如果模块根目录下有binding.gyp, npm将默认用node-gyp来编译preinstall的脚本
"contributors": [...]
若模块根目录下有AUTHORS 文件,则npm会按Name (url)格式解析每一行的数据添加到contributors中,可以用#添加行注释
参考资料