npm 常用命令是如何执行的

对于前端开发的同学来说,npm是必定会接触到的。当我们创建一个前端项目(npm init)、运行项目(npm start)、安装模块(npm install)都会用到。虽然,目前yarnpnpm等工具兴起,但npm仍有一席之地。

在平常开发中,我也是会经常用到,但是我从未真正去仔细了解过这些命令是怎么执行的,为什么这些命令可以达到这样的效果。本文便针对这些,一一进行探索。

一、npm 命令如何执行

1.1 什么是命令行(Command-line)

命令行本质上是一个软件程序为用户和操作系统或应用程序之间提供通信的桥梁。有时候也称之为终端、虚拟控制台等。

换句话说,命令行其实和我们常见的图形界面目的相同,都是让用户控制计算机。但是,真正能够控制计算机硬件(CPU、内存等)的只有操作系统内核(Kernel),命令行和图形界面只是架设在用户和内核之间的一座桥梁。(为什么用户不能直接控制操作系统内核,这里就暂不介绍)

所以为了让用户能间接操作内核,每种操作系统都提供了命令行程序。例如Window系统中的 Command-line ShellPowerShell,Linux系统中的Shell。命令行是在内核基础上编写的一个应用程序,和微信、VsCode等其他软件差不多。但它的独特之处在于其开机立马启动,连接了用户和操作系统内核。

  • 命令行如何连接用户和内核

命令行能够接收用户输入的命令,并对命令进行处理,处理完在将结果反馈给用户。运行某个命令时,命令行通常都是去调用内核暴露的接口进行处理,只不过细节被隐藏了起来。这就是命令行连接用户和内核的方式。

例如Linux系统中,在终端输入cat log.txt命令查看 log.txt 文件中的内容。其实就是去调用内核提供的 open()read() 函数。然后把函数返回的结果反馈给用户。

  • 命令行也支持编程

命令行不仅能简单执行用户输入的命令,也能作为解释器,去执行和翻译代码。Linux系统中称为shell编程,Windows系统称为dos编程,它们是一种脚本语言。

  • 命令行能连接其他程序

在命令行中输入的命令可以是系统提供的内置命令(不同系统有区别),也可以其他的应用程序(一个程序就是一个命令),即外部命令。

所以,当我们在命令行执行npmnode等这些外部命令时,其实上是在调用npm、node这些应用程序。

但是,当我们在命令行输入这些外部命令时,命令行如何知道我们调用的是系统中的哪个应用程序呢?

1.2 命令行如何解析命令

接上述问题,命令行如何知道执行的是哪个应用程序的呢?本文就以 Windows 系统为例,简单介绍一下命令行是如何调用其他应用程序的。

先简单介绍一下Windows命令行解析命令的方式,当我们在命令行输入一条命令时:

  1. 首先,Window命令行会首先按检查该命令是否为内部命令,如果是,则直接执行该命令
  2. 如果不是内部命令,Window命令行会检查该命令是否为外部命令。如果是,则执行该外部指令。
  3. 如果不是外部命令,Windows命令行会在Path环境变量中列出的目录查找该命令。如果找到该命令,它将执行该命令。
  4. 如果以上都不是,Windows命令行则会显示错误信息:'xxx' 不是内部或外部命令,也不是可运行的程序或批处理文件

第1步其实就是执行系统提供的那些内置命令,例如mkdirstart等。

第2步中外部命令其实就是某些特定类型的文件,例如:可执行文件[.exe],批处理文件[/bat],命令脚本[.cmd] 等

只需要在命令行输入这些文件的文件名(可以不带扩展名)即可执行这些文件。但需要注意的是,一定要保证文件路径正确(可以是相对于当前命令行路径的相对路径,也可以是绝对路径),不然也会报错。

此外,如果是其他一般类型的文件(如:文本文件[.txt]),在命令行输入的时候必须带上扩展名,然后命令行会用指定软件打开该文件。

其实,在Windows命令行输入某个文件名和双击该文件的效果是差不多的。

举个例子,有个如下的commands文件夹,打开命令行然后切换到该目录,输入如下命令:

  • a:打开 a 应用程序
  • b:执行 b 批处理文件
  • c.txt:使用 notePad 打开 a.txt 文本文件

