Angular7 Npm Package.Json文件详解
近期时间比较充裕,正好想了解下Angular Project相关内容。于是将Npm官网上关于Package.json的官方说明文档进行了一下翻译学习,仅供参考
原文出处: https://docs.npmjs.com/files/package.json
官方传送门
npm-package.json 特性说明
描述
本文介绍了package.json文件中,你需要了解的所有内容。Package.json文件必须是一个真正的Json格式文件,而不能是一个通俗上理解的JavaScript对象。
本文中讲到的很多操作指令来源于npm-config中的配置节点。
name
如果你想要发布npm包,最重要的是包中package.json文件中必须包含的name和version属性。name和verion组合在一起,标识了这个包的唯一性。包中任何的改变都应该同步进行版本(version)的变更,如果你不想把你的包发布到公共环境中去,name和version属性就变成了可选项。
name就是这个包被叫做的名字。命名需要按照这些规范:
- name必须少于等于214个字符,这214个字符包含了这个包的域名的全部字符。
- name不能以点(".") 和下划线("_")开头
- 新包的名称中不能包含大写字母
- 包的名称最终会成为URL的一部分、一个命令行的参数或者一个文件夹得名称,因此,name不能包含任何非URL安全的字符。
小建议
- 对于核心的node模块不要使用相同的名字
- 名字中不要包含“js”或者“node”字符。以js举例,假设你正在写一个package.json文件,你用“engines”描述“引擎”属性.(详细请往下看)
- 名称有可能会被当做一个参数传递给require(),所以他应该尽量短,并且能够合理的描述。
- 在你确定好名字之前。你可以通过npm reqistry看一下是否已经存在相同名称的包,https://www.npmjs.com/
名称可能会包含一个前缀,比如@myorg/mypackage,更多scope信息可以查看npm-scope 章节
version
如果想要发布npm包,最重要的是包中package.json文件中必须包含的name和version属性。name和verion组合在一起,标识了这个包的唯一性。包中任何的改变都应该同步进行版本(version)的变更,如果你不想把你的包发布到公共环境中去,name和version属性就变成了可选项。
Version必须能够被node-semver解析,node-semvery作为一个以来依附于npm(可以通过 npm install semver安装使用)
版本数值和范围相关的更多内容可以查看semver
description
package.json中包含description属性,他是一个字符串类型,由于npm的搜索会查找这个属性,所以,这个属性能够让其他人更好的找到您发布的包。
keywords
package.json中包含keywords属性。他是一个字符串数组,由于npm的搜索会查找这个属性,所以,这个属性能够让其他人更好的找到您发布的包。
homepage
这个url地址能够链接项目的主页上,例如:
"homepage": "https://github.com/owner/project#readme"
bugs
这个url地址用于提交问题,他也可以是一个邮箱地址。对在使用你的包的过程中遇到bug的任非常有用。看起来应该是这样的:
{ "url" : "https://github.com/owner/project/issues"
, "email" : "project@hostname.com"
}
你可以指定一个或两个地址,如果你只希望提供提一个url地址那可以将bugs的值设置为一个简单的字符串而不是一个对象。
如果提供了一个url他将会被npm bugs命令所使用。
license
你应该为你的包指定一个版权声明,这样别人就会知道是谁授权使用这个包,同时,他们也能够看到使用这个包的一些限制条件。
如果你正在使用一个像BSD-2-Clause或者MIT之类的通用授权,可以像这样,添加一个SPDX授权标识:
{ "license" : "BSD-3-Clause" }
你可以通过SPDX license查看SPDX授权的id列表,当然,你应该选择接近OSI标准的授权。
如果你的包拥有多个通用的授权,可以使用一个SPDX 2.0版本的授权表达式,就像这样:
{ "license" : "(ISC OR GPL-3.0)" }
如果你正在使用一个没有被SPDX认证过的授权,或者你正在使用一个专用的授权码,可以将信息配置成如下的值:
{ "license" : "SEE LICENSE IN <filename>" }
然后在包的最顶端添加一个名称为的文件。
一些旧的包使用授权许可对象或者一个包含授权对象数组的“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来防止意外发布出去。
people fields:author,contributors
author是一个人,contributors是一个包含多个人的数组。persion是一个包含名称属性,并且url和email可选的得对象。如下所示:
{ "name" : "Barney Rubble"
, "email" : "b@rubble.com"
, "url" : "http://barnyrubble.tumblr.com/"
}
或者你也可以把内容简写到一个字符串中,npm可以将它解析出来:
"Barney Rubble <b@rubble.com> (http://barnyrubble.tumblr.com/)"
email和url都是可选的。
npm也可以设置一个*的"maintainers"属性到用户信息中。
files
files属性是一个文件模板的数组,他描述了包被当做依赖安装时所要包含的文件。文件模板语法类似.gitignore,但是与git相反,它表示包含了文件、目录、或者全局属性( *、**/*等),打包完成后,文件会被放到tarball中,省略该属性将会按照默认值["*"]来处理,默认处理会包含所有的文件。
一些特殊的文件和目录也可以被包含或者排除,无论他们是否在files数组中(继续往下看)
你也可以提供一个.npmignore 文件在包的根目录上或者子目录上。以防止文件被包含到里面。在你文件的根目录上他将会重写files属性。但是子目录上.npmignore文件工作起来像是gitignore。如果有一个gitignore文件并且npmignore丢失了,gitignore的内容将会起作用。
包含"package.json#files"属性的文件不能通过npmignore或者gitignore排除。
以下文件经常被包含,忽略配置的话:
- packge.json
- README
- CHANGES / CHANGELOG / HISTORY
- LICENSE / LICENCE
- NOTICE
- the file in the main field
README,CHANGES,LICENSE &NOTICE也可以有其他的类型或者扩展。
相应的,以下文件也经常被忽略。 - .git
- CVS
- .svn
- .hg
- .lock-wscript
- .wafpickle-N
- .*.swp
- .DS_Store
- ._*
- npm-debug.log
- .npmrc
- node_modules
- config.gypi
- *.orig
- package-lock.json(可以用shrinkwrap替代)
main
main属性是一个模块id,也是程序的唯一入口。换句话说,如果你的包名叫foo,用户安装了他,然后用户就可以通过使用require(
"foo")将main模块中export的内容导入进去。
这个模块id应该是与包所在的文件夹根目录的相对路径。
对大部分模块来将,添加一个main脚本是有意义的,通常他并不会包含太多内容。
browser
如果模块是在客户端使用,你应该使用browser字段而不是main字段。这对暗示用户,模块依赖的一些node.js中无法获取的,像window一样的浏览器基础对象,是非常有用的。
bin
许多的包至少有一个可执行文件需要被安装到 Path目录中。npm让这变得非常简单。(事实上,正是通过这个特性来安装npm的可执行文件)
为了达到目标,package.json中提供了一个bin属性,他在命令和本地文件名之间建立了一个映射。全局(global)安装时,npm会将文件路径写入到prefix/bin下面,对于本地安装,npm会建立./node_modules/.bin/ 和文件路径的映射。
例如,myapp应当包含下面内容:
{ "bin" : { "myapp" : "./cli.js" } }
所以,当你安装myapp时,这将会创建一个从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的可执行文件。
man
指定单一文件或者多个文件名来让man程序使用。
如果只提供了一个单一文件,那么,忽略掉他实际的文件名,他安装后就是man 的结果。例如:
{ "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文件了。
如果文件名不是以包名开头的。那么他会被添加上前缀:
{ "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和man2 foo 两个文件。
directories
CommonJs的包描述了你能够通过directories查看到包结构的几种方法。如果你查看他的package.json文件。你会看到里面有directiories标识的doc、lib、和man。
未来,这条信息可能会其他创造性的方法所用到。
directories.lib
他告诉别人你这些库的位置,这个库的文件夹并没有其他的什么特殊用处,但是他是一个非常有用的元数据信息。
directories.bin
如果你指定了directories.bin中的一个bin文件夹。文件夹中的所有文件都会被添加进来。
由于bin指令的工作方式。他会指定一个bin路径,同时会将配置的directiores.bin配置设置为无效,如果你想要指定个人的文件,可以使用bin,并且对于所有bin下面已经存在的文件,可以使用directories.bin。
directories.man
他是一个存放man页的文件夹,通过移动文件夹可以生成一个man数组。
directories.doc
存放markdown文件,最终他会很好的显示出来。
directories.exaple
存放demo脚本的地方,以后的某一天它可能会以一种巧妙的方式暴露出来。
directories.test
存放测试文件的地方,当前他并没有暴露出来,但是未来可能会暴露出来。
repository
指定的存放代码的地方,这对想要完善代码得人是非常有用的,如果他是在github上的git仓库,那么npm docs 命令可以找到他。
就像这样:
"repository": {
"type" : "git",
"url" : "https://github.com/npm/cli.git"
}
"repository": {
"type" : "svn",
"url" : "https://v8.googlecode.com/svn/trunk/"
}
URL应该是个公开可访问的地址,他能够被VCS程序直接访问,而不用做任何修改,他不应该是一个浏览区输入的html页面地址。他是给计算机用的。
对GitHub、GitHub gist、Bitbucket或者GitLab仓库你可以使用相同的缩写形式:
"repository": "npm/npm"
"repository": "github:user/repo"
"repository": "gist:11081aaa281"
"repository": "bitbucket:user/repo"
"repository": "gitlab:user/repo"
scripts
scripts 属性是一个包含包运行时生命周期各个环节需要执行的脚本命令,key就是生命周期时间,value是运行时节点执行的命令。
可以查看npm-scripts查看更所script命令。
config
config对象用于在升级过程中配置包中脚本的配置参数。例如,如果一个包包含以下内容:
{ "name" : "foo"
, "config" : { "port" : "8080" } }
同时有一个start命令,引用了npm_package_config_port环境变量。name用户可以通过npm config set foo:port 8001来重写他。
可以查看npm-config和npm-script查看更多信息。
dependencies
Dependencies指定了一个报名和版本范围的简单对象。版本范围是一个包含一个或多个分隔符的字符串。Dependencies也可以使用tar包或者git Url标记。
请不要在Dependencies中配置测试或者过度内容,devDependencies可以查看下面。
通过semver查看更多指定的版本范围.
- version 必须完全匹配版本号
version 必须大于这个版本号
=version 必须大于等于
- <version
- <=version
- `version 与版本今夕向东 详细查看semver
- ^version 与版本兼容 详细查看semver
- 1.2.x 1.2.0,1.2.1等等,但不能是1.3.0
- http://... 详细查看下面的'URL as Dependencies'
- * 可以与任何版本匹配
- "" (就像是空字符串)与*相同
- version1-version2 与 >=version1 <=version2相同
- range1 || range2 满足range1或者range2中的任何一个都认为是通过,
- git... 查看下面的Git URLs as Dependencies
- user/repo 查看下面的GitHub URLs
- tag 一个特殊的版本,被当做标记进行标记或者发布。查看npm-dist-tag
- path/path/path 查看Local Paths
示例,以下所有都是可用的。
{ "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 as Dependencies
你可以制定一个tarball url 代替一个版本的范围
Git URLs as Dependencies
git url的格式如下
<protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]
是git、git+ssh、git+http,git+https或者git+file中的一个
他可以用于准确的克隆一个commit,如果commit-ish按照如下格式:#semver:,可以是任何可用的semver范围或者准确的版本,并且npm会查找远程仓库中任何匹配的标记或者引用。他们大部分都应该是注册的依赖。指定#或者#semver:时,默认使用master分支。
示例:
git+ssh://git@github.com:npm/cli.git#v1.0.27
git+ssh://git@github.com:npm/cli#semver:^5.0
git+https://isaacs@github.com/npm/cli.git
git://github.com/npm/cli.git#v1.0.27
GitHub URLs
1.1.65版本之后,你可以像"foo":"user/foo-project"这样引用GitHub Urls。使用git urls的时候需要添加commit-ish后缀,例如:
{
"name": "foo",
"version": "0.0.0",
"dependencies": {
"express": "expressjs/express",
"mocha": "mochajs/mocha#4727d357ea",
"module": "user/repo#feature\/branch"
}
}
Local Paths
2.0.0版本以后你可以给包含包的本地文件夹制定一个路径。Local paths可以通过npm install -S或者npm install --save指令来保存。可以使用以下格式:
../foo/bar
~/foo/bar
./foo/bar
/foo/bar
他们会被转换成一个相对地址并添加到package.json文件中。例如:
{
"name": "baz",
"dependencies": {
"bar": "file:../foo/bar"
}
}
这个特性对本地离线的开发和创建那些不需要访问外部服务器进行npm安装的测试文件是非常有用的。 #### DevDependencies
如果有人要下载并使用你发布的模块。但是他们可能并不想或者并不需要下载编译你使用的外部测试程序或者框架文档。
这种情况下,最好将这些附加项放到devDependencies这个对象中。
这些包将会在根目录下执行npm link或者npm install的时候安装,并且可以像其他npm配置参数一样管理使用,可以查看npm-config查看详细信息。
对于编译打包环节并没有指定特定的平台,比如编译CoffeeScript或者其他类似JavaScript的语言。可以使用prepare脚本来编译,并且把他们依赖的包放到devdependency中。
示例:
{ "name": "ethopia-waza",
"description": "a delightfully fruity coffee varietal",
"version": "1.2.3",
"devDependencies": {
"coffee-script": "~1.6.3"
},
"scripts": {
"prepare": "coffee -o lib/ -c src/waza.coffee"
},
"main": "lib/waza.js"
}
preapare脚本会在publishing之前执行,所以,用户可以不通过require就可以编译他们,在开发模式下(比如本地执行的npm install),也会执行这个脚本,所以你可以很轻松的测试他。
peerDependencies
在某些场景下,你需要通过工具或者库表示你的包的兼容性,但是并不想在通过require引用他,这通常指的是plugin,需要注意的是,你的模块需要暴露一个特定的接口,规范,并在文档中描述制定。
例如:
{
"name": "tea-latte",
"version": "1.3.5",
"peerDependencies": {
"tea": "2.x"
}
}
这可以确保包tea-latte与tea模块的次版本(X)的包一起安装.npm install tea-latte会按照如下依赖关系图生成
├── tea-latte@1.3.5
└── tea@2.2.0
建议:npm1.0版本和2.0版本会自动安装peerDependencies,他们不会依赖更高版本的依赖书,在npm 3.X版本中对此作了修改,当peerdependency没有安装的时候,你会收到一个警告提示。 1.x和2.X版本的操作经常混淆,并且很容易会版带入依赖地狱(dependncy hell),现在npm需要尽可能的避免他。
安装带有冲突的以来的其他插件会报错,所以,请确保你的插件依赖尽可能的全面,并且不要指定特定的版本号。
假如通过semver进行编译,只改变package.json的主版本号会影响你的插件。因此,如果你有1.x的版本使用"^1.0"或者"1.x",如果你依赖1.5.2提供的特性,可以使用">=1.5.2 <2".
bundkedDependencies
他定义了一个发布包时会被捆绑发布的包名的数组,
如果需要在本地保留npm包或通过单个文件下载使其可用,通过在bundledDependencies数组中指定包名称并执行npm pack,可以将包打包到tarball文件中。
例如:定义了如下的package.json
{
"name": "awesome-web-framework",
"version": "1.0.0",
"bundledDependencies": [
"renderized", "super-streams"
]
}
我们能够通过npm pack获取awesome-web-framework-1.0.0.tgz文件。这个文件包含了依赖renderized和super-streams两个包,这两个包可以在一个新工程中通过npm install awesome-web-framework-1.0.0.tgz.安装
optionalDependencies§
如果可以使用依赖项,同时在找不到或者安装失败时希望继续,那么你可以把它放到optionalDependencies配置对象中,他是一个程序包名称和版本或者URL的字典,就像dependencies对象一样,不同的是,编译失败后不会引起安装失败。
处理依赖的缺失仍然是程序的主要职责,就像这样:
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" } }
除非用户已经设置了engine-strict配置标签,否则,这个属性只是一个建议值,并且它只会在你的包安装依赖的时候产生警告信息。
engineStrict
这个特性在npm3.0版本中被删除
OS
你可以指定你的模块运行在那个操作系统中:
"os" : [ "darwin", "linux" ]
你也可以通过添加字符‘!’列出一个黑名单系统
"os" : [ "!win32" ]
主机的操作系统有process.plateform决定
这里可以使用黑名单,也可以使用白名单,尽管并没有什么很好的原因解释他。
cpu
如果你的代码只能够在特定的cpu架构下执行,你也可以指定他:
"cpu" : [ "x64", "ia32" ]
和操作系统一样,你也可以使用黑名单
"cpu" : [ "!arm", "!mips" ]
主机的架构有process.arch决定。
preferGlobal
反方
这个选项用于触发一个npm警告,但是他已经不再能发出警告,他现在只是单纯的用于提示的信息,现在建议将二进制文件当做本地的开发依赖项(devDependencies)来处理。
private
如果package.json中设置了"private":true,那么npm将会拒绝发布他,这是一种防止意外发布的方法,如果你想将一个特定的包发送到一个特定的位置(例如:内部注册国的位置),在发布时使用publishConfig 字典来重写registry配置参数。
publishConfig
这是在发布时使用的一系列的配置值,当你想要设置tag,registry或者access的时候特别方便,以至于你可以确定一个包是否有"latst"标记,是否被默认发布到了公共的注册地址。
任何配置值都可以被重写,当然除了tag,registry和access,这可能是因为他们和发布的意图有关。
查看更多细节npm-config.
DEFAULT VALUES
npm创建package是会默认带上一些配置信息:
- "script":{"start":"node server.js"}
如果在package的根目录有一个server.js文件。那么npm会默认添加指向node server.js的start命令 - "scripts":{"install":"node-gyp rebuild"}
如果根目录下存在binding.gyp文件,并且没有定义install或者preinstall 脚本,npm会默认添加intall命令来用node-gyp执行编译。 - "contributors":[]
如果根目录下有AUTHORS文件,npm
会将每行按照Name (url)格式来解析,email或者url是可选的。以#或者空格开头的行将会被忽略。