前言
以vue create xxx
命令为入口,探索脚手架背后的原理。常见经典的面试题:《当我们在终端输入vue create xxx创建项目时,发生了什么?》
,要搞清楚这个问题,就需要了解脚手架命令执行的过程。
开始
首先全局安装@vue/cli
cmd
npm install @vue/cli -g
创建项目
cmd
vue create vue-demo
此时,就会执行对应的命令开始创建项目了,我们将这段语句分为三段
vue
代表了主命令
create
代表了command
子命令,也可以理解为是一个动作vue-demo
代表了command的param
,就是对应子命令的参数
说到这里,其实我们npm install @vue/cli -g
也是可以按照这个规律去拆解
npm
主命令install
子命令@vue/cli
子命令参数-g
这里叫做option
,可以理解为配置。它是--global
的简写,所以全拼时是两条杠--global
,简写是一条杠-g
,常见的还有:--help/-h
或者--version/-v
等
那为什么我们在终端输入vue
或者npm
等命令时,终端可以识别的出来呢?
为什么终端认识vue命令
我们可以通过which
命令来找到vue
命令(实际这里是注入到了全局环境变量中)执行脚本的位置
cmd
which vue
要想知道有什么包注入了环境变量,我们先看一下全局安装了什么包:
cmd
npm list -g -deptch -0
以下是我装的全局npm
包 这些包都可以通过which
命令来查看:
所以可以用一句话概括就是:在终端输入vue
时,终端去寻找注入的全局环境变量,找到之后,执行其对应所在环境变量的脚本位置。 我这里对应的就是:
cmd
/Users/fengxiaodong/.nvm/versions/node/v18.16.0/bin/vue
那有的同学会疑问,为什么全局安装的是@vue/cli
,但是却添加的命令是vue
呢?这个问题我们留到后面解释。
vue脚本
我们进入vue
脚本位置的目录,这里是所有全局npm
包的命令目录,都被放在了bin
文件夹下 除了vue
命令外,还可以看到其他的命令,如上面提到的npm
和pnpm
命令。
cmd
lrwxr-xr-x 1 fengxiaodong staff 39B 1 20 18:21 vue -> ../lib/node_modules/@vue/cli/bin/vue.js
通过上面这条信息,我可以得出以下结论:
vue
命令执行的是:../lib/node_modules/@vue/cli/bin/vue.js
脚本- 通过软链接的方式执行,因为前面有
lrwxr-xr-x
标识
回到上层目录中,进一步分析得出:
- 我们的
npm
包都被安装在对应的node
版本目录下(v.18.16.0
) bin
目录是全局命令所在的文件夹目录lib
目录是全局命令执行的软链接对应的文件的目录(全局包安装的真实位置)
我们通过vscode
查看这个目录位置,找到了脚本文件vue.js
最终结论,我们可以用一张图概括:
- 在终端输入
vue
命令 - 在环境变量中找到了
vue
命令 - 终端根据
vue
命令链接到实际文件vue.js
- 终端利用
node
执行vue.js
vue.js
解析command
和option
vue.js
执行command
- 执行完毕,创建项目,退出执行
这里除了上面留下的疑问:为什么全局安装@vue/cli
后却添加了vue
命令;我们又多了一个疑问:为什么vue
命令指向一个js
文件,我们却可以直接通过vue
去执行它?
为什么全局安装@vue/cli添加的却是vue命令?
前面内容已经介绍过,可以通过vscode
打开vue.js
,实际就是在node_modules
下安装的@vue/cli
目录,打开package.json
,就可以看到bin
的配置
bin
字段就是用来指定各个内部命令对应的可执行文件的位置 ,这里写的是vue
,对应的文件就是bin/vue.js
。所以这就是为什么安装了@vue/cli
,却添加的是vue
命令的原因,如果我写的是:
json
{
haha: 'bin/vue.js'
}
那么添加的就是haha
命令,初始化项目可能就变成了:
cmd
haha create xxx
总结一下:当全局安装@vue/cli
时,首先会把这个这个npm
包下载到当前node
版本的lib/node_modules
目录下,同时如果配置了bin
,那么则会在当前node
版本的bin
目录下创建一个软链接,指向这个lib
目录中配置的文件vue.js
,所以这个关系就理清楚了。
为什么vue命令指向一个js文件,却可以通过vue去执行它?
我们都知道,正常运行某个.js
文件可以通过node xxx.js
执行,利用的就是node
解析器的能力,所以理论上应该是node vue.js
才对,那为什么可以用的却是vue
呢?
我们在终端输入vue
,会得到脚手架的信息
这个结果跟直接执行which vue
的路径是一样的
所以执行vue
命令时,首先去环境变量中找到vue
是否被注册;输入一个不存在的命令,则会提示command not found
但我们都知道which vue
的路径不是真实的路径,只是一个软链接,真实的脚本文件是:vue.js
进入这个文件,可以发现这段语句(#!/usr/bin/env node
),这个的作用是什么呢?
我们正常来说,自己的文件是没办法直接在终端上执行的,例如现在有一个haha.js
随意输入一段代码
执行这个文件,会显示没有权限,因为只有可读
通过chmod 777 haha.js
添加可写权限
但是直接执行这个文件,还是无法输出,必须使用node
去执行
但是如果在这个文件上方加入了这段代码:#!/usr/bin/env node
我们就可以直接执行文件了
其实这等同于使用 /usr/bin env node ./haha.js
所以这三个方式的执行结果都是一样的
- 使用
node
执行haha.js
- 在
haha.js
里面写入#!/usr/bin/env node
后直接执行 - 使用
/usr bin/env node
执行haha.js
那么/usr/bin/env
是什么呢?在终端输入这段语句,得到的是全部的环境变量信息
而/usr/bin/env node
则表示使用环境变量中node
变量,所以上面总结的三种方式实际上都是使用node
去执行这个文件
但是目前只能直接执行haha.js
,而不是通过haha
命令去执行,如果想和直接输入vue
一样直接执行vue.js
,是如何做到的呢?
我们期望直接输入haha
就可以执行haha.js
,这个时候就需要去创建软链接了,我们回到当前node
版本的bin
目录
通过ln -s
的方式创建软链接
这样就成功的创建了一个软链接了
我们去到任意目录,输入haha
,都可以成功执行vue-demo/haha.js
文件了
总结一下:为什么vue
命令指向的是vue.js
文件,却可以通过vue
去执行?原因就是因为,vue
命令在bin
目录下存在软链接地址,且这个地址的执行文件vue.js
中有这段代码:#!/usr/bin/env node
,所以在终端输入vue
时,是使用环境变量node
去执行了vue.js
总结
整篇文章介绍了@vue/cli
从安装到执行的背后原理,理解这个背后原理对我们日后写脚手架有很大的帮助,感谢您的阅读。