npm run是如何执行一个脚本的

1,021 阅读2分钟

什么是npm脚本

{
  // ...
  "scripts": {
    "build": "webpack"
  }
}

package.jsonscripts字段定义的每一个属性,都对应了一条脚本命令。上面代码定义了一个build脚本,执行npm run build,最终会使用webpack打包工程。

npm run build 背后发生的事情

在当前shell中执行npm run build时,系统会在环境变量PATH中寻找npm命令,npm命令是如何被找到的呢?

1. 寻找npm命令

Linux中命令其实是一个个的命令行程序,这些程序是分布在不同的众多目录中的。当命令行中输入一个命令的时,Linux需要到指定目录去查找命令对应的程序,而在PATH环境变量就记录这些目录。

安装nodejs时,会在PATH中添加nodejs的bin目录地址。

echo $PATH //可以查看PATH环境变量中记录了可执行命令所在的目录
// 输出结果:
/home/max/.nvm/versions/node/v14.17.6/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib

/home/max/.nvm/versions/node/v14.17.6/bin就是nodejs的bin目录地址。我们看看bin目录里有什么:

ll -a /home/max/.nvm/versions/node/v14.17.6/bin
...
lrwxrwxrwx 1 max max  38 Aug 31  2021 npm -> ../lib/node_modules/npm/bin/npm-cli.js
...

npm命令就在这里!

2. 执行npm命令

从上面的输出可以发现,npm是一个软链接指向npm-cli.js。这意味着执行npm时,实际执行了npm-cli.js文件。

npm-cli.js又是如何执行的?系统是如何知道使用node调用这个js文件呢?秘密就在npm-cli.js的第一行中:#!/usr/bin/env node

#!叫做Shebang,常出现在类Unix系统的脚本中第一行,作为前两个字符,用于指明执行这个脚本文件的解释器。#!/usr/bin/env node会通知系统执行当前文件时,去PATH变量中所有的可执行命令目录中寻找node,类似前面寻找npm命令一样,找到node命令后就可以执行node npm-cli.js。到此为止,npm命令就被成功的调用了。

3. 调用webpack命令

webpack命令又在哪里?

默认情况下,我们会把webpack安装在当前工程中:npm i -D webpack,安装完毕后,会在当前工程的node_modules/.bin子目录中添加webpack命令。

npm run build是如何调用到node_modules/.bin目录中的webpack命令的?

每当执行npm run,就会自动新建一个 Shell,在这个 Shell 里面执行指定的脚本命令。因此,只要是 Shell(一般是 Bash)可以运行的命令,就可以写在 npm 脚本里面。

比较特别的是,npm run新建的这个 Shell,会将当前目录的node_modules/.bin子目录加入PATH变量,如此一来,我们就能调用到node_modules/.bin目录中的webpack命令了。执行结束后,再将PATH变量恢复原样。

参考链接