阅读(4866) (8)

npm 脚本 scripts

2021-10-18 15:26:54 更新

npm 如何处理脚本(Scripts)字段?

描述

npm 支持 package.json 文件的 "scripts" 属性,适用于以下脚本:

  • 预发布(prepublish):在打包和发布包之前运行,以及在没有任何参数的本地 npm install 上运行。(见下文)
  • 准备(prepare): 在打包和发布包之前,在没有任何参数的本地 npm install 上,以及在安装 git 依赖项时运行(见下文)。这是在预发布之后运行,但在仅预发布之前。
  • 预发布(prepublishOnly):在准备和打包包之前运行,仅在 npm publish 上运行。
  • 预打包(prepack):在打包 tarball 之前运行(在 npm packnpm publish和安装 git 依赖项时。)
  • 打包后(postpack):在 tarball 生成并移动到其最终目的后运行。
  • 发布,发布后(publish,postpublish):在发布包后运行。
  • 预安装(preinstall):在安装包之前运行。
  • 安装,安装后(install,postinstall):在安装包后运行。
  • 预卸载,卸载(preuninstall,uninstall):在卸载包之前运行。
  • 卸载后(postuninstall):在卸载软件包后运行。
  • 预测版本(preversion):在碰撞包版本之前运行。
  • 版本(version):在碰撞包版本后运行,但在提交之前。
  • 提交版本(postversion):在碰撞包版本后运行,并在提交后运行。
  • 预测试,测试,测试后(pretest,test,posttest):通过 npm test 命令运行。
  • 预停止,停止,停止后(prestop,stop,poststop):通过 npm stop 命令运行。
  • 预启动,启动,启动后(prestart,start,poststart):通过 npm start 命令运行。注意:如果没有提供重启脚本,npm restart 将运行停止和启动脚本。
  • 预包装,包装,包装后(preshrinkwrap,shrinkwrap,postshrinkwrap):通过 npm shrinkwrap 命令取消。

此外,可以通过运行npm run-script<stage>来执行任意脚本。具有匹配名称的前置(pre)和后置(post)命令也将运行(例如:premyscript,myscript,postmyscript)。来自依赖项的脚本可以使用npm explore <pkg> --npm run<stage>运行。

预发布和与准备(prepublish and prepare)

弃用说明

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

使用案例

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

  • start:node server.js: 如果你的包的根目录中有一个 server.js 文件,那么 npm 会将启动命令默认为 node server.js。
  • install:node-gyp rebuild: 如果你的包的根目录中有一个 binding.gyp 文件,并且你没有定义自己的安装和预安装脚本,npm 将默认安装命令使用 node-gyp 进行编译。

    用户

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

环境

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

路径

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

{"name":foot
,"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环境变量设置为foot,并且npm_package_version设置为1.2.5。

package.json 对象

如果有<name>[@<version>]:<key>的配置参数,package.json "config"键在环境中被覆盖。例如,如果 package.json 有这个:

{"name":"foo"
,"config":{"post":"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} 中,当所有软件包在该根目录中安装的任何软件包的软件包生命周期中的那个点时,它将为所有软件包运行。

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

最佳实践

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