上述例子中,我们切换到了文件所在的目录下。那如果我们在其他目录下想执行这些文件,那就需要输入完整的相对路径或绝对路径。这对我们来说,非常难以记忆。

对此,我们可以将这些存在外部命令的目录添加到Path环境变量中。正如第3步所述,命令行会去在PATH环境变量中列出的目录查找该命令,如果找到则执行。

其实,这就解释了为什么我们在命令行的任意目录下输入npm, node都可以执行的原因了。是因为我们在下载node的时候,已经将node.cmd文件所在的目录添加到了Windows的Path环境变量中。

Path 环境变量:path环境变量的变量值是很多个文件夹路径,它的意思是告诉系统,当你想运行一个应用程序时,你可以在这些文件夹里查找。这样就能让系统快速启动这个应用程序

以我自己的电脑配置的Path环境变量为例,当我运行npm命令时,系统会运行C:\Software\Environment\nodejs下的npm.cmd文件。

1.3 npm 命令如何执行

由上述4可知,当在Windows命令行输入npm命令时,系统实际上运行的是指定目录(我的电脑是C:\Software\Environment\nodejs)下的npm.cmd文件

那我们打开npm.cmd文件,其内容如下:

从代码中我们可以看出,运行npm.cmd脚本文件,最终其实运行的是"%NODE_EXE%" "%NPM_CLI_JS%" %*(其中%~dp0可以简单理解为当前文件所在目录),即最终执行的命令一般如下::

python 复制代码
node node_modules\npm\bin\npm-cli.js

绕了大半天,我也终于明白了为什么很多推文上都说:在Windows系统上,命令行输入npm命令将执行node_modules\npm\bin\npm-cli.js文件了。

但其实我们再打开node_modules\npm\bin\npm-cli.js看看,发现其实和node_modules\npm\lib下的cli.jsnpm.js等文件有关。这里就不进一步叙述了。

但至于为什么npm runnpm start这些命令可以执行呢?实际上,npm-cli.js中的程序会获取命令行输入的参数,然后进行使用。可以简单理解为,npm之后输入的那些内容其实就是在传递参数。所以无论npm之后输入多少参数,本质上执行的还是npm-cli.js这个文件。

二、npm 常见命令的执行流程

既然了解了 npm 是各种命令是如何执行的,那下面就继续深入了解一些常见的命令作用以及执行流程吧。

2.1 npm init

当我们想初始化一个 npm 包时,npm init 能够帮我们快速初始化。其本质上就是快速创建一个 package.json 文件。命令如下:

swift 复制代码
npm init <initializer>
  • 当未传递 initializer 参数时,该命令会首先给用户提示,询问name,version等信息(如果想跳过这些提示,可以使用-y / --yes参数),然后创建在当前目录下创建一个package.json文件。
  • 如果传递了 initializer 参数时,initializer则是一个名为create-<initializer> 的npm包,并由 npm exec 命令安装,并执行该npmbin目录下的脚本。例如:npm init foo 会被转化成 npm exec create-foo
    所以当我们想使用create-react-app创建一个React项目my-react-app可直接运行 npm init react-app my-react-app 命令创建。

此外,npm init 还支持使用workspace配置项在项目中创建新的工作区,命令如下:

bash 复制代码
npm init -w <dir>

例如运行npm init -w package/a,则会在当前项目中生成如下目录和文件:

