详解前端脚手架(一):脚手架的执行原理和实现原理

前端开发人员在入门时,总会听到一个术语“脚手架”。不知道大家是不是和我一样,对于此术语总是一知半解,即便百度后也没有完全搞懂到底啥是脚手架。或许在学过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环境变量指定的路径中,搜索某个系统命令的位置,并且返回第一个搜索结果。

210511-1.png

可以看到,命令返回了一个本地的bin目录。bin标识可执行文件,所以bin文件夹里均为可执行文件。随后我们进入此目录,ll命令查看文件信息

210511-2.png

可以看到vue文件事实上是一个软连接,类似于windows系统的快捷方式。它实际指向了另外一个地址下的vue.js文件。而在文件开头的lrwxr-xr-xl也是link的意思,意味着这是一个软连接。

我们再进入这个实际js文件的地址,

210511-3.png

那么,我们之前所说到的第一个问题:为什么全局安装@vue/cli后会添加的命令为vue?即vue命令和vue.js的绑定关系是在哪里指定的呢?我们在当前目录向上一级,就可以看到这个目录就是@vue/cli的安装目录

210511-4.png

在这个目录下有一个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的源码

210511-6.png

可以看到,源码第一行有这么一段代码:

#!/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 文件实际地址 命令名称
这也是我们自己开发脚手架的一个核心原理。

 关于setState是异步还是同步
详解DOCTYPE 
上一篇:关于setState是异步还是同步
下一篇:详解DOCTYPE


如果我的文章对你有帮助,或许可以打赏一下呀!

支付宝
微信
QQ