前端脚手架基本原理

501 阅读5分钟

我们会经常使用脚手架去创建我们的工程,比如用 @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 下面有这样的一个配置,它就会在 nodebin 目录下 添加对应的软链接,这个软链接就会指向我们 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 ~ % 
  1. 执行 vue 命令的第一步其实就是在环境变量中查找 vue 命令是否被注册,所以我们执行一些没有注册过的命令就会提示command not found
  2. 如果命令被注册,就会根据软链接一层一层的去找到其真实的可执行文件 /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 就可以将这个文件执行起来的原因。

  1. #!/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解析器来执行文件。

4. 脚手架执行过程流程图