start
- 今天准备午休的时候,刚躺到床上,不知怎得,突然想起最近看到的一篇文章标题:
运行 npm run xxx 的时候发生了什么?
。 - 当时只是看了一眼文章的标题,有那么一点点印象,但是等我仔细思考这个问题的时候,发现好像不是那么简单。
- 后来啊,我越思考越精神,不行不午睡了,我要弄懂它!
问题拆分
命令 : npm run serve
问题一: 为什么我们可以在控制台输入npm
还不会报错?
问题二: run
是哪里来的?
问题三: serve
又是哪里来的?
知识储备
首先要学会打开cmd窗口
- win + R键 输入
cmd
回车即可 - 文件夹目录输入
cmd
回车即可 - 按住
shift
,在文件夹右键 =》在此次打开Powershell
即可
注释:cmd 和 Powershell 暂时可以为理解是一样的,打开后就是下面这个样子:
问题一 》》》为什么我们可以在控制台输入npm
还不会报错?
比如说我在cmd窗口输入一个我的昵称 tomato
,它会提示
'tomato' 不是内部或外部命令,也不是可运行的程序或批处理文件。
那我是不是可以反向理解,我们的npm
它是 内部或外部命令,或者是可运行的程序或批处理软件
其中一种呢?
这里我找了一下相关文章,解释cmd
窗口中输入字符串后的逻辑:
- 它首先会判断这个文件名是否包含绝对路径。如果包含绝对路径,那它只会在绝对路径中寻找。此时如果没找到,直接报错。
- 如果不包含绝对路径,则它会在
cmd
所操作的目录下寻找。
- 如果没找到,就会在操作系统的内置命令中找。PS :我这里就演示了一下
cd、dir
- 如果还没找到,就会去环境变量 Path 中记载的目录中找到。如果再没找到,
cmd
就会报错。
打开环境变量操作步骤 :设置》系统》关于》高级系统变量》环境变量》系统变量》Path
到这里就基本清楚了,为什么cmd
中能够执行npm
了。
问题一总结
- 我们安装了nodejs,nodejs中又内置npm,所以安装了nodejs 就一起安装了npm;
- 在安装nodejs的时候,安装程序会把nodejs的安装路径写入到了环境变量 Path 中;
- 在我们cmd中输入npm的时候,它会依次匹配,如果前三步都没有寻找到的话,它会在环境变量 Path 中记载的目录下找是否有名字叫npm的可执行文件;
- 这个时候就会读取到我们 nodejs文件夹下面的
npm.cmd
这个文件了;
PS: 可以尝试着把这个npm.cmd
文件剪切到其他文件目录,重新打开cmd窗口输入npm,你会发现npm也无法执行。
问题二 》》》 run
是哪里来的?
犹豫不决,先看官方文档,npm官方文档地址
问题二总结:(个人总结参考即可)
npm run
是npm自带的内置命令npm run
可以用来执行当前目录下package.json
中的scripts
对象中的属性对应的命令。npm run
后面没有加字符,那它会打印可执行的命令。- 除了可以打
run
,还可以敲rum, urn
功能是一样的。
问题三 》》》 serve
又是哪里来的?
由问题二的结论可以得知,serve
就是我们在package.json
中的scripts
对象中定义的属性名,我们执行npm run serve
其实就是在执行vue-cli-service serve
。
初始化好的vue2项目的配置文件
{
"name": "app",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-router": "^3.2.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.15",
"@vue/cli-plugin-router": "~4.5.15",
"@vue/cli-service": "~4.5.15",
"vue-template-compiler": "^2.6.11"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
问题四 》》》 衍生出来的问题vue-cli-service
哪里来的?
我在控制台直接输入命令vue-cli-service serve
直接报错。提示'vue-cli-service' 不是内部或外部命令,也不是可运行的程序或批处理文件。
为什么我通过 npm run serve
,可以执行 vue-cli-service serve
呢?
别慌继续看文档:
我用我9级英语意译一下:(ps 仅供参考)
In addition to the shell's pre-existing `PATH`,
// 除了预先已经存在于命令行中的 环境变量PATH
`npm run` adds `node_modules/.bin` to the `PATH` provided to scripts.
// 在 npm run 这个命令中 会将(./node_modules/.bin)这个目录也添加到环境变量Path中 给脚本使用
Any binaries provided by locally-installed dependencies can be used without the `node_modules/.bin` prefix.
// ./node_modules/.bin中的任何二进制文件都可以在,不拼接前缀`./node_modules/.bin`,供npm run使用。
我们去查看一下我们本地项目中的./node_modules/.bin
目录,确实存在vue-cli-service
可执行文件
所以我npm run serve
实际执行的是./node_modules/.bin
中的vue-cli-service.cmd
文件,即
npm run serve
↓
npm run ./node_modules/.bin/vue-cli-service serve
# 这里解释一下为什么有三个同名文件
# unix 系默认的可执行文件,必须输入完整文件名 vue-cli-service
# windows cmd 中默认的可执行文件,当我们不添加后缀名时,自动根据 pathext 查找文件 vue-cli-service.cmd
# Windows PowerShell 中可执行文件,可以跨平台 vue-cli-service.ps1
总结
-
npm
是cmd
窗口通过 环境变量Path中的路径 找到文件npm.cmd
文件并执行; -
run
是npm
自带的命令,支持运行package.json
中的scripts
对象的属性; -
同时
run
还会将./node_modules/.bin
中的可执行的文件,添加到 Path 中,从而可以不用添加前缀./node_modules/.bin
, 就给scripts
对象中的脚本中使用 -
serve
是package.json
中的scripts
对象的属性名。 -
有的依赖包会向
./node_modules/.bin
中写入可执行文件。 -
./node_modules/.bin
中文件名相同,但文件格式不同的可执行文件,是用来兼容不同系统的。
举一反三
- 我们全局安装的依赖会怎么样呢,我尝试了一下,全局安装的依赖会被安装在,nodejs安装的目录,部分插件也会生成以 .cmd 结尾的文件,例如vue-cli的脚手架;
-
其次,由上述内容我们可以知道 ,要卸载nodejs。除了在系统的控制面板卸载应用以外,Path中的环境变量也要清除,对应路径的软件包也要删除,才算卸载干净。
-
在执行npm run 的时候,我自己试验了一下,它会先在自身的
./node_modules/.bin
中的可执行文件匹配,如果没有匹配到,才会再去cmd环境中匹配。 -
其次我工作中,单一的
nodejs
版本并不适合所有业务需要,某些时候需要切换nodejs的版本用来维护不同的项目,所以就借用了工具nvm
切换和管理nodejs
版本。在我了解完node
和npm
这两个命令在cmd
中完整的执行过程之后,我去看了一下,我电脑的环境变量Path。又测试了一下,基本理解了nvm
的工作原理:
- 它会将一个文件夹路径A,写入到环境变量Path中,供
cmd
访问。- 每次切换nodejs版本的时候,它会把你设置的对应版本nodejs执行文件,拷贝到文件夹A中。
- 可以理解为每次切换nodejs版本的时候,其实就是不同版本的nodejs程序的复制粘贴。因为我们通过cmd使用nodejs都是访问路径A,所以路径A中的nodejs的版本是多少,我cmd中的node -v版本就是多少。
参考博客
end
- 其实写到这里 我就对这种
.cmd
结尾的文件是如何运行的,产生了浓厚的兴趣,后面一定了解了解,再做详细说明。 - 走了睡午觉去了。