掌握 NPM 脚本
介绍
内置脚本和别名
执行多个脚本
了解错误
静默或大声运行脚本
从文件引用脚本
事前与事后
访问环境变量
传递参数
命名约定
文档
结论
scripts
您可能在文件中遇到过该属性package.json
,甚至自己编写过一些脚本。但是您知道 NPM Scripts 的所有功能吗?
我使用 NPM Scripts 已经很多年了,但几周前我想给脚本传递一个参数,却发现自己不知道该怎么做。于是,我决定学习所有关于 NPM Scripts 的知识,并写下这篇文章。
在本文中,我将分享有关如何充分利用 NPM 脚本的研究。
介绍
NPM 脚本是一组在文件中定义的内置和自定义脚本package.json
。它们的目标是提供一种简单的方法来执行重复性任务,例如:
- 在代码上运行 linter 工具
- 执行测试
- 在本地启动你的项目
- 构建你的项目
- 缩小或丑化 JS 或 CSS
您还可以在 CI/CD 管道中使用这些脚本来简化构建和生成测试报告等任务。
script
要定义 NPM 脚本,您需要做的就是设置其名称并在文件中的属性中写入脚本package.json
:
{
"scripts": {
"hello-world": "echo \"Hello World\""
}
}
值得注意的是,NPM 将所有依赖项的二进制文件都包含在脚本中。因此,您可以直接访问它们,就像它们被添加到 PATH 中一样。我们来看一个例子:
不要这样做:
{
"scripts": {
"lint": "./node_modules/.bin/eslint .",
}
}
您可以这样做:
{
"scripts": {
"lint": "eslint ."
}
}
npm 运行
现在您需要做的就是npm run hello-world
从项目的根文件夹在终端上运行。
> npm run hello-world
"Hello World"
您还可以运行npm run
(不指定脚本)来获取所有可用脚本的列表:
> npm run
Scripts available in sample-project via `npm run-script`:
hello-world
echo "Hello World"
如您所见,npm run
打印添加到的每个脚本的名称和实际脚本package.json
。
ℹ️
npm run
是的别名npm run-script
,这意味着你也可以使用npm run-script hello-world
。在本文中,我们将使用 ,npm run <script>
因为它更短。
内置脚本和别名
在前面的例子中,我们创建了一个名为的自定义脚本hello-world
,但您应该知道 npm 还支持一些内置脚本,例如test
和start
。
有趣的是,与我们的自定义脚本不同,这些脚本可以使用别名执行,从而使完整命令更短且更容易记住。例如,以下所有命令都将运行该test
脚本。
npm run-script test
npm run test
npm test
npm t
与该命令类似test
,以下所有内容都将运行该start
命令:
npm run-script start
npm run start
npm start
为了使这些内置脚本能够正常工作,我们需要在 中为它们定义一个脚本package.json
。否则,它们将会失败。我们可以像编写其他脚本一样编写这些脚本。以下是示例:
{
"scripts": {
"start": "node app.js",
"test": "jest ./test",
"hello-world": "echo \"Hello World\""
}
}
执行多个脚本
我们可能想合并一些脚本并一起运行。为此,我们可以使用&&
或&
。
- 要顺序运行多个脚本,我们使用
&&
。例如:npm run lint && npm test
- 要并行运行多个脚本,我们使用
&
。例如:npm run lint & npm test
- 这仅适用于 Unix 环境。在 Windows 中,它将按顺序运行。
例如,我们可以创建一个组合另外两个脚本的脚本,如下所示:
{
"scripts": {
"lint": "eslint .",
"test": "jest ./test",
"ci": "npm run lint && npm test"
}
}
了解错误
当脚本以非零退出代码完成时,表示运行脚本时发生错误,并且执行终止。
这意味着我们可以通过使用非零退出代码来故意结束带有错误的脚本的执行,如下所示:
{
"scripts": {
"error": "echo \"This script will fail\" && exit 1"
}
}
当脚本抛出错误时,我们会获得一些其他详细信息,例如错误编号errno
和code
。这两者都有助于在 Google 上搜索错误。
如果我们需要更多信息,我们随时可以访问完整的日志文件。该文件的路径在错误消息的末尾提供。失败时,所有日志都会包含在该文件中。
静默或大声运行脚本
用于npm run <script> --silent
减少日志并防止脚本抛出错误。
当你想运行一个你知道可能会失败的脚本,但又不想抛出错误时,这个--silent
标志(简称)会很有帮助。也许在 CI 管道中,你希望即使命令失败,整个管道也能继续运行。--loglevel silent
test
它还可以用作-s
:npm run <script> -s
ℹ️ 如果我们不想在脚本不存在时出现错误,我们可以使用
--if-present
:npm run <script> --if-present
。
关于日志级别
我们了解了如何使用 来减少日志数量--silent
,但如何获取更详细的日志呢?或者两者兼而有之?
日志级别有多种选择:“silent”、“error”、“warn”、“notice”、“http”、“timing”、“info”、“verbose”和“silly”。默认级别为“notice”。日志级别决定哪些日志将显示在输出中。任何高于当前定义级别的日志都将被显示。
我们可以使用 明确定义运行命令时要使用的日志级别--loglevel <level>
。如前所述,--silent
标志与使用 相同--loglevel silent
。
现在,如果我们想要获取更详细的日志,我们需要使用比默认级别(“通知”)更高的级别。例如--loglevel info
:
我们还可以使用简短版本来简化命令:
-s
,,--silent
--loglevel silent
-q
,,--quiet
--loglevel warn
-d
,--loglevel info
-dd
,,--verbose
--loglevel verbose
-ddd
,--loglevel silly
因此,为了获得最高级别的细节,我们可以使用npm run <script> -ddd
或npm run <script> --loglevel silly
。
从文件引用脚本
您可以从文件执行脚本。这对于特别复杂、难以在文件中读取的脚本非常有用package.json
。但是,如果您的脚本简短明了,则此功能的价值不大。
考虑这个例子:
{
"scripts": {
"hello:js": "node scripts/helloworld.js",
"hello:bash": "bash scripts/helloworld.sh",
"hello:cmd": "cd scripts && helloworld.cmd"
}
}
我们用来node <script-path.js>
执行 JS 文件,也bash <script-path.sh>
用来执行 bash 文件。
请注意,您不能直接调用scripts/helloworld.cmd
CMD 和 BAT 文件。您需要cd
先使用 导航到该文件夹。否则,您将收到来自 NPM 的错误。
从文件执行脚本的另一个优点是,如果脚本很复杂,则在单独的文件中维护比在文件内的单行中维护更容易package.json
。
事前与事后
我们可以为任何脚本创建“pre”和“post”脚本,NPM 会自动按顺序运行它们。唯一的要求是,脚本名称(前缀为“pre”或“post”)必须与主脚本名称一致。例如:
{
"scripts": {
"prehello": "echo \"--Preparing greeting\"",
"hello": "echo \"Hello World\"",
"posthello": "echo \"--Greeting delivered\""
}
}
如果我们执行npm run hello
,NPM 将按以下顺序执行脚本:prehello
,hello
,posthello
。这将导致以下输出:
> script-test@1.0.0 prehello
> echo "--Preparing greeting"
"--Preparing greeting"
> script-test@1.0.0 hello
> echo "Hello World"
"Hello World"
> script-test@1.0.0 posthello
> echo "--Greeting delivered"
"--Greeting delivered"
ℹ️ 如果我们单独运行
prehello
或posthello
,NPM将不会自动执行任何其他脚本。它仅在运行“主”脚本时才有效,在本例中为hello
。
访问环境变量
在执行 NPM 脚本时,NPM 会提供一组可用的环境变量。这些环境变量是通过从 NPM 配置、package.json 和其他来源获取数据生成的。
配置参数使用前缀放置在环境中npm_config_
。以下是一些示例:
{
"scripts": {
"config:loglevel": "echo \"Loglevel: $npm_config_loglevel\"",
"config:editor": "echo \"Editor: $npm_config_editor\"",
"config:useragent": "echo \"User Agent: $npm_config_user_agent\""
}
}
我们来看看执行上述命令后会得到什么:
> npm run config:loglevel
# Output: "Loglevel: notice"
> npm run config:editor
# Output: "Editor: notepad.exe"
> npm run config:useragent
# Output: "User Agent: npm/6.13.4 node/v12.14.1 win32 x64"
ℹ️您还可以运行
npm config ls -l
以获取所有可用配置参数的列表。
类似地,package.json
字段(例如version
和main
)也包含在npm_package_
前缀中。让我们看几个例子:
{
"scripts": {
"package:main": "echo \"Main: $npm_package_main\"",
"package:name": "echo \"Name: $npm_package_name\"",
"package:version": "echo \"Version: $npm_package_version\""
}
}
这些命令的结果将是这样的:
> npm run package:main
# Output: "Main: app.js"
> npm run package:name
# Output: "Name: npm-scripts-demo"
> npm run package:version
# Output: "Version: 1.0.0"
最后,您可以使用文件中的字段添加自己的环境变量。那里设置的值将使用前缀添加为环境变量。config
package.json
npm_package_config
{
"config": {
"my-var": "Some value",
"port": 1234
},
"script": {
"packageconfig:port": "echo \"Port: $npm_package_config_port\"",
"packageconfig:myvar": "echo \"My var: $npm_package_config_my_var\""
}
}
如果我们执行这两个命令,我们将得到:
> npm run packageconfig:port
# Output: "Port: 1234"
> npm run packageconfig:myvar
# Output: "My var: Some value"
ℹ️ 在 Windows 中,
cmd
您$npm_package_config_port
应该使用%npm_package_config_port%
来访问环境变量。
传递参数
在某些情况下,您可能需要向脚本传递一些参数--
。您可以使用命令末尾的 来实现,如下所示npm run <script> -- --argument="value"
:
让我们看几个例子:
{
"scripts": {
"lint": "eslint .",
"test": "jest ./test",
}
}
如果我只想运行发生变化的测试,我可以这样做:
> npm run test -- --onlyChanged
如果我想运行 linter 并将输出保存在文件中,我可以执行以下命令:
> npm run lint -- --output-file lint-result.txt
参数作为环境变量
传递参数的另一种方式是通过环境变量。我们添加到脚本中的任何键值对都将转换为带有npm_config
前缀的环境变量。这意味着我们可以创建如下脚本:
{
"scripts": {
"hello": "echo \"Hello $npm_config_firstname!\""
}
}
然后像这样使用它:
> npm run hello --firstname=Paula
# Output: "Hello Paula"
命名约定
对于如何命名脚本,没有具体的指导原则,但我们可以记住一些事情,以便其他开发人员更容易掌握我们的脚本。
根据我的研究,我对这个问题的看法如下:
- 保持简短:如果你查看 Svelte 的 NPM 脚本,你会注意到大多数脚本名称都只有一个单词。如果我们能够设法保持脚本名称简短,那么在需要它们时就会更容易记住它们。
- 保持一致:您可能需要使用多个单词来命名脚本。在这种情况下,请选择一种命名风格并坚持使用。可以是驼峰式命名、短横线命名或任何您喜欢的命名方式。但请避免混用。
前缀
您可能见过一种约定,即使用前缀和冒号对脚本进行分组,例如“build:prod”。这只是一种命名约定。它不会影响脚本的行为,但有助于创建更容易通过前缀识别的脚本组。
例子:
{
"scripts": {
"lint:check": "eslint .",
"lint:fix": "eslint . --fix",
"build:dev": "...",
"build:prod": "..."
}
}
文档
考虑为你的脚本添加文档,以便其他人可以轻松理解如何以及何时使用它们。我喜欢在 Readme 文件中添加几行解释每个脚本的内容。
每个可用脚本的文档应包括:
- 脚本名称
- 描述
- 接受的参数(可选)
- 其他文档的链接(可选):例如,如果您的脚本运行
tsc --build
,您可能想要包含指向 Typescript 文档的链接。
结论
这就是我找到的关于 NPM Scripts 的全部内容。希望对你有用!通过这项研究,我确实学到了很多东西。虽然花费的时间比我想象的要多,但绝对值得。
如果您还有任何需要补充的内容,请告诉我,以使本指南更加完善!💬
文章来源:https://dev.to/paulasantamaria/mastering-npm-scripts-2chd