阅读(455) (10)

npm 脚本 script

2021-09-16 14:59:19 更新

npm 如何处理脚本字段

描述

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

前后脚本

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

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

在本例中,npm run compress将按照描述执行这些脚本。

生命周期脚本

有一些特殊的生命周期脚本仅在某些情况下发生。这些脚本发生除pre<event>post<event>和 <event>脚本。

  • prepareprepublishprepublishOnlyprepack,postpack

准备(因为npm@4.0.0

  • 在包装包装之前的任何时间运行,即在包装期间npm publish 和npm pack
  • 在打包之前运行
  • 在发布包之前运行
  • npm install没有任何参数的情况下在本地运行
  • 之后运行prepublish,但之前prepublishOnly
  • 注意:如果通过 git 安装的包包含prepare 脚本,则在打包和安装包之前dependenciesdevDependencies将安装其和并运行准备脚本。
  • 由于npm@7这些脚本在后台运行。要查看输出,运行带有:--foreground-scripts

预发布(已弃用)

  • 不在期间运行npm publish,但在npm ci 和期间运行npm install。请参阅下文了解更多信息。

仅预发布

  • 在包准备和打包之前运行,仅在npm publish.

预包装

  • 在打包 tarball 之前运行(在“ npm pack”、“ npm publish”和安装 git 依赖项时)。注意:“ npm run pack”与“ npm pack”不同。" npm run pack" 是用户定义的任意脚本名称,其中, " npm pack" 是 CLI 定义的命令。邮包
  • 在 tarball 生成之后但在将其移动到最终目的地之前运行(如果有的话,publish 不会在本地保存 tarball)

准备和预发布

弃用说明:预发布

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

请参阅https://github.com/npm/npm/issues/10074以获得更长的理由,并进一步阅读此更改。

用例

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

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

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

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

生命周期操作顺序

npm cache add

  • prepare

npm ci

  • preinstall
  • install
  • postinstall
  • prepublish
  • preprepare
  • prepare
  • postprepare

这些都在将模块实际安装到 node_modules中后按顺序运行,中间没有发生任何内部操作

npm diff

  • prepare

npm install

这些也会在你运行时运行 npm install -g <pkg-name>

  • preinstall
  • install
  • postinstall
  • prepublish
  • preprepare
  • prepare
  • postprepare

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

这些是从脚本运行的 <pkg-name>

npm pack

  • prepack
  • prepare
  • postpack

npm publish

  • prepublishOnly
  • prepack
  • prepare
  • postpack
  • publish
  • postpublish
  • prepare 

期间不会运行 --dry-run

npm rebuild

preinstall``install``postinstall``prepare``prepare 仅当当前目录是符号链接时才运行(例如,带有链接的包)

npm restart

如果restart定义了脚本,则运行这些事件,否则 stopstart如果存在,则都运行,包括它们的pre和 post迭代)

  • prerestart
  • restart
  • postrestart

npm run <user defined>

  • pre<user-defined>
  • <user-defined>
  • post<user-defined>

npm start

  • prestart
  • start
  • poststart

如果server.js包的根目录中有一个文件,那么 npm 会将start命令默认为node server.jsprestart并且 poststart在这种情况下仍会运行。

npm stop

  • prestop
  • stop
  • poststop

npm test

  • pretest
  • test
  • posttest

关于缺少npm uninstall脚本的说明

虽然 npm v6 有uninstall生命周期脚本,但 npm v7 没有。删除包的原因多种多样,目前还没有明确的方法可以为脚本提供足够有用的上下文。

删除软件包的原因包括:

  • 一个用户直接卸载了这个包
  • 用户卸载了依赖包,因此正在卸载此依赖项
  • 用户卸载了一个依赖包,但另一个包也依赖于这个版本
  • 此版本已与另一个版本合并为副本等等。
  • 由于缺乏必要的上下文,uninstall生命周期脚本没有实现,也不会起作用。

用户

当 npm 以 root 身份运行时,脚本总是使用工作目录所有者的有效 uid 和 gid 运行。

环境

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

路径

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

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

然后你可以运行npm start执行bar脚本,它导出到node_modules/.bin的目录npm install

package.json 变量

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

有关package-json.md包配置的更多信息,请参见。

当前生命周期事件

最后,npm_lifecycle_event环境变量被设置为正在执行的循环阶段。因此,您可以将单个脚本用于流程的不同部分,该脚本根据当前发生的情况进行切换。

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

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 以外的代码退出,则这将中止进程。

请注意,这些脚本文件不必是 Node.js 甚至 JavaScript 程序。它们只需要是某种可执行文件。

最佳实践

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