lua 复制代码
. 
+-- package.json 
    `-- packages 
        `-- a 
            `-- package.json

需要注意的是,该配置项是在项目中 创建新的工作区,所以该目录下必须存在package.json文件,不然会报错。

有关 npm init 的具体介绍,大家可以查看官方文档了解。

2.2 npm install *

npm install ,简单来说,就是安装一个 npm 包。

该命令会安装一个包以及它所依赖的任何包。如果一个包有 package-lock.json文件,或者 npm-shrinkwrap.json 文件,或者yarn.lock 文件,依赖安装则会遵循以下顺序:

  1. npm-shrinkwrap.json
  2. package=lock.json
  3. yarn.lock

该命令通常使用方式如下:

  • npm install

不加任何参数运行npm install命令会将package.json文件中的依赖项安装到本地 node_modules 文件夹。 如果是全局模式(即:-g 或 --global),则安装到全局目录下。

默认情况下,npm install 将安装 package.json 中列为依赖项的所有模块。

使用 --production 标志(或者当 NODE_ENV 环境变量设置为 production 时),npm 将不会安装 devDependencies 中列出的模块。当 NODE_ENV 环境变量设置为 production 时,要安装 dependenciesdevDependencies 中列出的所有模块,您可以使用 --production=false

  • npm install <folder>

如果 <folder> 位于项目的根目录中,它的依赖项将被安装,并且可能会像其他类型的依赖项一样被提升到顶级 node_modules

如果 <folder> 位于项目的根目录之外,npm 将不会在 <folder> 目录中安装包依赖项,但它会创建指向 <folder> 的符号链接。

注意:如果您想从注册表安装目录的内容(如包)而不是创建链接,则需要使用 --install-links 选项。

  • npm install <tarball file>

安装位于文件系统上的包。压缩包要求:

  1. 文件名必须使用 .tar.tar.gz.tgz 作为扩展名。
  2. 包内容应位于 tarball 内的子文件夹中(通常称为 package/)。
  3. 包必须包含具有 nameversion 属性的 package.json 文件。

通常 tarball 可以通过npm pack命令从包中创建。

bash 复制代码
npm install ./package.tgz
  • npm install <tarball url>

获取 tarball url,然后安装它。参数必须以 "http://" 或 "https://" 开头

ruby 复制代码
npm install https://github.com/indexzero/forever/tarball/v0.5.6
  • npm install [<@scope>/]<name>@<tag>

安装 <name>@<tag> 包,这也是平常开发中用的最多的方式,其中

  1. <@scope/>:可选参数,表示包的范围。每个 npm 用户/组织都有自己的范围,只有你可以在你的范围内添加包,这样就能防止包重名。
  2. <name>:包的名称
  3. <tag>:包的版本,若不指定,默认为latest

默认情况下,npm install 将任何指定的包保存到 package.json 文件中的 dependencies 项。但是也可以通过一些参数进行控制:

  1. -P, --save-prod:保存到 dependencies 中。默认值
  2. -D, --save-dev:保存到 devDependencies 中。
  3. -O, --save-optional:保存到 optionalDependencies 中。
  4. --no-save:防止保存到 dependencies。即:只安装,不保存到package.json文件中。

当使用上述任何选项将依赖项保存到 package.json 时,还有两个额外的可选标志:

  1. -E, --save-exact:保存的依赖项将使用精确的版本进行配置,而不是使用 npm 的默认 semver 范围运算符。
  2. -B, --save-bundle:保存的依赖项也将添加到您的 bundleDependencies 列表中。
  • 全局安装(-g / --gloabl)

默认情况下,npm install 会将所有包安装到当前目录下的node_modules文件夹中。但如果是在 "global" 模式下运行,会将包安装到 prefix 文件夹中。(prefix指的是全局安装目录, 可以通过npm config set prefix 命令设置)即:

  1. 包安装到 {prefix}/lib/node_modules 文件夹。
  2. bin 文件链接到 {prefix}/bin
  3. 手册页链接到 {prefix}/share/man

当然npm install还有其它很多配置项和使用方式,大家可以到官方文档了解。接着主要介绍一下 npm install 安装一个模块的流程。

npm install 安装模块机制

  1. 首先查询 node_modules 目录下是否存已经存在指定模块,若存在,则不再重新安装
  2. 若不存在,则从.npmrc文件(npm配置文件)配置的registry中查询模块压缩包的网址
  3. 如果查询到,则下载压缩包,存放在缓存目录 (可通过npm config get cache命令查看)
  4. 解压压缩包到当前项目的 node_modules 目录下。

前面 2.2 中 介绍的 npm install 可以帮助我们快速安装一个远程或本地的包。但是如果我们正在开发一个包,并且想在其它项目中测试它。使用 npm install 便有点繁琐,因为我们每次测试都需要先打包再安装,如果有迭代更新,就需要重新打包安装。对此,npm link能够很好地帮助我们解决这个问题。

npm link 用于创建包的符号链接

它通常是一个两步过程:

  1. 首先,在一个包中执行npm link,将在全局文件夹 中创建一个符号链接,该符号链接链接到执行npm link命令的{prefix}/lib/node_modules/<package>包。npm link它还会将包中的任何 bin 链接到{prefix}/bin/{name}. 请注意,npm link使用全局前缀。
  2. 在其他需要使用该包的项目中执行npm link package-name,将创建从全局安装的 package-name 到当前文件夹的 node_modules/ 的符号链接。

例如,现在有如下两个项目 project-a, project-b,依次执行如下命令:

bash 复制代码
cd ~/projects/project-a
npm link
cd ~/projects/project-b
npm link project-a

执行完毕后,cd ~/projects/project-a中的所有改变都会反映在~/projects/project-b/node_modules/project-a中。

当然,也可以将上述操作简化成一步:

bash 复制代码
cd ~/projects/project-b
npm link ../project-a

但是还是会先创建一个project-a全局链接,然后将全局安装目标链接到project-bnode_modules 文件夹中。

注意

  1. package-name指的是package.json中的name而不是 目录名称。例如上述例子中的project-aproject-b都是包名,不是目录名称。
  2. 默认情况下, 以这种方式链接的包不会 保存package.json的依赖项中。如果想保存在package.json文件中package-lock.json,可以执行npm link <dep> --save

此外,我们也可以通过--workspace参数指定创建链接的工作空间,例如:

  • npm link <pkg> --workspace <name> :链接相关包作为指定工作空间的依赖项。
  • npm link --workspace <name>:创建指向指定工作空间的全局链接。

2.4 npm start

开发过程中,通常会使用 npm start 命令启动一个项目。实际上这将运行package.json文件中scripts对象的start属性中指定的预定义命令。

如果"scripts"对象没有定义"start"属性,npm 将运行node server.js。

2.5 npm run *

npm run 用于运行 package.json 文件script对象中定义的任意命令。如果没有提供 "command",它将列出可用的脚本。

其中 starttestrestartstop 命令可以直接运行,例如:2.3 小节中的 npm start 命令。

任何位置参数都会传递给指定的脚本。使用 -- 传递以 - 为前缀的标志和选项,否则它们会被 npm 解析。具体语法如下所示:

xml 复制代码
npm run-script <command> [-- <args>]

此外,env 脚本是一个特殊的内置命令,可用于列出脚本在运行时可用的环境变量 。如果你的包中定义了 env 命令,它将优先于内置命令。

除了 shell 预先存在的 PATH 之外,npm run 还将 node_modules/.bin 添加到提供给脚本的 PATH 中。本地安装的依赖项提供的任何二进制文件都可以在没有 node_modules/.bin 前缀的情况下使用。

工作区(workspaces)支持

可以使用工作区或工作区配置,以便在指定工作区的上下文中从包的"脚本"对象运行任意命令。如果未提供"命令",它将列出每个已配置工作区的可用脚本。

例如这样一个已配置工作区的项目:

lua 复制代码
. 
+-- package.json 
`-- packages 
    +-- a 
    |   `-- package.json 
    +-- b 
    |   `-- package.json 
    `-- c 
        `-- package.json

