.env 文件设置环境变量npm install 期间运行的生命周期脚本的输出node --eval 和 node --printper-env:根据 $NODE_ENV 在脚本之间切换package.json 具有属性 "scripts",它允许我们定义*包脚本*,这些小型 Shell 脚本执行与包相关的任务,例如编译工件或运行测试。本章解释了它们,以及我们如何编写它们,以便它们在 Windows 和 Unix(macOS、Linux 等)上都能工作。
*npm 包脚本*通过 package.json 的属性 "scripts" 定义
{
···
"scripts": {
"tsc": "tsc",
"tscwatch": "tsc --watch",
"tscclean": "shx rm -rf ./dist/*"
},
···
}"scripts" 的值是一个对象,其中每个属性定义一个包脚本
如果我们输入
npm run <script-name>
那么 npm 会在 Shell 中执行名称为 script-name 的脚本。例如,我们可以使用
npm run tscwatch
在 Shell 中运行以下命令
tsc --watch
在本章中,我们偶尔会使用 npm 选项 -s,它是 --silent 的缩写,它告诉 npm run 减少输出
npm -s run <script-name>
此选项在关于日志记录的部分中有更详细的介绍。
某些包脚本可以通过更短的 npm 命令运行
| 命令 | 等效 |
|---|---|
npm test、npm t |
npm run test |
npm start |
npm run start |
npm stop |
npm run stop |
npm restart |
npm run restart |
npm start:如果没有包脚本 "start",npm 将运行 node server.js。npm restart:如果没有包脚本 "restart",npm 将运行 "prerestart"、"stop"、"start"、"postrestart"。默认情况下,npm 在 Windows 上通过 cmd.exe 运行包脚本,在 Unix 上通过 /bin/sh 运行包脚本。我们可以通过npm 配置设置 script-shell 更改它。
但是,这样做很少是一个好主意:许多现有的跨平台脚本都是为 sh 和 cmd.exe 编写的,并且会停止工作。
某些脚本名称是为*生命周期脚本*保留的,每当我们执行某些 npm 命令时,npm 都会运行这些脚本。
例如,每当我们执行 npm install(不带参数)时,npm 都会运行脚本 "postinstall"。生命周期脚本将在后面详细介绍。
如果配置设置 ignore-scripts 为 true,则 npm 永远不会自动运行脚本,只有在我们直接调用它们时才会运行。
在 Unix 上,npm 通过npm completion 支持命令和包脚本名称的 Tab 自动补全。我们可以通过在 .profile / .zprofile / .bash_profile / 等文件中添加以下行来安装它。
. <(npm completion)如果您需要非 Unix 平台的 Tab 自动补全,请执行网络搜索,例如“npm tab completion PowerShell”。
不带名称的 npm run 将列出可用的脚本。如果存在以下脚本
"scripts": {
"tsc": "tsc",
"tscwatch": "tsc --watch",
"serve": "serve ./site/"
}那么它们将像这样列出
% npm run
Scripts available via `npm run-script`:
tsc
tsc
tscwatch
tsc --watch
serve
serve ./site/
如果有很多包脚本,我们可以将脚本名称误用作分隔符(脚本 "help" 将在下一小节中解释)
"scripts": {
"help": "scripts-help -w 40",
"\n========== Building ==========": "",
"tsc": "tsc",
"tscwatch": "tsc --watch",
"\n========== Serving ==========": "",
"serve": "serve ./site/"
},现在脚本如下所示
% npm run
Scripts available via `npm run-script`:
help
scripts-help -w 40
========== Building ==========
tsc
tsc
tscwatch
tsc --watch
========== Serving ==========
serve
serve ./site/
请注意,预先添加换行符 (\n) 的技巧在 Unix 和 Windows 上都有效。
包脚本 "help" 通过包 @rauschma/scripts-help 中的 bin 脚本 scripts-help 打印帮助信息。我们通过 package.json 属性 "scripts-help" 提供描述("tscwatch" 的值被缩写以适应一行)
"scripts-help": {
"tsc": "Compile the TypeScript to JavaScript.",
"tscwatch": "Watch the TypeScript source code [...]",
"serve": "Serve the generated website via a local server."
}这就是帮助信息的样子
% npm -s run help
Package “demo”
╔══════╤══════════════════════════╗
║ help │ scripts-help -w 40 ║
╚══════╧══════════════════════════╝
Building
╔══════════╤══════════════════════════════════════════╗
║ tsc │ Compile the TypeScript to JavaScript. ║
╟──────────┼──────────────────────────────────────────╢
║ tscwatch │ Watch the TypeScript source code and ║
║ │ compile it incrementally when and if ║
║ │ there are changes. ║
╚══════════╧══════════════════════════════════════════╝
Serving
╔═══════╤══════════════════════════════════════════╗
║ serve │ Serve the generated website via a local ║
║ │ server. ║
╚═══════╧══════════════════════════════════════════╝
如果某些名称用于脚本,则它们会在某些情况下自动运行
npm install 等操作时运行。所有其他脚本都称为*直接运行脚本*。
每当 npm 运行包脚本 PS 时,它都会自动运行以下脚本(如果它们存在)
prePS(*前置脚本*)postPS(*后置脚本*)以下脚本包含前置脚本 prehello 和后置脚本 posthello
"scripts": {
"hello": "echo hello",
"prehello": "echo BEFORE",
"posthello": "echo AFTER"
},如果我们运行 hello,就会发生这种情况
% npm -s run hello
BEFORE
hello
AFTER
npm 在 npm 命令期间运行*生命周期脚本*,例如
npm publish(将包上传到 npm 注册表)npm pack(为注册表包、包目录等创建存档)npm install(不带参数使用,用于安装从 npm 注册表以外的来源下载的包的依赖项)如果任何生命周期脚本失败,则整个命令将立即停止并报错。
生命周期脚本的用例是什么?
编译 TypeScript:如果一个包包含 TypeScript 代码,我们通常会在使用它之前将其编译成 JavaScript 代码。虽然后者代码通常不会签入版本控制,但必须将其上传到 npm 注册表,以便可以从 JavaScript 使用该包。生命周期脚本允许我们在 npm publish 上传包之前编译 TypeScript 代码。这确保了在 npm 注册表中,JavaScript 代码始终与我们的 TypeScript 代码同步。它还确保我们的 TypeScript 代码没有静态类型错误,因为在遇到这些错误时,编译(以及发布)会停止。
运行测试:我们还可以在发布包之前使用生命周期脚本运行测试。如果测试失败,则不会发布包。
这些是最重要的生命周期脚本(有关所有生命周期脚本的详细信息,请参阅npm 文档)
"prepare":
.tgz 文件)之前运行npm publish 期间npm pack 期间npm install 或全局安装包时运行。"prepack" 在创建包存档(.tgz 文件)之前运行npm publish 期间npm pack 期间"prepublishOnly" 仅在 npm publish 期间运行。"install" 在不带参数使用 npm install 或全局安装包时运行。"preinstall" 和/或一个后置脚本 "postinstall"。它们的名称更清楚地表明了 npm 何时运行它们。下表总结了这些生命周期脚本的运行时间
prepublishOnly |
prepack |
prepare |
install |
|
|---|---|---|---|---|
npm publish |
✔ |
✔ |
✔ |
|
npm pack |
✔ |
✔ |
||
npm install |
✔ |
✔ |
||
| 全局安装 | ✔ |
✔ |
||
| 通过 git、路径安装 | ✔ |
**注意:**自动执行操作总是有点棘手。我通常遵循以下规则
prepublishOnly)。postinstall)。在本节中,我们将偶尔使用
node -p <expr>
它运行 expr 中的 JavaScript 代码并将结果打印到终端 - 例如
% node -p "'hello everyone!'.toUpperCase()"
HELLO EVERYONE!
当包脚本运行时,当前目录始终是包目录,与我们在其根目录树中的位置无关。我们可以通过将以下脚本添加到 package.json 来确认这一点
"cwd": "node -p \"process.cwd()\""让我们在 Unix 上试用 cwd
% cd /Users/robin/new-package/src/util
% npm -s run cwd
/Users/robin/new-package
以这种方式更改当前目录有助于编写包脚本,因为我们可以使用相对于包目录的路径。
当一个模块 M 从一个以包 P 的名称开头的说明符导入模块时,Node.js 会遍历 node_modules 目录,直到找到 P 的目录。
M 父目录中的 node_modules(如果存在)。M 父目录的父目录中的 node_modules(如果存在)。也就是说,M 继承了其祖先目录的 node_modules 目录。
类似的继承也发生在 bin 脚本上,当我们安装一个包时,这些脚本存储在 node_modules/.bin 中。npm run 会临时将条目添加到 shell PATH 变量中(Unix 上为 $PATH,Windows 上为 %Path%)。
node_modules/.bin。node_modules/.bin。要查看这些添加的内容,我们可以使用以下包脚本:
"bin-dirs": "node -p \"JS\""JS 代表包含以下 JavaScript 代码的单行:
(process.env.PATH ?? process.env.Path)
.split(path.delimiter)
.filter(p => p.includes('.bin'))在 Unix 上,如果我们运行 bin-dirs,我们会得到以下输出:
% npm -s run bin-dirs
[
'/Users/robin/new-package/node_modules/.bin',
'/Users/robin/node_modules/.bin',
'/Users/node_modules/.bin',
'/node_modules/.bin'
]
在 Windows 上,我们会得到:
>npm -s run bin-dirs
[
'C:\\Users\\charlie\\new-package\\node_modules\\.bin',
'C:\\Users\\charlie\\node_modules\\.bin',
'C:\\Users\\node_modules\\.bin',
'C:\\node_modules\\.bin'
]
在 Make、Grunt 和 Gulp 等任务运行器中,变量很重要,因为它们有助于减少冗余。然而,虽然包脚本没有自己的变量,但我们可以使用_环境变量_(也称为_shell 变量_)来解决这个问题。
我们可以使用以下命令列出特定于平台的环境变量:
envSETnode -p process.env在 macOS 上,结果如下所示:
TERM_PROGRAM=Apple_Terminal
SHELL=/bin/zsh
TMPDIR=/var/folders/ph/sz0384m11vxf5byk12fzjms40000gn/T/
USER=robin
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
PWD=/Users/robin/new-package
HOME=/Users/robin
LOGNAME=robin
···
在 Windows 命令行中,结果如下所示:
Path=C:\Windows;C:\Users\charlie\AppData\Roaming\npm;···
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROMPT=$P$G
TEMP=C:\Users\charlie\AppData\Local\Temp
TMP=C:\Users\charlie\AppData\Local\Temp
USERNAME=charlie
USERPROFILE=C:\Users\charlie
···
此外,npm 会在运行包脚本之前临时添加更多环境变量。要查看最终结果,我们可以使用以下命令:
npm run env
此命令调用内置的包脚本。让我们用这个 package.json 来试试:
{
"name": "@my-scope/new-package",
"version": "1.0.0",
"bin": {
"hello": "./hello.mjs"
},
"config": {
"stringProp": "yes",
"arrayProp": ["a", "b", "c"],
"objectProp": {
"one": 1,
"two": 2
}
}
}所有 npm 临时变量的名称都以 npm_ 开头。让我们按字母顺序只打印这些变量:
npm run env | grep npm_ | sort
npm_ 变量具有层次结构。在 npm_lifecycle_ 下,我们可以找到当前正在运行的包脚本的名称和定义:
npm_lifecycle_event: 'env',
npm_lifecycle_script: 'env',在 Windows 上,npm_lifecycle_script 在这种情况下将是 SET。
在 npm_config_ 前缀下,我们可以看到一些 npm 的配置设置(在 npm 文档中有描述)。以下是一些示例:
npm_config_cache: '/Users/robin/.npm',
npm_config_global_prefix: '/usr/local',
npm_config_globalconfig: '/usr/local/etc/npmrc',
npm_config_local_prefix: '/Users/robin/new-package',
npm_config_prefix: '/usr/local'
npm_config_user_agent: 'npm/8.15.0 node/v18.7.0 darwin arm64 workspaces/false',
npm_config_userconfig: '/Users/robin/.npmrc',
前缀 npm_package_ 允许我们访问 package.json 的内容。它的顶层如下所示:
npm_package_json: '/Users/robin/new-package/package.json',
npm_package_name: '@my-scope/new-package',
npm_package_version: '1.0.0',
在 npm_package_bin_ 下,我们可以找到 package.json 属性 "bin" 的属性:
npm_package_bin_hello: 'hello.mjs',
npm_package_config_ 条目允许我们访问 "config" 的属性:
npm_package_config_arrayProp: 'a\n\nb\n\nc',
npm_package_config_objectProp_one: '1',
npm_package_config_objectProp_two: '2',
npm_package_config_stringProp: 'yes',
这意味着 "config" 允许我们设置可以在包脚本中使用的变量。下一小节将对此进行更深入的探讨。
请注意,对象已转换为“嵌套”条目(第 2 行和第 3 行),而数组(第 1 行)和数字(第 2 行和第 3 行)已转换为字符串。
以下是剩余的 npm_ 环境变量:
npm_command: 'run-script',
npm_execpath: '/usr/local/lib/node_modules/npm/bin/npm-cli.js',
npm_node_execpath: '/usr/local/bin/node',
以下 package.json 演示了如何在包脚本中访问通过 "config" 定义的变量:
{
"scripts": {
"hi:unix": "echo $npm_package_config_hi",
"hi:windows": "echo %npm_package_config_hi%"
},
"config": {
"hi": "HELLO"
}
}遗憾的是,没有内置的跨平台方法可以从包脚本访问环境变量。
但是,有一些带有 bin 脚本的包可以帮助我们。
包 env-var 允许我们获取环境变量。
"scripts": {
"hi": "env-var echo {{npm_package_config_hi}}"
}包 cross-env 允许我们设置环境变量。
"scripts": {
"build": "cross-env FIRST=one SECOND=two node ./build.mjs"
}.env 文件设置环境变量还有一些包允许我们通过 .env 文件设置环境变量。这些文件具有以下格式:
# Comment
SECRET_HOST="https://example.com"
SECRET_KEY="123456789" # another comment
使用与 package.json 分开的文 件可以让我们将这些数据保留在版本控制之外。
以下是一些支持 .env 文件的包:
包 dotenv 支持 JavaScript 模块的 .env 文件。我们可以预加载它:
node -r dotenv/config app.mjs
我们也可以导入它:
import dotenv from 'dotenv';
dotenv.config();
console.log(process.env);包 node-env-run 允许我们通过 shell 命令使用 .env 文件:
# Loads `.env` and runs an arbitrary shell script.
# If there are CLI options, we need to use `--`.
nodenv --exec node -- -p process.env.SECRET
# Loads `.env` and uses `node` to run `script.mjs`.
nodenv script.mjs包 env-cmd 是前一个包的替代方案。
# Loads `.env` and runs an arbitrary shell script
env-cmd node -p process.env.SECRET
该包具有更多功能:在多组变量之间切换、更多文件格式等。
让我们探讨如何将参数传递给通过包脚本调用的 shell 命令。我们将使用以下 package.json:
{
···
"scripts": {
"args": "log-args"
},
"dependencies": {
"log-args": "^1.0.0"
}
}bin 脚本 log-args 如下所示:
for (const [key,value] of Object.entries(process.env)) {
if (key.startsWith('npm_config_arg')) {
console.log(`${key}=${JSON.stringify(value)}`);
}
}
console.log(process.argv.slice(2));位置参数按预期工作:
% npm -s run args three positional arguments
[ 'three', 'positional', 'arguments' ]
npm run 会消耗选项并为其创建环境变量。它们不会添加到 process.argv 中。
% npm -s run args --arg1='first arg' --arg2='second arg'
npm_config_arg2="second arg"
npm_config_arg1="first arg"
[]
如果我们希望选项出现在 process.argv 中,则必须使用_选项终止符_ --。该终止符通常插入在包脚本名称之后:
% npm -s run args -- --arg1='first arg' --arg2='second arg'
[ '--arg1=first arg', '--arg2=second arg' ]
但我们也可以将其插入在该名称之前:
% npm -s run -- args --arg1='first arg' --arg2='second arg'
[ '--arg1=first arg', '--arg2=second arg' ]
npm 支持以下日志级别:
| 日志级别 | npm 选项 |
别名 |
|---|---|---|
| silent | --loglevel silent |
-s --silent |
| error | --loglevel error |
|
| warn | --loglevel warn |
-q --quiet |
| notice | --loglevel notice |
|
| http | --loglevel http |
|
| timing | --loglevel timing |
|
| info | --loglevel info |
-d |
| verbose | --loglevel verbose |
-dd --verbose |
| silly | --loglevel silly |
-ddd |
日志记录指的是两种活动:
以下小节描述了:
日志级别如何影响这些活动。原则上,silent 记录最少,而 silly 记录最多。
如何配置日志记录。上表显示了如何通过命令行选项临时更改日志级别,但还有更多设置。我们可以临时或永久地更改它们。
默认情况下,包脚本在终端输出方面相对详细。以以下 package.json 文件为例:
{
"name": "@my-scope/new-package",
"version": "1.0.0",
"scripts": {
"hello": "echo Hello",
"err": "more does-not-exist.txt"
},
···
}如果日志级别高于 silent 并且包脚本退出时没有错误,则会发生以下情况:
% npm run hello
> @my-scope/new-package@1.0.0 hello
> echo Hello
Hello
如果日志级别高于 silent 并且包脚本失败,则会发生以下情况:
% npm run err
> @my-scope/new-package@1.0.0 err
> more does-not-exist.txt
does-not-exist.txt: No such file or directory
使用日志级别 silent,输出会变得不那么混乱:
% npm -s run hello
Hello
% npm -s run err
does-not-exist.txt: No such file or directory
某些错误会被 -s 吞没。
% npm -s run abc
%
我们需要至少 error 日志级别才能看到它们:
% npm --loglevel error run abc
npm ERR! Missing script: "abc"
npm ERR!
npm ERR! To see a list of scripts, run:
npm ERR! npm run
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/robin/.npm/_logs/2072-08-30T14_59_40_474Z-debug-0.log
遗憾的是,日志级别 silent 也会抑制 npm run(不带参数)的输出。
% npm -s run
%
默认情况下,日志会写入 npm 缓存目录,我们可以通过 npm config 获取其路径:
% npm config get cache
/Users/robin/.npm
日志目录的内容如下所示:
% ls -1 /Users/robin/.npm/_logs
2072-08-28T11_44_38_499Z-debug-0.log
2072-08-28T11_45_45_703Z-debug-0.log
2072-08-28T11_52_04_345Z-debug-0.log
日志中的每一行都以行索引和日志级别开头。这是一个使用日志级别 notice 编写的日志示例。有趣的是,即使是比 notice“更详细”的日志级别(例如 silly)也会出现在其中:
0 verbose cli /usr/local/bin/node /usr/local/bin/npm
1 info using npm@8.15.0
···
33 silly logfile done cleaning log files
34 timing command:run Completed in 9ms
···
如果 npm run 返回错误,则相应的日志将如下所示结尾:
34 timing command:run Completed in 7ms
35 verbose exit 1
36 timing npm Completed in 28ms
37 verbose code 1
如果没有错误,则相应的日志将如下所示结尾:
34 timing command:run Completed in 7ms
35 verbose exit 0
36 timing npm Completed in 26ms
37 info ok
npm config list --long 会打印各种设置的默认值。以下是与日志记录相关的设置的默认值:
% npm config list --long | grep log
loglevel = "notice"
logs-dir = null
logs-max = 10
如果 logs-dir 的值为 null,则 npm 将使用 npm 缓存目录中的 _logs 目录(如前所述)。
logs-dir 允许我们覆盖默认值,以便 npm 将其日志写入我们选择的目录。logs-max 允许我们配置在 npm 删除旧文件之前要写入日志目录的文件数量。如果我们将 logs-max 设置为 0,则永远不会写入日志。loglevel 允许我们配置 npm 的日志级别。要永久更改这些设置,我们也使用 npm config,例如:
获取当前日志级别:
npm config get loglevel永久设置当前日志级别:
npm config set loglevel silent将日志级别永久重置为内置默认值:
npm config delete loglevel我们也可以通过命令行选项临时更改设置,例如:
npm --loglevel silent run build
npm 文档 解释了更改设置的其他方法(例如使用环境变量)。
npm install 期间运行的生命周期脚本的输出在 npm install(不带参数)期间运行的生命周期脚本的输出是隐藏的。我们可以通过(临时或永久)将 foreground-scripts 设置为 true 来更改此设置。
silent 才会在使用 npm run 时关闭额外输出。最常用于包脚本的两个 shell 是:
sh。cmd.exe。在本节中,我们将研究在两个 shell 中都有效的结构。
提示:
使用段之间用斜杠分隔的相对路径:即使您通常在 Windows 平台上使用反斜杠,Windows 也接受斜杠作为分隔符。
用双引号引起来参数:虽然 sh 支持单引号,但 Windows 命令行不支持。遗憾的是,当我们在包脚本定义中使用双引号时,我们必须对其进行转义。
"dir": "mkdir \"\my dir""有两种方法可以链接在两个平台上都有效的命令:
&& 之后的命令仅在前一个命令成功(退出代码为 0)时执行。|| 之后的命令仅在前一个命令失败(退出代码不为 0)时执行。忽略退出代码的链接在不同平台上有所不同:
;&以下交互演示了 && 和 || 在 Unix 上的工作方式(在 Windows 上,我们将使用 dir 而不是 ls):
% ls unknown && echo "SUCCESS" || echo "FAILURE"
ls: unknown: No such file or directory
FAILURE
% ls package.json && echo "SUCCESS" || echo "FAILURE"
package.json
SUCCESS
可以通过 shell 变量访问退出代码:
$?%errorlevel%npm run 返回的退出代码与最后执行的 shell 脚本的退出代码相同:
{
···
"scripts": {
"hello": "echo Hello",
"err": "more does-not-exist.txt"
}
}以下交互发生在 Unix 上:
% npm -s run hello ; echo $?
Hello
0
% npm -s run err ; echo $?
does-not-exist.txt: No such file or directory
1
|cmd > stdout-saved-to-file.txtcmd < stdin-from-file.txt以下命令在两个平台上都存在(但在选项方面有所不同):
cdecho。Windows 上的注意事项:双引号会被打印出来,而不是被忽略。exitmkdirmorermdirsort以下 package.json 演示了三种调用依赖项中的 bin 脚本的方法:
{
"scripts": {
"hi1": "./node_modules/.bin/cowsay Hello",
"hi2": "cowsay Hello",
"hi3": "npx cowsay Hello"
},
"dependencies": {
"cowsay": "^1.5.0"
}
}说明:
hi1:依赖项中的 bin 脚本安装在 node_modules/.bin 目录中。
hi2:如我们所见,npm 在执行包脚本时会将 node_modules/.bin 添加到 shell PATH 中。这意味着我们可以像使用全局安装的 bin 脚本一样使用本地 bin 脚本。
hi3:当 npx 运行脚本时,它也会将 node_modules/.bin 添加到 shell PATH 中。
在 Unix 上,我们可以直接调用包本地脚本,前提是它们具有 hashbang 并且是可执行的。但是,这在 Windows 上不起作用,这就是为什么最好通过 node 调用它们的原因。
"build": "node ./build.mjs"node --eval 和 node --print当包脚本的功能变得过于复杂时,通常最好通过 Node.js 模块来实现它,这使得编写跨平台代码变得容易。
但是,我们也可以使用 node 命令来运行小的 JavaScript 代码片段,这对于以跨平台的方式执行小任务非常有用。相关的选项有:
node --eval <expr> 计算 JavaScript 表达式 expr。node -enode --print <expr> 计算 JavaScript 表达式 expr 并将结果打印到终端。node -p以下命令在 Unix 和 Windows 上均可使用(只有注释是特定于 Unix 的)
# Print a string to the terminal (cross-platform echo)
node -p "'How are you?'"
# Print the value of an environment variable
# (Alas, we can’t change variables via `process.env`)
node -p process.env.USER # only Unix
node -p process.env.USERNAME # only Windows
node -p "process.env.USER ?? process.env.USERNAME"
# Print all environment variables
node -p process.env
# Print the current working directory
node -p "process.cwd()"
# Print the path of the current home directory
node -p "os.homedir()"
# Print the path of the current temporary directory
node -p "os.tmpdir()"
# Print the contents of a text file
node -p "fs.readFileSync('package.json', 'utf-8')"
# Write a string to a file
node -e "fs.writeFileSync('file.txt', 'Text content', 'utf-8')"
如果我们需要特定于平台的行终止符,我们可以使用 os.EOL——例如,我们可以将前面命令中的 'Text content' 替换为
`line 1${os.EOL}line2${os.EOL}`注意事项
os 或 fs 的原因。fs 支持更多文件系统操作。这些操作记录在 §8 “在 Node.js 上使用文件系统” 中。npm-quick-run 提供了一个 bin 脚本 nr,它允许我们使用缩写来运行包脚本——例如
nr m -w 执行 "npm run mocha -- -w"(如果 "mocha" 是第一个名称以“m”开头的包脚本)。nr c:o 运行包脚本 "cypress:open"。并发运行 shell 脚本
&start以下两个包为我们提供了跨平台的选择,用于实现该功能和相关功能
concurrently 并发运行多个 shell 命令——例如
concurrently "npm run clean" "npm run build"npm-run-all 提供了几种功能——例如
一种更方便的顺序调用包脚本的方式。以下两个命令是等效的
npm-run-all clean lint build
npm run clean && npm run lint && npm run build并发运行包脚本
npm-run-all --parallel lint build使用通配符运行多个脚本——例如,watch:* 代表所有名称以 watch: 开头的包脚本(watch:html、watch:js 等)
npm-run-all "watch:*"
npm-run-all --parallel "watch:*"包 shx 允许我们使用“Unix 语法”来运行各种文件系统操作。它所做的一切都可以在 Unix 和 Windows 上运行。
创建目录
"create-asset-dir": "shx mkdir ./assets"删除目录
"remove-asset-dir": "shx rm -rf ./assets"清空目录(使用双引号以确保通配符 * 的安全)
"tscclean": "shx rm -rf \"./dist/*\""复制文件
"copy-index": "shx cp ./html/index.html ./out/index.html"删除文件
"remove-index": "shx rm ./out/index.html"shx 基于 JavaScript 库 ShellJS,其存储库列出了 所有受支持的命令。除了我们已经看到的 Unix 命令之外,它还模拟:cat、chmod、echo、find、grep、head、ln、ls、mv、pwd、sed、sort、tail、touch、uniq 等。
包 trash-cli 适用于 macOS(10.12+)、Linux 和 Windows(8+)。它将文件和目录放入回收站,并支持路径和 glob 模式。以下是使用它的示例
trash tmp-file.txt
trash tmp-dir
trash "*.jpg"
包 copyfiles 允许我们复制文件树。
以下是 copyfiles 的一个用例:在 TypeScript 中,我们可以导入非代码资产,例如 CSS 和图像。TypeScript 编译器将代码编译到“dist”(输出)目录,但会忽略非代码资产。此跨平台 shell 命令将它们复制到 dist 目录
copyfiles --up 1 "./ts/**/*.{css,png,svg,gif}" ./distTypeScript 编译
my-pkg/ts/client/picker.ts -> my-pkg/dist/client/picker.js
copy-assets 复制
my-pkg/ts/client/picker.css -> my-pkg/dist/client/picker.css
my-pkg/ts/client/icon.svg -> my-pkg/dist/client/icon.svg
包 onchange 监视文件并在每次文件更改时运行 shell 命令——例如
onchange 'app/**/*.js' 'test/**/*.js' -- npm test
一个常见的替代方案(还有许多其他方案)
在开发过程中,拥有一个 HTTP 服务器通常很有用。以下软件包(以及许多其他软件包)可以提供帮助
per-env:根据 $NODE_ENV 切换脚本bin 脚本 per-env 允许我们运行包脚本 SCRIPT,并根据环境变量 NODE_ENV 的值自动在(例如)SCRIPT:development、SCRIPT:staging 和 SCRIPT:production 之间切换
{
"scripts": {
// If NODE_ENV is missing, the default is "development"
"build": "per-env",
"build:development": "webpack -d --watch",
"build:staging": "webpack -p",
"build:production": "webpack -p"
},
// Processes spawned by `per-env` inherit environment-specific
// variables, if defined.
"per-env": {
"production": {
"DOCKER_USER": "my",
"DOCKER_REPO": "project"
}
}
}bin 脚本 cross-os 根据当前操作系统在脚本之间切换。
{
"scripts": {
"user": "cross-os user"
},
"cross-os": {
"user": {
"darwin": "echo $USER",
"win32": "echo %USERNAME%",
"linux": "echo $USER"
}
},
···
}支持的属性值有:darwin、freebsd、linux、sunos、win32。