理解脚手架
我们对脚手架其实并不陌生,创建vue项目有其对应的脚手架:@vue/cli或者是使用vite的create-vue;react也有其对应的脚手架:create-react-app;
脚手架实际就是一个客户端工具,它帮助我们执行流程化的操作,来避免重复工作带来的耗时以提升工作效率,除此之外它还有很多其他价值:
- 自动化:项目重复代码拷贝/git操作/发布上线操作
- 标准化:项目创建/git flow/发布流程/回滚流程
- 数据化:研发过程数据化、系统化,使得研发过程可量化
从使用角度理解脚手架
我们从创建vue项目最常用的@vue/cli脚手架的命令:vue create project
入手。
这条看似简单常见的命令实际上由3个部分组成:
- 主命令:vue
- command:create
- command的param:project,这条命令大家应该都很常见了,它表示创建一个vue项目,项目的名字叫project。
执行原理
在控制台输入vue create project
命令后发生了什么?
- 查找vue环境变量:首先会查看电脑中是否存在vue环境变量,如果你没有安装@vue/cli,控制台会提示vue command不存在。安装以后其实通过类似which vue指令查找vue脚手架在全局的安装目录(/opt/homebrew/bin/vue,ps:也有可能在安装node目录下的bin/vue,这取决于你安装脚手架的方式),但这个路径指向的其实是一个软连接(可以理解为window操作系统的快捷方式)。
- 查找上述软连接指向的真正的执行文件的位置:
/opt/homebrew/lib/node_modules/@vue/cli/bin/vue.js
,执行vue.js文件,其中会解析create命令和project参数,并执行对应的代码。PS:是在bin同级目录lib文件夹中,这里是存放源码的位置。然后执行vue.js文件
总结:
- 在终端输入vue create project
- 终端解析出vue
- 在环境变量中找到vue命令
- 终端根据vue命令链接到实际文件vue.js
- 终端利用node执行vue.js
- vue.js解析command/options(create project)
- vue.js执行command(create)
- 执行完毕,退出执行
一些疑惑
全局安装@vue/cli发生了什么
- 将@vue/cli下载到全局的/lib/node_modules目录下。
- 解析@vue/cli的package.json文件中的bin配置项,在全局/bin目录下创建一个软连接,该软连接指向bin配置项的值的位置。
为什么安装了@vue/cli脚手架就能使用vue命令,不能是其他的吗?
其实是该项目的package.json文件中有这样的配置
{
"bin": {
"vue": "bin/vue.js"
},
}
所以开发自己的脚手架时完全可以自定义脚手架的使用命令。
为什么vue.js会执行,好像也没有调用node vue.js命令
关键在于vue.js文件中的第一行代码:#!/usr/bin/env node
,如果你在控制台直接执行/usr/bin/env命令可以看到打印的是所有的环境变量,那么#!/usr/bin/env node
的意思就是找到node命令然后去执行本文件,等价于node xxx.js
。如果你了解Python,在Python脚本文件的第一行也可能会有一行#!/usr/bin/env python
命令,他们的原理都是一样的。
如果对#!/usr/bin/env node
命令感兴趣,你完全可以自己随便创建一个js文件,然后第一行添加上#!/usr/bin/env node
,再随便写一些测试代码,直接在控制台输入js文件的路径,你就会发现文件直接执行了。PS:如果遇到permission denied,可以使用chmod +x xxx.js
命令为你的执行文件增加权限后再运行。
为什么说脚手架本质是操作系统的客户端?它和我们在PC上安装的应用/软件有什么区别?
1.node在window中是一个node.exe,在Mac中是一个可执行文件(node*),因为node是操作系统的一个客户端,脚手架的本质是通过node去执行js文件,所以也可以说脚手架的本质是操作系统的客户端。
2.本质来说没有区别,PC安装的应用只是提供了一个GUI,脚手架是通过命令的形式
自研脚手架和自动化构建工具的区别
市面上已经有了如Jenkins,travis等自动化构建工具,我们为什么还要自研脚手架?
- 不满足需求:jenkins/travis通常需要在git hooks中触发,在服务端执行,无法覆盖研发人员本地的功能,如创建项目自动化,git操作自动化
- 定制复杂:jenkins/travis等工具的定制过程需要开发插件,要用到Java语言,对前端开发人员并不友好
如何开发一个脚手架
- 新建一个文件夹(项目)使用npm进行初始化,打开package.json 配置bin字段,创建一个命令,指向bin/index.js;
- 将这个项目发布到npm;
- 全局安装这个脚手架;
- 使用第一步中bin字段中配置的命令来使用脚手架即可,会执行bin指向的那个js文件(别忘了增加
#!/usr/bin/env node
)。
脚手架本地link标准流程(调试)
脚手架开发通常是多个包同时管理,除了脚手架项目本身,还需要分其他的包来实现不同的功能,因此本地调试变得很重要,下面是常用的一些指令:
链接本地脚手架:
cd your-cli-dir
npm link
使用link链接到全局后,可以使用npm remove -g移除对应的命令
链接本地库文件:
cd your-lib-dir
npm link
cd your-cli-dir
npm link your-lib
取消链接本地库文件:
cd your-lib-dir
npm remove -g
cd your-cli-dir
# link存在
npm unlink your-lib
# link不存在
rm -rf node_modules
npm install -S your-lib
理解npm link:
- npm link your-lib:将当前项目中的node_modules下指定的库文件链接到node全局node_modules下的库文件
- npm link:将当前项目链接到node全局node_modules中作为一个库文件,并解析bin配置创建可执行文件
理解npm unlink:
- npm remove -g:将当前项目从node全局node_modules中移除
- npm unlink your-lib:将当前项目中的库文件依赖移除
脚手架开发难点解析
- 分包:将复杂的系统拆分成若干个模块
- 命令注册:
vue create
vue add
vue invoke
- 参数解析:
vue command [options] <params>
- help信息:包括全局help和命令help信息
- 命令行交互
- 日志打印
- 命令行文字变色
- 网络通信:HTTP、WebSocket
- 文件处理
- 等等..
原生脚手架开发痛点分析
- 痛点一:重复操作
-
- 多Package本地link
- 多Package依赖安装
- 多Package单元测试
- 多Package代码提交
- 多Package代码发布
- 痛点二:版本一致性
-
- 发布时版本一致性
- 发布后相互依赖版本升级
package越多,管理复杂度越高,所以需要一个多包管理工具来管理我们的项目,下个章节会带大家认识lerna的使用和原理。