脚本

npm 如何处理 "scripts" 字段

描述

你的 package.json 文件的 "scripts" 属性支持许多内置脚本及其预设的生命周期事件以及任意脚本。 这些都可以通过运行 npm run-script <stage> 或简称 npm run <stage> 来执行。 具有匹配名称的前置和后置命令也将为这些运行(例如 premyscriptmyscriptpostmyscript)。 来自依赖的脚本可以使用 npm explore <pkg> -- npm run <stage> 运行。

前后脚本

要为 package.json"scripts" 部分中定义的任何脚本创建 "pre" 或 "post" 脚本,只需创建另一个具有匹配名称的脚本并将 "pre" 或 "post" 添加到它们的开头。

{
"scripts": {
"precompress": "{{ executes BEFORE the `compress` script }}",
"compress": "{{ run command to compress files }}",
"postcompress": "{{ executes AFTER `compress` script }}"
}
}

生命周期脚本

有一些特殊的生命周期脚本只在某些情况下发生。 这些脚本发生在 "pre" 和 "post" 脚本之外。

  • prepareprepublishprepublishOnlyprepackpostpack

prepare(自 npm@4.0.0

  • 在打包之前运行
  • 在包发布之前运行
  • 在本地 npm install 上运行,不带任何参数
  • prepublish 之后但在 prepublishOnly 之前运行
  • 注意: 如果通过 git 安装的包包含 prepare 脚本,则在打包和安装包之前,将安装其 dependenciesdevDependencies,并运行准备脚本。

prepublish(弃用)

  • prepare

prepublishOnly

  • 在封装准备和封装之前运行,仅在 npm publish 上运行。

prepack

  • 在打包 tarball 之前运行(在 "npm pack"、"npm publish" 和安装 git 依赖时)。
  • 注意: "npm run pack" 与 "npm pack" 不同。 "npm run pack" 是任意用户定义的脚本名称,其中 "npm pack" 是 CLI 定义的命令。

postpack

  • 在 tarball 生成并移动到其最终目的地之后运行。

准备和预发布

弃用说明:预发布

npm@1.1.71 开始,npm CLI 已经为 npm publishnpm install 运行了 prepublish 脚本,因为它是一种方便的方式来准备一个包以供使用(一些常见的用例在下面的部分中描述)。 在实践中,它也被证明是 非常混乱。 从 npm@4.0.0 开始,引入了一个新事件 prepare,它保留了这种现有行为。 添加了一个新事件 prepublishOnly 作为过渡策略,以允许用户避免现有 npm 版本的混乱行为,并且只在 npm publish 上运行(例如,最后一次运行测试以确保它们处于良好状态)。

有关此更改的详细说明,请参阅 https://github.com/npm/npm/issues/10074,并进一步阅读。

用例

如果你需要在使用之前对你的包执行操作,以不依赖于目标系统的操作系统或体系结构的方式,使用 prepublish 脚本。 这包括以下任务:

  • 将 CoffeeScript 源代码编译成 JavaScript。
  • 创建 JavaScript 源代码的缩小版本。
  • 获取你的包将使用的远程资源。

prepublish 时间做这些事情的好处是它们可以在一个地方做一次,从而降低复杂性和可变性。 此外,这意味着:

  • 你可以依赖 coffee-script 作为 devDependency,因此你的用户不需要安装它。
  • 你不需要在你的包中包含缩小器,从而为你的用户减少大小。
  • 你不需要依赖你的用户在目标机器上拥有 curlwget 或其他系统工具。

生命周期操作顺序

npm publish

  • prepublishOnly
  • prepare
  • prepublish
  • publish
  • postpublish

npm pack

  • prepack
  • postpack

npm install

  • preinstall
  • install
  • postinstall

也触发

  • prepublish (在本地时)
  • prepare (在本地时)

npm start

npm run start 有一个 npm start 简写。

  • prestart
  • start
  • poststart

默认值

npm 将根据包内容默认一些脚本值。

  • "start": "node server.js"

    如果你的包根目录中有 server.js 文件,那么 npm 将默认 start 命令为 node server.js

  • "install": "node-gyp rebuild"

    如果你的包根目录中有一个 binding.gyp 文件,并且你还没有定义自己的 installpreinstall 脚本,npm 将默认使用 node-gyp 编译 install 命令。

用户

如果 npm 以 root 权限调用,那么它会将 uid 更改为 user 配置指定的用户账户或 uid,默认为 nobody。 设置 unsafe-perm 标志以使用 root 权限运行脚本。

环境

包脚本在一个环境中运行,其中提供了许多关于 npm 设置和进程当前状态的信息。

路径

如果你依赖于定义可执行脚本的模块,例如测试套件,那么这些可执行文件将被添加到 PATH 以执行脚本。 所以,如果你的 package.json 有这个:

{
"name" : "foo",
"dependencies" : {
"bar" : "0.1.x"
},
"scripts": {
"start" : "bar ./test"
}
}

然后你可以运行 npm start 来执行 bar 脚本,该脚本被导出到 npm install 上的 node_modules/.bin 目录中。

package.json 变量

package.json 字段附加在 npm_package_ 前缀上。 因此,例如,如果你的 package.json 文件中有 {"name":"foo", "version":"1.2.5"},那么你的包脚本会将 npm_package_name 环境变量设置为 "foo",并将 npm_package_version 设置为 "1.2.5"。 你可以在代码中使用 process.env.npm_package_nameprocess.env.npm_package_version 访问这些变量,其他字段以此类推。

配置

配置参数以 npm_config_ 前缀放入环境中。 例如,你可以通过检查 npm_config_root 环境变量来查看有效的 root 配置。

特殊:package.json "配置" 对象

如果有 <name>[@<version>]:<key> 的配置参数,则 package.json "配置" 键在环境中被覆盖。 例如,如果 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 环境变量设置为正在执行的循环的任何阶段。 因此,你可以将一个脚本用于流程的不同部分,根据当前发生的情况进行切换。

对象按照这种格式展平,所以如果你的 package.json 中有 {"scripts":{"install":"foo.js"}},那么你会在脚本中看到:

process.env.npm_package_scripts_install === "foo.js"

示例

例如,如果你的 package.json 包含以下内容:

{
"scripts" : {
"install" : "scripts/install.js",
"postinstall" : "scripts/install.js",
"uninstall" : "scripts/uninstall.js"
}
}

那么 scripts/install.js 将在生命周期的安装和安装后阶段被调用,而 scripts/uninstall.js 将在包被卸载时被调用。 由于 scripts/install.js 运行在两个不同的阶段,在这种情况下查看 npm_lifecycle_event 环境变量是明智的。

如果你想运行一个 make 命令,你可以这样做。 这工作得很好:

{
"scripts" : {
"preinstall" : "./configure",
"install" : "make && make install",
"test" : "make test"
}
}

退出

通过将该行作为脚本参数传递给 sh 来运行脚本。

如果脚本以 0 以外的代码退出,那么这将中止该过程。

请注意,这些脚本文件不必是 nodejs 甚至 javascript 程序。 它们必须是某种可执行文件。

钩子脚本

如果要在所有包的特定生命周期事件中运行特定脚本,则可以使用钩子脚本。

将一个可执行文件放在 node_modules/.hooks/{eventname} 中,当所有包在该根目录中安装的任何包的包生命周期中经历该点时,它将为所有包运行。

钩子脚本的运行方式与 package.json 脚本完全相同。 也就是说,它们位于一个单独的子进程中,具有上述环境。

最佳实践

  • 不要以非零错误代码退出,除非你是认真的。 除了卸载脚本,这将导致 npm 操作失败,并可能被回滚。 如果故障很小或只会阻止某些可选功能,那么最好只打印警告并成功退出。
  • 尽量不要使用脚本来做 npm 可以为你做的事情。 通读 package.json 以查看你可以通过适当地描述你的包来指定和启用的所有内容。 一般来说,这将导致更健壮和一致的状态。
  • 检查环境以确定将东西放在哪里。 例如,如果 npm_config_binroot 环境变量设置为 /home/user/bin,则不要尝试将可执行文件安装到 /usr/local/bin 中。 用户可能出于某种原因这样设置它。
  • 不要在脚本命令前加上 "sudo"。 如果出于某种原因需要 root 权限,那么它将因该错误而失败,并且用户将 sudo 有问题的 npm 命令。
  • 不要使用 install。 使用 .gyp 文件进行编译,使用 prepublish 进行其他任何操作。 你几乎不必显式设置预安装或安装脚本。 如果你这样做,请考虑是否有其他选择。 installpreinstall 脚本的唯一有效用途是编译必须在目标架构上完成。

也可以看看

npm 中文网 - 粤ICP备13048890号