根目录的package.json文件中有如下配置:

json 复制代码
{ 
    "workspaces": [ "./packages/*" ] 
}

每个配置的工作区的package.json文件的scripts中都有test命令,那我们就可以使用npm test --workspces执行配置的工作区中的所有test命令。

当然我们也可以指定工作区:

  • 指定单个工作区:npm test --workspace=a
  • 指定多个工作区:npm test -w a -w b

关于 npm run 更多细节,可查看官方文档,本文主要来探讨一下npm run-script 是如何执行的。

npm run-script 是如何执行的

这里以本人一个项目中的npm run dev为例,对应package.json中的脚本为:

json 复制代码
{
    scripts{
        "dev": "webpack-dev-server -c webpack.dev.js",
    }
}

首先我们会想为什么我们不直接在命令行执行webpack-dev-server -c webpack.dev.js这条命令呢?我们尝试一下,会发现命令行会报错如下:

那为什么 npm run dev 就可以执行呢?我们一步一步来探讨。

如第一节中所述,执行npm实际上是执行node目录下的node_modules\npm\bin\npm-cli.js文件。之所以node目录能够被命令行识别到,那是因为我们已经将node目录添加到系统环境变量中了。所以npm run dev是可以执行,那为什么通过npm run dev就可以执行对应的webpack-dev-server -c webpack.dev.js命令呢。

