写在前面
上班闲逛某社区(就是摸鱼T.T), 无意中发现个帖子标题挺有意思的: 运行npm run xxx的时候发生了什么?<br />嗯哼, 其实该命令经常会使用, 特别是在web端项目中, 先看下一般是如何启动一个web项目的:
git clone xxx // 项目克隆npm install // 安装依赖npm run dev // 启动项目, 启动成功后浏览器通过http://localhost:8080访问该web项目
But从来没去研究过发生了什么,故有了此文。
我想的
我想的:npm run xxx会去项目根目录package.json中找到script标签, 并执行对应xxx脚本(为方面描述, 这里的npm run xxx先当做是npm run dev, 其他同理)。
先看下常规一个vue项目的package.json文件(只截取了重点的scripts做展示).
{"scripts": {"dev": "vue-cli-service serve","build": "vue-cli-service build","lint": "vue-cli-service lint"}}
比如执行npm run dev, 其实等价于执行vue-cli-service serve,用npm run dev相对来说比较语法比较简单好记。
我想的到此结束了, 没了?????
实际上
为什么不直接执行vue-cli-service serve?
我们先来看下执行该脚本的效果:

通过上面两张图,你会发现:windows上在powershell跟cmd中报错稍有不同,但都表达了一个意思:操作系统中没有vue-cli-service serve这条指令。
看到这里,你可能就会有点好奇了:若没有这个指令, 那为什么npm run dev就可以执行而且不报错呢?
请继续往下看!
为什么npm run dev可正确执行?
按照前面的说法: npm run dev === vue-cli-service serve, 但为什么npm run dev却可以执行呢, 不报错?
我们在安装依赖的时候(比如: npm install -g @vue/cli), 除了往node_modules中添加相关依赖外, 还会在.bin文件中创建同名的可执行文件,而具体执行哪个取决于操作系统和组策略&环境变量决定的。<br />
我们看下3种可执行文件的区别是什么:
- vue-cli-service: unix 系默认的可执行文件,必须输入完整文件名
- vue-cli-service.cmd: windows cmd 中默认的可执行文件,当我们不添加后缀名时,自动根据 pathext 查找文件
vue-cli-serviec.ps1: Windows PowerShell 中可执行文件,可以跨平台
我们再看下windows下在cmd窗口执行的话, vue-cli-service.cmd的内容长什么样子:
看到这里,你会发现:运行npm run dev相当于执行node bin/vue-cli-service.js。大白话:npm run dev === vue-cli-service serve === vue-cli-service.cmd === node vue-cli-service.js。
我们紧接着再看下这图(访问路径: 项目根目录node_modules -> @vue -> cli-service -> package.json):
留意下vue-cli-service.js的文件头: #!/usr/bin/env node,表示这是一个通过使用 Node 执行的脚本。
至此,就可以解释为什么直接执行vue-cli-service serve会报错了:没有找到相应的可执行文件。
答案总结
npm run xxx执行的时候,会先去项目根目录package.json中找到script标签, 然后去项目的node_modules-.bin中查找是否有同名的可执行文件,若有则直接执行;若没有则去全局的.bin查找,最后才是去path环境变量中查找。若还是没有找到,则报错。
写在最后
作为一个前端搬砖仔,凡是多想想会发生什么事情,为什么🧐,毕竟细节决定高度!
