文档翻译自:
描述
npm 支持 package.json 中的 “scripts” 属性, 包括一下 scripts:
- prepublish: 在包 published 之前运行。也会在不带参数的
npm install
命令前运行(查看下面)。 - prepare: 在包 packed 并且 published 之前运行, 也会在本地不带参数的
npm install
执行时运行 (查看下面)。这在prepublish
之后,但是在prepublishOnly
之前运行。 - prepublishOnly: 在包 prepared 和 packed 之前,且仅在
npm publish
上运行(查看下面)。 - prepack: 在 tarball 打包(packed) 前运行(
npm pack
,npm publish
,和当安装 git 依赖项)。 - postpack: 在 tarball 生成(generated),并将其移动到其最终目标地址后运行。
- publish, postpublish: 在包 published 之后运行。
- preinstall: 在包 installed 之前运行。
- install, postinstall: 在包 installed 之后运行。
- preuninstall, uninstall: 在包 uninstalled 之前运行。
- postuninstall: 在包 uninstalled 之后运行。
- preversion: 在包版本改变之前执行。
- version: 在包版本改变之后执行,但在提交之前运行。
- postversion: 在包版本改变之后执行,但在提交之后运行。
- pretest, test, posttest: 伴随
npm test
命令运行。 - prestop, stop, poststop: 伴随
npm stop
命令运行。 - prestart, start, poststart: 伴随
npm start
命令运行。 - prerestart, restart, postrestart: 伴随
npm restart
命令运行。注意:如果没有提供restart
脚本,npm restart
将运行停止和启动脚本。 - preshrinkwrap, shrinkwrap, postshrinkwrap: 伴随
npm shrinkwrap
命令运行。
另外,所有的 scripts 都可以用 npm run-script <stage>
? 命令运行, 以 pre 和 post 为前缀对应名称的命令会自动运行(例如 premyscript
, myscript
,postmyscript
),依赖包中的 scripts 可以用 npm explore <pkg> -- npm run <stage>
来运行。
prepublish 和 prepare
废弃公告:
自 [email protected]
开始,npm CLI 会在 npm publish
和 npm install
之前执行 prepublish
脚本,因为这做法便于准备 package 环境(一些常见的用例在下面描述)。但事实证明这让人非常困惑。所以在 [email protected]
后,新增来一种事件 prepare
来代替上述行为。另外一种 新 事件 prepublishOnly
作为过度策略,让用户避免以往 npm 版本的混乱行为,且仅在 npm publish
上执行(例如,publish 前最后执行一次测试,以确保无误)。
对于这个变化,更加详细的理由请查阅 <https://github.com/npm/npm/issues/10074> 。
用例
如果你需要在使用 package 之前执行某些操作,请使用 prepublish
脚本,这种方式不依赖于目标系统的比赛或架构,这包括以下任务:
- 把 coffeescript 源码编译成 JavaScript
- 压缩 JavaScript 源码
- 获取你的 package 所需的远程资源
在publish时做这些事情的好处是,它们可以在同一处完成,从而降低复杂性和差异性。另外,这意味着:
- 你可以依赖于
coffee-script
作为devDependency
,但你的用户不需要安装它。 - 你不需要在包中包含 minifiers ,以节省包大小。
- 你的用户的机器上不需要具有
curl
或wget
或其他系统工具。
默认值
npm 将根据 package 的内容默认一些 script 值。
"start": "node server.js"
: 如果你的 package 根目录中有server.js
文件,那么 npm 会将默认start
命令为node server.js
。-
"install": "node-gyp rebuild"
: 如果你的 package 根目录下中有binding.gyp
,并且没定义install
或preinstall
脚本,npm 会默认install
命令用 node-gyp 编译。?
user 用户
如果使用 root 权限调用 npm ,那么它会将 uid 更改为 user
配置指定的 uid ,默认为 nobody
。设置 unsafe-perm
以使用 root 权限运行脚本。
环境
包脚本(package scripts)在一个环境中运行,在这个环境中可以获得许多关于 npm 的设置和进程的当前状态的信息。
path 路径
如果你依赖的模块定义了可执行 scripts ,如测试套件,那么这些可执行 scripts 将被添加到 PATH
中执行。所以,如果你的 package.json 有这样的依赖:
{ "name": "foo", "dependencies": { "bar": "0.1.x" }, "scripts": { "start": "bar ./test" } }
然后在你运行 npm start
执行 bar
script,会导进 node_modules/.bin
目录中,在你运行 npm install
时,他会被导入到 node_modules/.bin
目录。
package.json vars 变量
package.json 的属性名会拼接上 npm_package_
前缀。例如,你的 package.json 文件中有 {"name":"foo", "version":"1.2.5"}
,那么你的包脚本(package scripts)会将 npm_package_name
环境变量设置为 “foo” ,而 npm_package_version
设置为 “1.2.5” 。
configuration 配置
使用 npm_config_
前缀将配置参数放在环境中。例如,你可以通过检查 npm_config_root
环境变量来查看当前生效的 root
配置。
特殊情况: package.json 中的 “config” 对象
如果存在 <name>[@<version>]:<key>
的配置参数,则 package.json 中的 “config” 键将在环境中被覆盖。例如,如果 package.json 是这样的:
{ "name": "foo", "config": {"port": "8080"}, "scripts": {"start": "node server.js"} }
并且 server.js 是这样的:
http.createServer(...).listen(process.env.npm_package_config_port)
然后用户可以这样修改行为:
npm config set foo:port 80
当前的生命周期事件
最后,将npm_lifecycle_event环境变量设置为执行循环的哪个阶段。
因此,您可以使用一个单独的 script,用于根据当前正在进行的切换的不同部分。
最后,npm_lifecycle_event
环境变量是用来设置当前执行循环的哪个阶段。所以,你可以使用单个单独的 script ,根据当前正在进行的事件来切换的进程的不同部分。
对象按照这种格式变平,所以如果你的 package.json 中有 {"scripts":{"install":"foo.js"}}
,那么你会在 script 中看到这个:
process.env.npm_package_scripts_install === "foo.js"
例子
假如,你的 package.json 有如下设置:
{ "scripts" : { "install" : "scripts/install.js" , "postinstall" : "scripts/install.js" , "uninstall" : "scripts/uninstall.js" } }
那么在生命周期的 install
和 postinstall
阶段将调用 scripts/install.js
,在 uninstall
阶段将会调用 scripts/uninstall.js
。由于 scripts/install.js
在两个不同的阶段都有运行,因此在这种情况下,查看 npm_lifecycle_event
变量是聪明的做法。
如果你想要运行 make
命令也没问题,这样写:
{ "scripts" : { "preinstall" : "./configure" , "install" : "make && make install" , "test" : "make test" } }
EXITING 退出
npm 脚本是通过将该行作为脚本参数传给 sh
来运行的。
如果脚本不是以退出码 0
退出,则会中止该进程。
请注意,这些脚本文件不必是 nodejs 甚至是 javascript 程序。他们只需要一些可执行文件。
HOOK SCRIPTS
如果要为所有 package 在某生命周期事件中运行某脚本,则可以使用钩子脚本。
在 node_modules/.hooks/{eventname}
中放置一个可执行文件,所有装在根目录下的 package 在运行到该生命周期节点时都会执行。
Hook 脚本的运行方式与 package.json 里的脚本完全相同。也就是说,它们与上述 env 在一个单独的子进程中。
最佳实践
- 不要以
0
以外的错误码退出,除非你 真的 想这样做。因为这将导致 npm 操作失败,并可能会回滚。如果这个错误无关紧要或只会阻断一些小功能,那么最好只是输出一个警告,让线程成功退出。 - 尽量不要使用 npm 脚本来做 npm 本身就可以做的事情。通读
package.json(5)
文件,你可以学到所有通过简单、合适的配置来具体描述你的 package 。这通常更健壮和通用。 - 通过检查env来决定把东西装在哪。例如,如果
npm_config_binroot
环境变量设置为/home/user/bin
,那么不要尝试将可执行文件安装到/usr/local/bin
中。用户可能因为某种原因设置了这种方式。 - 不要在脚本命令里加 “sudo” 前缀。如果由于某些原因需要 root 权限,否则会报错;那么用户应该考虑以 sudo 运行 npm 命令。
- 不要使用
install
脚本。使用.gyp
文件进行编译,其他情况则使用prepublish
。你最好永远不要自定义 preinstall 或 install 脚本。如果你要这样做,请优先考虑是否有其他办法。install
或preinstall
脚本的唯一正确使用场景是用作设置那些编译的目标目录。
学习了