npm中package.json

443 阅读11分钟

package.json文件是项目模块的描述文件。

name

name和version两个属性形成了一个npm模块的唯一标识符。这个两个属性是必须要有的,否则模块无法被安装。
name属性就是项目模块的名称,命名规则为:

  • 必须小于等于214个字节
  • 不能以"_"或"."开头
  • 不能含有大写字母
  • 不能含有url非法字符,因为那么会成为url的一部分

官网文档的建议

  • 不要使用和node核心模块一样的名称
  • 不要含有'js'和'node'
  • 最好取一个简短且语义化的值,因为name属性也许会被写在require()参数中
  • 创建一个模块前可以先到 www.npmjs.com/ 查看name是否已经被占用

version

version是项目模块的版本号,version必须可以被npm依赖的一个node-semver模块解析。
升级版本应该遵循以下标准:

  1. 补丁版本:解决了Bug或者一些较小的更改,增加最后一位数字
  2. 小版本:增加了新特性,同时不会影响之前的版本,增加中间一位数字
  3. 大版本:大改版,无法兼容之前的,增加第一位数字

description

项目模块的描述,是一个字符串,方便别人了解你的模块作用,便于搜索

keywords

项目模块的关键字,是一个字符串数组,便于搜索

homepage

项目主页的url
注意:这和'url'不一样,registry会认为url是一个跳转到发布在其他地方的地址,获取模块的时候不会从npm官方仓库获取,而是会重定向到url属性配置的地址

bugs

该项目的issue跟踪页面或者报告issue的email地址 格式是

{
    url:"",
    email:""
}

如果只想提供一个url,可以对bugs字段指定一个字符串而不是Object

license

为项目指定一个协议,让用户知道他们有何权限来使用项目,以及使用该项目有什么限制。
可以在 spdx.org/licenses/ 查阅协议列表

author、contributors、person

author是指一个人,contributors是指一些人(数组形式),person是一个对象,拥有必须的name字段和可选的url和email字段。例如:

{
    name:"",
    email:"",
    url:""
}

也可以使用单个字符串的精简形式,npm会帮忙进行解析

name <email> (url)

npm会使用提供的npm用户信息来设置一个顶级的'maintainers'维护者字段

files

'files'字段是一个被项目包含的文件名数组,可以为文件名或者问文件夹名,如果为文件夹名,则这个文件夹中的所有文件都会被包含进项目中(除非是那些在其他规则中被忽略的文件)。

还可以在包的根目录或者子目录下提供一个'.npmignore'文件来忽略项目包含文件,即使这些文件被包含在files字段中。.npmignore文件和.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')来使用这个模块,那么require返回的内容就是main属性指定的文件中module.exports指向的对象。
它应该指向模块根目录下的一个文件。这个属性更多的是让模块有一个主入口文件

bin

bin字段是模块用来配置到PATH路径下的可执行模块,(其实npm本身也是通过bin属性安装为一个可执行命令的)。bin属性是一个已命令名称为key,本地文件名称为value的map。格式如下

{bin:{key:value}}

模块安装的时候,如果是全局安装,则npm会为bin中配置的文件在bin目录下创建一个软连接(对于Windows系统,默认会在C:\Users\username\AppData\Roaming\npm目录下),若是局部安装,则会在项目内的./node_modules/.bin/目录下创建一个软连接。如果模块只有一个可执行文件,并且命令名称和模块名称一样,上面的格式可以用字符串来代替。例如:

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

等同于

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

man

指定一个或通过数组指定一些文件来让linux下的man命令查找文档地址
如果只有一个文件被指定的话,安装后可以直接使用man+模块名称,而不管man指定的文件的实际名称。

{
    name:"foo",
    version:"1.0.0",
    description:"描述",
    main:"foo.js",
    man:'./man/doc.1'
}

上述配置中通过man foo 命令可以使用./man/doc.1文件

如果man文件名称不是以模块名称开头的,安装的时候会给加上模块名称前缀。因此,下面这段配置:

{
    name:"foo",
    version:"1.0.0",
    description:"描述",
    main:"foo.js",
    man:["./man/foo.1","./man/bar.1"]
}

需要使用man foo 和man foo-bar来执行对应的文件 man文件必须以一个数字结尾,和一个可选的.gz后缀(当文件被压缩时)。数字用来说明这个文件被安装到了哪个节中
如果man中的两个项目的文件名除数字外全部相同,则需要通过数字进行区分

{
    name:"foo",
    version:"",
    man:['./man/foo.1','./man/foo.2']
}

会创建man foo 和man 2 foo两条命令

directories

CommonJS Packages规范说明了几种可以用directories对象来标示包结构的方法。npm的package.json标示出了doc、lib和man。在未来,这个信息可能会被用到

{
    lib:"",//标示库文件夹的位置,目前没有地方需要用到lib文件夹,但是这是重要的元信息
    bin:"",//如果在directories.bin中指定一个bin目录,在这个目录中所有文件都会被当作在bin来使用。由于bin指令的工作方式,同时指定一个bin路径和设置directories.bin将是一个错误。如果想指定独立的文件,使用bin,如果想执行某个文件夹里的所有文件,使用directories.bin
    man:"",//指定的文件夹里都是man文件,系统通过遍历这个文件夹来生成一个man的数组
    doc:"",//放置markdown文件,暂时无用
    example:"",//放置示例脚本,暂时无用
}

repository

指明代码被托管在何处,如果git仓库在github上,可以用npm docs找到。格式如下:

{
    repository:{
        type:"git",
        url:""
    }
}

url应该是公开且可用的。对于GitHub,github gist bitbucket或gitlab的仓库,可以使用缩写

{
    "repository": "npm/npm"
    "repository": "gist:11081aaa281"
    "repository": "bitbucket:example/repo"
    "repository": "gitlab:another/repo"
}

script

scripts字段是一个由脚本命令组成的字典,这些命令运行在包的各个周期中。这里的键是生命周期事件名,值是要运行的命令。可以从npm-script中获取多详细的信息

原理

npm中脚本的原理是npm run ,就会自动新建一个shell,在这个Shell里面执行指定的脚本命令。因此,只要是Shell(一般是Bash)可以运行的命令,就可以写在npm脚本(script)里边。

注意:npm run 新建的这个Shell,会将当前目录的node_modules/.bin子目录加入PATH变量,执行结束后,再将PATH变量恢复原样。这意味着,当前目录的node_modules/.bin子目录里面的所有脚本,都可以直接用脚本名调用,而不必加上路径。比如,当前项目的依赖里面有Mocha,只要直接写mocha test就可以了。

"test":"mocha test"

而不用写成下面这样

'test':"./node_modules/.bin.mocha test"

由于npm脚本的唯一要求就是可以在Shell执行,因此它不一定是Node脚本,任何可执行文件都可以写在里面。 npm脚本的退出码也遵守Shell脚本规则。如果退出码不是0,npm就会认为这个脚本执行失败。

通配符

由于npm脚本就是Shell脚本,因此也可以使用Shell通配符。通配符中*表示任意文件名,**表示任意一层子目录。如果要将通配符传入原始命令,防止被Shell转义,需要将*使用\*进行转义

传参

向npm脚本传入参数,要使用--表明 可以在npm run的时候传入参数,也可以在package.json里封装命令中设置好参数

执行顺序

如果npm脚本里面需要执行多个任务,那么需要明确它们的执行顺序。
如果是并行执行(即同时的平行执行),可以使用&符号。
如果是继发执行(即只有前一个任务成功,才执行下一个任务),可以使用&&符号。 这两个符号是Bash的功能。此外,还可以使用node的任务管理模块:script-runner、npm-run-all、redrun

默认值

一般来说,npm脚本有用户提供。但是,npm对两个脚本提供了默认值。也就是说,这两个脚本不用定义,就可以直接使用(前提项目根目录中存在这两个文件)

'start':"node server.js"
'install':'node-gyp rebuild'

钩子