这是因为npm run 会将当前目录下的 node_modules/.bin(该文件夹用于存放一些包执行脚本的软连接) 添加到node的 PATH 环境变量中。我们可以看到该目录下会有如下两个文件,在Windows系统下就会执行webpack-dev-server.cmd文件。

查看该文件内容,发现其实执行的是:

node ...\webpack-dev-server\bin\webpack-dev-server.js

npm run-script执行流程总结一下来说就是:

  1. npm install 安装一个包的时候,会将该包的可执行脚本软链接到node_modules/.bin目录下。
  2. npm run执行某个脚本时会首先把当前目录下的 node_modules/.bin 添加到node的 PATH 环境变量中。
  3. 然后执行package.json文件scripts中定义的对应脚本。即:npm run dev 转换成 webpack-dev-server -c webpack.dev.js
  4. 执行脚本时,系统便会访问node_modules/.bin目录下对应的可执行文件。即webpack-dev-server.cmd,命令就转换成node_modules/.bin/webpack-dev-server -c webpack.dev.js
  5. 然后执行该可执行文件,进而最终转换成
vbscript 复制代码
node node_modules\webpack-dev-server\bin\webpack-dev-server.js -c webpack.dev.js

注意: npm run是将node_modules/.bin添加到node的PATH环境变量中,而并非系统环境变量。

系统环境变量是在操作系统级别上定义的变量,而 Node 环境变量是特定于 Node.js 应用程序的变量,node环境变量通常包含系统环境变量

npm run 之所以能够访问到node环境变量,是因为npm本质上执行的是node node_modules\npm\bin\npm-cli.js,是一个node应用程序。

2.6 npm exec

npm exec:执行本地或远程 npm 包中的命令。

上面介绍的npm run执行的命令必须是package.jsonscripts项定义的脚本命令。而npm exec 执行的命令无需在package.json文件中定义。但是其运行环境和npm run的类似。npm exec 使用方式如下:

css 复制代码
npm exec -- <pkg>[@<version>] [args...]
npm exec --package=<pkg>[@<version>] -- <cmd> [args...]
npm exec -c '<cmd> [args...]'
npm exec --package=foo -c '<cmd> [args...]'

npm exec 的执行流程

下面以 npm exec -- <pkg>[@<version>] [args...] 为例,探索一下具体的执行流程:

  1. 首先在本地 查找是否存在<pkg>对应的npm包(必须包名版本号都相同)

    • 若存在,则运行这个包的package.jsonbin字段对应的可执行文件
    • 若不存在,在远程npm仓库查找是否有<pkg>对应的npm包.
      • 若找到,则提示(可以通过 --yes--no参数控制是否提示)是否将它们安装到 npm 缓存文件夹中,该文件夹将添加到执行过程中的 PATH 环境变量中。下载完成后,再运行这个包package.jsonbin字段对应的可执行文件
      • 若没找到,则退出
  2. 执行 package.jsonbin 字段指定的可执行文件

    • 如果包在 package.json 的 bin 字段中只有单个入口,或者所有入口都是同一命令的别名,则将使用该命令。
    • 如果 bin 字段有多个入口 ,并且其中之一与包名匹配,则将使用该命令。
    • 如果没有 bin 字段,或者没有一个入口与包名匹配,则 npm exec 将退出并出现错误

