详解前端脚手架(一):脚手架的执行原理和实现原理
前端开发人员在入门时,总会听到一个术语“脚手架”。不知道大家是不是和我一样,对于此术语总是一知半解,即便百度后也没有完全搞懂到底啥是脚手架。或许在学过react、vue后会说,噢,类似于create-react-app的就是脚手架,但要说一下具体的含义也说不出个细节。今天我们就详细切入脚手架,了解什么是脚手架,为什么需要脚手架。以及脚手架的开发。
我们在学习过程中,以vue
的脚手架@vue/cli
为实际例子,如果有不了解的,点击此处进行了解
什么是脚手架?
什么是脚手架?脚手架本质是开发人员的一个操作系统的客户端工具。它通过命令行执行。
比如vue的命令:
vue create vue-test-app
这条命令由三部分构成:
- 主命令:vue
- 子命令command:create
- command的param参数:vue-test-app
它表示创建一个 vue 项目,项目的名称为 vue-test-app,以上是最一个较为简单的脚手架命令,但实际场景往往更加复杂,比如当前目录已经有文件了,我们需要覆盖当前目录下的文件,强制进行安装vue项目,此时我们就可以输入:
vue create vue-test-app --force
这里的 --force
叫做 option,用来辅助脚手架确认在特定场景下用户的选择(可以理解为配置)。还有一种场景:
通过 vue create
创建项目时,会自动执行 npm install
帮用户安装依赖,如果我们希望使用淘宝源来安装,可以输入命令:
vue create vue-test-app --force -r https://registry.npm.taobao.org
这里的 -r
也叫做 option,它与 --force
不同的是它使用 -
,并且使用简写,这里的 -r
也可以替换成 --registry
,这些命令怎么得知?其实我们输入下面的命令就可以看到 vue create
支持的所有 options:
vue create --help
-r https://registry.npm.taobao.org
后面的 https://registry.npm.taobao.org
成为 option 的 param,其实 --force
可以理解为:--force true
,简写为:--force
或 -f
为什么需要脚手架?
站在前端研发的视角,为什么我们需要开发脚手架?脚手架能给我们带来什么价值
脚手架是实现前端自动化的关键工具。在脚手架中,可自由置入多种功能,保障代码的安全性、规范性,提高开发效率。研究学习脚手架,是前端提效的核心抓手。即,开发脚手架的核心目标是:提升前端研发效能。
研发提效
脚手架能够帮助团队从哪里进行提效?在公司内,我们会有多个前端子团队,也会有多个前端项目。但不论这些前端项目是哪种类型,小程序也好H5也好,它们都有一些操作是共通的。这些操作可以分为三个大类:创建项目+通用代码、git操作、构建+发布上线。
在创建项目过程中会有大量的通用代码,比如resetCss。我们每创建一个项目都需要拷贝一份resetCss,那这个工作量可想而知。除此之外,公司特有的埋点方案、技术最终选型的HTTP请求方案(比如将请求封装为react的api中间件)、常用工具方法、业务组件库和通用组件库。这些内容都是在创建项目时就可以固化好的,我们将这些集成到我们的项目模板中,在创建项目时就固化好,就已经能够为我们节省大量人力。
而在git操作中,每个项目都要经历创建项目、解决冲突、远程代码同步、创建版本、发布打tag等等一系列git操作。而在这些操作上总是会耗费开发人员时间和精力,同时新人会面临操作失误的可能。更别提更为复杂的git reset操作、git flow流程要求。而在各个公司内,对git的管理可能各有流程制度要求,在多人开发下,就算我们的流程制度要求再详细再精确,也有也可能出现git管理失误。如果能够把这一系列git操作自动化,那么势必能够节约前端开发大量的时间,并且减少git出错风险。
最后是构建和发布上线。对于前端项目来说,构建和发布上线还是较为麻烦的。包括依赖安装和构建、资源上传cdn、域名绑定、测试/正式服务器区分等等。如果我们一直保持前端开发人员手工操作的情况,那么可能每次上线都要耗费开发10~20分钟时间。
所以开发脚手架,能够带来的研发效能提升是非常明显的。
脚手架核心价值
在研发提效的基础上,脚手架还能给我们带来以下价值:
- 自动化:项目重复代码拷贝/git操作/发布上线操作,实现自动化操作,减少人工操作风险
- 标准化:项目创建/git flow/发布流程/回滚流程,实现多个团队各个项目的一系列技术流程、技术操作标准化
- 数据化:研发过程系统化,数据化,使得研发过程可量化。比如新建项目的时间,我们可以通过脚手架工具实现其可统计为时间指标,有了指标就能够进一步为我们后续的脚手架迭代带来方向和目标。
和自动化构建工具的区别
jenkins等自动化构建工具已经非常成熟,为什么还需要自研脚手架?
- 不满足需求:jenkins通常在git hook中触发,需要在服务端执行,无法覆盖研发人员本地的功能。如创建项目自动化、本地git操作自动化等。而脚手架本身则是一个客户端。
- 定制复杂:Jenkins定制过程需要开发插件,过程复杂,语言为java,对前端开发不够友好。
脚手架的执行原理
脚手架的执行原理如下:
- 终端输入
vue create vue-test-app
- 终端解析出
vue
主命令 - 终端在环境变量中找到
vue
命令 - 终端根据
vue
命令链接到实际可执行文件vue.js - 终端利用node执行vue.js
- vue.js解析command和option
- vue.js执行command
- 执行完毕,退出执行
具体执行过程的分析,可以见下一节“实现原理”。里面有详细分析。
脚手架的实现原理
要了解脚手架的实现原理,核心需要掌握以下三个问题
- 为什么全局安装
@vue/cli
后会添加的命令为vue
?即执行命令npm i -g @vue/cli
- 全局安装
@vue/cli
时发生了什么? - 执行
vue
命令是发生了什么,为什么vue
指向了一个js文件,我们却可以直接通过vue
命令去执行它?
这里我们来一一深入研究
问题一
首先,我们可以先研究vue
命令的实际执行文件在哪里。终端上执行命令
which vue
which指令会在PATH环境变量指定的路径中,搜索某个系统命令的位置,并且返回第一个搜索结果。
可以看到,命令返回了一个本地的bin目录。bin标识可执行文件,所以bin文件夹里均为可执行文件。随后我们进入此目录,ll
命令查看文件信息
可以看到vue
文件事实上是一个软连接,类似于windows系统的快捷方式。它实际指向了另外一个地址下的vue.js文件。而在文件开头的lrwxr-xr-x
的l
也是link的意思,意味着这是一个软连接。
我们再进入这个实际js文件的地址,
那么,我们之前所说到的第一个问题:为什么全局安装@vue/cli
后会添加的命令为vue
?即vue命令和vue.js的绑定关系是在哪里指定的呢?我们在当前目录向上一级,就可以看到这个目录就是@vue/cli
的安装目录
在这个目录下有一个package.json
,我们查看此文件,就能看见红框中的配置
210511-5.png
而红框中的bin
里的内容,就是我们在操作系统安装@vue/cli
之后配置的软连接的名称和实际指向的文件。这就解答了我们的第一个问题。
问题二
全局安装@vue/cli
时发生了什么?
其实从刚才的分析中我们已经能够整理出具体的流程:
当我们执行安装语句时,首先node会将@vue/cli
的安装包下载到node_modules文件夹。上图中蓝色地址框也有显示具体地址。当下载完成后,会进一步解析package.json文件中的bin配置,如果bin中有配置,就会在最初的bin目录下创建一个软连接,软连接指向实际文件。
问题三
执行vue
命令是发生了什么,为什么vue
指向了一个js文件,我们却可以直接通过vue
命令去执行它?
首先,通过上面的流程分析,我们在执行vue命令时,首先会在环境变量中检查vue命令是否被注册。随后发现vue命令被注册,即之前所说的软连接指向的vue.js文件。那么,在执行vue命令时,即直接执行了vue.js文件。
但为什么vue.js文件能够直接被执行呢?我们自己随便写个js的helloworld,直接运行是会报错的。因为js文件必须要通过一个解释器——node来执行。
但是很明显我们在执行vue时没有加node,那么vue.js是怎么执行的呢?我们看一下vue.js的源码
可以看到,源码第一行有这么一段代码:
#!/usr/bin/env node
当我们把这行代码放在自己写的js文件后,能够发现,该js文件无需调用node也能够直接执行。
这句代码就能够告诉操作系统,在执行这个文件时,到环境变量中找node命令,并通过node命令去执行。
即加入了这句话后,执行vue命令相当于执行node vue.js。
而之所以通过环境变量而非实际node目录地址,是因为不同的电脑node安装目录可能不一致,因此为了保障可靠性,通过环境变量进行调用是最好的。
一些其他内容:
如果我们想要自己也能够通过一个简单快捷的命令调用自己写的js文件,应该如何做?
其实也很简单,定义软连接即可。
首先通过echo $PATH
找到所有的环境变量,在其中某个bin目录下创建一个软连接指向我们的js目录即可。注意,js文件要加上#!/usr/bin/env node
。
软连接指令为ln -s 文件实际地址 命令名称
这也是我们自己开发脚手架的一个核心原理。