npm脚本中有pre和post两个钩子。例如:build脚本命令的钩子就是prebuild和postbuild。
用户在执行npm run build 的时候,会自动按照下面的顺序执行。 npm run prebuild && npm run build && npm run postbuild

npm 默认提供下面这些钩子

1.prepubilsh postpublish
2.preinstall postinstall
3.preuninstall postuninstall 
4.preversion postversion
5.pretest posttest 
6.prestop poststop 
7.prestart poststart 
8.prerestart poststart

自定义的脚本命令也可以加上pre和post钩子。但是双重的pre和post无效

npm提供了一个npm_lifecycle_event变量,返回当前正在运行的脚本名称,所以可以利用这个变量,在同一个脚本文件里面,为不同的npm scripts命令编写代码

注意,4.0以下的npm中prepublish这个钩子不仅会在npm publish命令之前执行,还会在npm install(不带任何参数)命令之前执行。所以npm 4 引入了一个新的钩子prepare,行为等同于prepublish,而从npm 5 开始 prepublish将只在npm publish命令之前执行

简写形式

1.npm start === npm run start 
2.npm stop === npm run stop 
3.npm test === npm run test 
4.npm restart === npm run stop && npm run restart && npm run start 

npm restart 是一个复合命令,实际上会执行三个脚本命令:stop、restart、start。具体的执行顺序如下:

1.prerestart 
2.prestop
3.stop 
4.poststop
5.restart 
6.prestart 
7.start
8.poststart
9.postrestart

变量

npm脚本可以通过npm_package_前缀获得packgae.json里面的字段。例如

{
    name:"foo",
    version:"1.2.5"
}

可以通过环境变量process.env对象,process.env.npm_package_version获得package.json中的version字段

config

config字段是一个对象,可以用来配置包脚本中的跨版本参数

dependencies

dependencies字段是一个对象,指定了依赖的包名和其版本范围的映射。版本范围是个有一个或多个空白分隔符的字符串。dependencies字段还可以用tarball或者git URL

指定版本范围的格式如下:

1.version 必须确切匹配version
2.\>version 必须大于version
3.\>=version 必须大于等于version
4.< version 必须小于等于version
5.<=version 必须小于等于version
6.~version '约等于'
7.^version 和version兼容
8. 1.2.x 限制到中版本
9.http://... 用url作为依赖项
10.\* 匹配任何版本
11. ""(空字符串)匹配任何版本,和\*一样
12.version1-version2 === version1<= <=version2
13.version1||version2 二选其一
14.git... 用git URL作为依赖项
15.user/repo
16.tag 一个以tag发布的指定版本
17.path 本地路径

devDependecies

用来存储开发过程中所使用的依赖包

peerDependencies

说明模块只能作为插件跑在宿主的某个版本范围下

bundledDependencies

指定发布的时候会被一起打包的模块

optionalDependencies

如果一个依赖模块可以被使用,但是同时又不希望在该模块找不到或无法获取时npm继续运行,可以把这个模块依赖放到optionalDepencies配置中。这个配置的写法和dependencies的写法一样,不同的是这里边写的模块安装失败不会导致npm install 失败。

注意:这种模块需要自己带代码中处理模块是否可以使用的情况。同时optionalDependencies中的配置会覆盖dependencies中的配置

engines

用于指定项目运行的node版本范围。和dependencies一样,如果不指定版本范围或者指定为*,任何版本的node都可以

注意:只有设置engine-strict属性,engines属性才执行

os

指定模块的操作系统

cpu

指定模块的CPU架构

preferGlobal

如果软件包主要用于安装到全局的命令行应用程序,该值设置成true时,如果软件包被安装到本地时,会提供一个警告。但是实际上并没有阻止用户把模块安装到本地,只是防止该模块被错误的使用引起一些问题

private

设置为true时,npm将拒绝发布。这是为了防止一个私有模块被无意间发布出去

publishConfig

用来设置模块在发布时用到的一些值,如果不想模块被默认标记为最新的,或者默认发布到公共仓库,可以在这里配置tag或仓库地址

DEFAULT VALUES

用来设置一些默认参数