我们会经常使用脚手架去创建我们的工程,比如用 @vue/ci 创建一个vue项目,我们会执行 vue create myProject来初始化工程,在使用脚手架之前会在全局安装 @vue/cli。
三个问题
1. 为什么全局安装 @vue/cli 后会添加的命令为 vue?
执行 yarn gloabl add @vue/cli 安装好 @vue/cli 后来查找一下 vue 被安装在了哪里?
ps: 不论是用yarn gloabl add 还是 npm i -g 安装,其原理都是大同小异。
huiazir@cuiwenhuideMacBook-Pro ~ % which vue
/usr/local/bin/vue
在我的电脑中 vue 被安装在了 /usr/local/bin 目录下,进入到这个目录。
huiazir@cuiwenhuideMacBook-Pro ~ % cd /usr/local/bin
huiazir@cuiwenhuideMacBook-Pro bin % ll
total 144600
drwxr-xr-x 14 root wheel 448 10 28 23:47 .
drwxr-xr-x 7 root wheel 224 10 8 23:58 ..
lrwxr-xr-x 1 root wheel 50 10 28 23:47 vue -> ../share/.config/yarn/global/node_modules/.bin/vue
.....
可以看到 vue 实际上是一个软链接,链接到了../share/.config/yarn/global/node_modules/.bin目录下,进入到这个目录。
huiazir@cuiwenhuideMacBook-Pro bin % cd ../share/.config/yarn/global/node_modules/.bin/
huiazir@cuiwenhuideMacBook-Pro .bin % ll
total 0
drwxr-xr-x 3 root wheel 96 10 28 23:47 .
drwxr-xr-x 603 root wheel 19296 10 28 23:47 ..
lrwxr-xr-x 1 root wheel 22 10 28 23:47 vue -> ../@vue/cli/bin/vue.js
这样我们就找到了 vue 是真实路径,在 ../@vue/cli/bin/vue.js,那么为什么全局安装 @vue/cli 后会添加的命令为 vue 呢? 进入到 vue 的安装目录,查看下 package.json
huiazir@cuiwenhuideMacBook-Pro .bin % cd ../@vue/cli
huiazir@cuiwenhuideMacBook-Pro cli % ll
total 24
drwxr-xr-x 9 root wheel 288 10 28 23:44 .
drwxr-xr-x 10 root wheel 320 10 28 23:44 ..
-rw-r--r-- 1 root wheel 1091 10 28 23:44 LICENSE
-rw-r--r-- 1 root wheel 106 10 28 23:44 README.md
drwxr-xr-x 3 root wheel 96 10 28 23:44 bin
drwxr-xr-x 22 root wheel 704 10 28 23:44 lib
drwxr-xr-x 7 root wheel 224 10 28 23:47 node_modules
-rw-r--r-- 1 root wheel 1707 10 28 23:44 package.json
drwxr-xr-x 5 root wheel 160 10 28 23:44 types
huiazir@cuiwenhuideMacBook-Pro cli % cat package.json
{
"name": "@vue/cli",
"version": "4.5.14",
"description": "Command line interface for rapid Vue.js development",
"bin": {
"vue": "bin/vue.js"
},
// ...
}
package.json中有一个bin 配置项,bin中的配置就是我们在操作系统中安装完成之后软链接的名称。
2. 全局安装 @vue/cli 时发生了什么?
在安装 @vue/cli 后,包会被安装到 /usr/local/share/.config/yarn/global/node_modules中(如果使用 npm 或者其他工具安装则会被安装在对应的目录),包完全安装完成之后,会去解析 package.json 中的 bin,如果发现 bin 下面有这样的一个配置,它就会在 node 的 bin 目录下 添加对应的软链接,这个软链接就会指向我们 bin 中配置的所指向的文件链接。
huiazir@cuiwenhuideMacBook-Pro node_modules % which vue
/usr/local/bin/vue
huiazir@cuiwenhuideMacBook-Pro node_modules % cd /usr/local/bin
huiazir@cuiwenhuideMacBook-Pro bin % ll
total 144600
drwxr-xr-x 14 root wheel 448 10 28 23:47 .
drwxr-xr-x 7 root wheel 224 10 8 23:58 ..
lrwxr-xr-x 1 root wheel 50 10 28 23:47 vue -> ../share/.config/yarn/global/node_modules/.bin/vue
huiazir@cuiwenhuideMacBook-Pro bin %
3. 执行 vue 命令时发生了什么?
直接执行vue命令和直接执行vue安装目录下面的vue是完全等价的。
huiazir@cuiwenhuideMacBook-Pro ~ % vue -V
@vue/cli 4.5.14
huiazir@cuiwenhuideMacBook-Pro ~ % /usr/local/bin/vue -V
@vue/cli 4.5.14
huiazir@cuiwenhuideMacBook-Pro ~ %
- 执行
vue命令的第一步其实就是在环境变量中查找vue命令是否被注册,所以我们执行一些没有注册过的命令就会提示command not found。 - 如果命令被注册,就会根据软链接一层一层的去找到其真实的可执行文件
/usr/local/share/.config/yarn/global/node_modules/@vue/cli/bin/vue.js。到这里可能就会有问,我们平时写.js文件要执行node xxx.js去执行,而在这里为什么不写node就可以执行了呢? 对于js文件来说,想要执行起来就必须需要一个解析器,这个解析器就是node,而我们在执行 vue 的时候,并没有写node,但是却被执行了,那么这个vue.js相比其他的js文件有什么不同呢?
huiazir@cuiwenhuideMacBook-Pro bin % vim vue.js
#!/usr/bin/env node
// Check node version before requiring/doing anything else
// The user may be on a very old node version
const { chalk, semver } = require('@vue/cli-shared-utils')
// ...
可以看到第一行有这么一段代码 #!/usr/bin/env node 这也是为什么我们不输入 node 就可以将这个文件执行起来的原因。
#!/usr/bin/env node这段代码的意思就是到环境变量中去找到node命令。 我们可以打印出环境变量
huiazir@cuiwenhuideMacBook-Pro bin % /usr/bin/env
TMPDIR=/var/folders/zr/7l4r5c0j5r5c2z9zmgnh_rfc0000gn/T/
__CFBundleIdentifier=com.apple.Terminal
XPC_FLAGS=0x0
TERM=xterm-256color
SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.dkdt2BPQPi/Listeners
XPC_SERVICE_NAME=0
TERM_PROGRAM=Apple_Terminal
TERM_PROGRAM_VERSION=440
TERM_SESSION_ID=1FEDBE07-AC77-4CAE-8280-0B703647303E
SHELL=/bin/zsh
HOME=/Users/huiazir
LOGNAME=huiazir
USER=huiazir
PATH=/usr/local/bin:/usr/local/mongodb/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin
SHLVL=1
PWD=/usr/local/share/.config/yarn/global/node_modules/@vue/cli/bin
OLDPWD=/usr/local/share/.config/yarn/global/node_modules/.bin
LANG=zh_CN.UTF-8
_=/usr/bin/env
node 命令就在环境变量PATH当中。找到node之后就会通过node解析器来执行文件。