此外 npm exec 提供如下常用配置项:

  • -p / --package:指定 npm exec 需要安装的包。无论 --package 选项指定什么包,都将在执行命令的 PATH 中提供,以及任何本地安装的包可执行文件。可以多次指定 --package 选项,以便在所有指定的包都可用的环境中执行提供的命令
  • -c / --call:指定与已安装的软件包一起运行的自定义命令(类似package.json文件中scripts字段指定的命令)。如果未提供 -c--call 选项,则使用位置参数来生成命令字符串。
  • -w / --workspace:指定命令运行的工作区,当然也可以通过--workspaces指定多个工作区。

2.7 npx

  • npx:执行本地或远程 npm 包中的命令。
css 复制代码
npx -- <pkg>[@<version>] [args...]
npx --package=<pkg>[@<version>] -- <cmd> [args...]
npx -c '<cmd> [args...]'
npx --package=foo -c '<cmd> [args...]'

npxnpm exec 的区别

npxnpm exec的作用相同,只是对于位置参数的解析方式有所不同,具体如下:

  • npx 执行命令时,所有options(例如:--package等)必须在任何位置参数之前设置。
  • npm exec执行命令时,会优先解析设置的options,可以使用双连字符--标志抑制对options的解析。

举个例子:

$ npx foo@latest bar --package=@npmcli/foo

在这种情况下,npx 将解析foo包名称,并运行以下命令

$ foo bar --package=@npmcli/foo

由于--package选项位于位置参数之后,因此它被视为执行命令的参数。

相反,由于 npm 的参数解析逻辑,运行此命令是不同的:

$ npm exec foo@latest bar --package=@npmcli/foo

--package在这种情况下,npm 将首先解析选项,解析@npmcli/foo包。然后,它将在该上下文中执行以下命令:

$ foo@latest bar

建议使用双连字符来明确告诉 npm 停止解析命令行选项和开关。因此,以下命令与上面的命令等效npx

$ npm exec -- foo@latest bar --package=@npmcli/foo

再引用官网上的两个例子:

tap使用提供的参数运行本地依赖项中的版本:

shell 复制代码
$ npm exec --tap --bail test/foo.js 
$ npx tap --bail test/foo.js

通过指定选项来运行名称与包名称匹配的命令以外的 命令--package

ini 复制代码
$ npm exec --package = foo -- bar --bar-argument  
# ~ 或 ~
$ npx --package = foo bar --bar-argument

npxnpm 的区别

  • npm全称是node package manager,是一个node包管理器。
  • npx 全称是 node package execute是一个npm包运行程序,npx会随 npm 5.2.0 及更高版本自动安装。

npx 出现之前,我们想要执行某些包中的二进制文件,需要首先npm install下载安装该包,然后切换到该包的安装目录下,然后执行。此外,全局安装一些不经常使用的包,还会造成污染。

npx出现后,它可以直接执行npm包,无需安装该包。

以我们常用的create-react-app为例,npx出现前,需先全局安装create-react-app

lua 复制代码
npm install create-react-app -g

然后执行create-react-app命令

lua 复制代码
create-react-app my-app

但实际上我们不会频繁使用create-react-app,全局安装可能会造成软件包污染。

而使用npx的话,只用执行如下命令即可:

lua 复制代码
npx create-react-app my-app

npx会首先查找本地是否安装了create-react-app包,如果找到则执行该包命令。如果没有找到,则会临时安装 create-react-app包,然后执行相关命令。即,仅在使用的时候安装,使用完之后又会卸载,不会造成软件包污染。

总结来说,npmnpx区别如下:

npm npx
NPM 是一个包管理器,用于在计算机上安装、删除和更新 Javascript 包。 NPX 是一个包执行器,用于直接执行 javascript 包,无需安装它们。
NPM 会全局安装软件包,这意味着您的机器可能会被长期不再需要的软件包污染。 NPX 不安装软件包,因此无需担心计算机上的软件包污染。
要使用 NPM 来使用 create-react-app,我们首先必须全局安装它,然后运行它,这使得在这种情况下使用 NPM 变得多余。 NPX 最常见的应用是 create-react-app 命令。由于我们只需要使用它一次,即在初始化项目时,不需要安装。

三、scripts

上述对npm常见命令的执行已经介绍的差不多了,但是个人感觉有必要在此继续了解一下有关package.json文件中 scripts 项的一些知识点。

