在前端开发中,我们经常使用 npm run dev 来启动本地开发环境。那么,当输入完类似 npm run xxx 的命令后,到底发生了什么呢?项目又是如何被启动的?
首先我们知道,node 可以把 .js 文件当做脚本来运行,例如启动后台项目时经常会输入:
node app.js
这个是直接使用全局安装的 node 命令来执行了 ./src 目录下的 app.js 文件。
而当我们使用 npm (或者 yarn)来管理项目时,会在根目录下生成一个 package.json 文件,其中的 scripts 属性,就是用于配置 npm run xxx 命令的,比如以下配置:
//vue项目中的package.json 文件
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
再看对应的node_modules目录下的.bin目录,里面有一个vite文件
打开vite文件可以看到 #!/bin/sh,表示这是一个脚本(node可以执行)。
当执行npm run dev时,首先会去package.json 文件中找到script属性的"dev",然后再到node_modules目录下的.bin目录中找到"dev"对应的"vite",执行vite(由前面可知vite是一个脚本,类似于前面提过的node app.js)。
再如:
当执行npm run dev 时,相当于执行 "./node_modules/.bin/nodemon bin/www",其中 bin/www作为参数传入。
即:
"scripts": {
"xxx1": "sss1",
"xxx2": "sss2",
"xxx3": "sss3"
},
当执行npm run xxx1时,相当于执行了sss1(先去package.json的scripts属性中查找xxx1,再去./node_modules/.bin中查找xxx1对应的sss1,执行sss1文件);类似的,当执行npm run xxx2时相当于执行了sss2;执行npm run xxx3时,相当于执行了sss3。
问题1: 为什么不直接执行sss而要执行xxx 呢?
直接执行sss会报错,因为操作系统中不存在sss这一条指令。
问题2: 为什么执行npm run xxx(或者yarn xxx)时就能成功呢?
因为我们在安装依赖的时候,是通过npm i xxx (或者yarn ...)来执行的,例如 npm i @vue/cli-service,npm 在 安装这个依赖的时候,就会node_modules/.bin/ 目录中创建好名为vue-cli-service 的几个可执行文件了。
.bin 目录下的文件,是一个个的软链接,打开文件可以看到文件顶部写着 #!/bin/sh ,表示这是一个脚本,可由node来执行。当使用 npm run xxx 执行 sss 时,虽然没有安装 sss的全局命令,但是 npm 会到 ./node_modules/.bin 中找到 sss 文件作为脚本来执行,则相当于执行了 ./node_modules/.bin/sss。
即: 运行 npm run xxx的时候,npm 会先在当前目录的 node_modules/.bin 查找要执行的程序,如果找到则运行;没有找到则从全局的 node_modules/.bin 中查找; 全局目录还是没找到,就会从 window的path环境变量中查找有没有其他同名的可执行程序。