scripts中定义的就是一些可以通过npm run执行的脚本命令,执行时npm run会将node_modules/.bin目录添加到PATH环境变量中。具体执行流程2.5中已经详细介绍,这里就不再赘述了。下面主要介绍 scripts 的一些书写规范。

支持通配符

由于 npm 脚本就是 Shell 脚本,因为可以使用 Shell 通配符。

json 复制代码
"lint": "jshint *.js"
"lint": "jshint **/*.js"

上面代码中,*表示任意文件名,**表示任意一层子目录。

传递参数

向 npm 脚本传入参数,要使用--标明。例如,有如下脚本

arduino 复制代码
"webpack": 'webpack-cli'

我想要传递 --help 参数查看帮助文档,则需要运行如下命令:

arduino 复制代码
npm run webpack -- --help

多任务

如果 npm 脚本里面需要执行多个任务,那么需要明确它们的执行顺序。

并行执行 (即同时执行):使用&符号连接

arduino 复制代码
$ npm run script1.js & npm run script2.js

继发执行 (即只有前一个任务成功,才执行下一个任务):使用&&符号连接

arduino 复制代码
$ npm run script1.js && npm run script2.js

输入输出

此外,任务之间或者任务与文件之间可以进行输入输出的传递。

  1. < 用于将文件的内容(stdin)输入到命令
  2. > 用于重定向命令的输出(stdout)并将其转储到文件
  3. | 用于重定向命令的输出(stdout)并将其发送到另一个命令

hooks

npm 脚本有prepost两个钩子。举例来说,build脚本命令的钩子就是prebuildpostbuild

json 复制代码
"prebuild": "echo I run before the build script",
"build": "cross-env NODE_ENV=production webpack",
"postbuild": "echo I run after the build script"

用户执行npm run build的时候,会自动按照下面的顺序执行。

arduino 复制代码
npm run prebuild && npm run build && npm run postbuild

快捷脚本

npm提供了一些快捷脚本,无需使用npm run即可执行,例如以下几个常用的 npm 快捷脚本。

  • npm start => npm run start
  • npm stop => npm run stop
  • npm test => npm run test
  • npm restart => npm run stop && npm run restart && npm run start

变量

  1. 通过npm_package_前缀,npm 脚本可以拿到package.json里面的字段(注意:获取的是当前路径package.json文件内部的变量)

例如:变量npm_package_name返回包的名称

arduino 复制代码
console.log(process.env.npm_package_name); // 输出包名

我们通过环境变量process.env对象,拿到package.json的字段值。如果是 Bash 脚本,可以用$npm_package_name

  1. 通过npm_config_前缀,拿到 npm 的配置变量,即npm config get xxx命令返回的值。

例如:变量 npm_config_registry 返回配置的npm仓库地址。

该小结主要参考以下几位大佬的推文:

[1] npm scripts 使用指南

[2] How to Use npm as a Build Tool

[3] Awesome npm Scripts

Ending

本文这里就结束了,以上是个人学习过程中的一些记录,如有错误,欢迎提出,共同学习。

相关推荐
小行星1251 分钟前
前端预览pdf文件流
前端·javascript·vue.js
小行星1258 分钟前
前端把dom页面转为pdf文件下载和弹窗预览
前端·javascript·vue.js·pdf
Lysun00118 分钟前
[less] Operation on an invalid type
前端·vue·less·sass·scss
J总裁的小芒果33 分钟前
Vue3 el-table 默认选中 传入的数组
前端·javascript·elementui·typescript
Lei_zhen9636 分钟前
记录一次electron-builder报错ENOENT: no such file or directory, rename xxxx的问题
前端·javascript·electron
咖喱鱼蛋38 分钟前
Electron一些概念理解
前端·javascript·electron
yqcoder39 分钟前
Vue3 + Vite + Electron + TS 项目构建
前端·javascript·vue.js
鑫宝Code1 小时前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架
Mr_Xuhhh2 小时前
重生之我在学环境变量
linux·运维·服务器·前端·chrome·算法
永乐春秋3 小时前
WEB攻防-通用漏洞&文件上传&js验证&mime&user.ini&语言特性
前端