首页
学习
活动
专区
圈层
工具
发布
50 篇文章
1
【架构师(第一篇)】整体需求分析和架构设计
2
【架构师(第二篇)】脚手架架构设计和框架搭建
3
【架构师(第三篇)】脚手架开发之掌握Lerna操作流程
4
【架构师(第四篇)】脚手架开发之Lerna源码分析
5
【架构师(第五篇)】脚手架之import-local执行流程及简历设计
6
【架构师(第六篇)】脚手架之需求分析和架构设计
7
【架构师(第七篇)】脚手架之准备阶段编写
8
【架构师(第八篇)】脚手架之 commander 框架使用方法
9
【架构师(第九篇)】如何让 Node 环境支持 ES Module
10
【架构师(第十篇)】脚手架之注册命令及架构优化
11
【架构师(第十一篇)】脚手架之命令注册和执行过程开发
12
【架构师(第十二篇)】脚手架之命令行交互工具 inquirer.js 使用方法
13
【架构师(第十三篇)】脚手架之创建项目准备阶段开发
14
【架构师(第十四篇)】脚手架之 egg.js 和 mongodb 的使用
15
【架构师(第十五篇)】脚手架之创建项目模板开发
16
【架构师(第十六篇)】脚手架之创建项目模板的下载与更新
17
【架构师(第十七篇)】脚手架之 ejs 和 glob 的使用
18
【架构师(第十八篇)】脚手架之项目模板的安装
19
【架构师(第十九篇)】脚手架之组件库模板开发
20
【架构师(第二十篇)】脚手架之自定义模板及第一阶段总结
21
【架构师(第二十一篇)】编辑器开发之需求分析和架构设计
22
【架构师(第二十二篇)】编辑器开发之项目整体搭建
23
【架构师(第二十三篇)】编辑器开发之画布区域组件的渲染
24
【架构师(第二十四篇)】编辑器开发之添加模版到画布
25
【架构师(第二十五篇)】编辑器开发之属性编辑区域表单渲染
26
【架构师(第二十六篇)】编辑器开发之属性编辑同步渲染
27
【架构师(第二十七篇)】前端单元测试框架 Jest 基础知识入门
28
【架构师(第二十八篇)】 测试工具 Vue-Test-Utils 基础语法
29
【架构师(第二十九篇)】Vue-Test-Utils 触发事件和异步请求
30
【架构师(第三十篇)】Vue-Test-Utils 全局组件和第三方库 vuex | vue-router
31
【架构师(第三十一篇)】前端测试之 TDD 的开发方式
32
【架构师(第三十二篇)】 通用上传组件开发及测试用例
33
【架构师(第三十三篇)】 Vue 中的实例及本地图片预览
34
【架构师(第三十四篇)】 业务组件库开发之 vue3 的插件系统
35
【架构师(第三十五篇)】 业务组件库开发之使用 Rollup 进行打包
36
【架构师(第三十六篇)】 业务组件库开发之发布到 NPM
37
【架构师(第三十七篇)】 服务端开发之后端框架与数据库技术选型
38
【架构师(第三十八篇)】 服务端开发之本地安装最新版 MySQL 数据库
39
【架构师(第三十九篇)】 服务端开发之连接 MySQL 数据库
40
【架构师(第四十篇)】 服务端开发之连接 Mongodb 数据库
41
【架构师(第四十一篇)】 服务端开发之安装并连接 Redis数据库
42
【架构师(第四十二篇)】 服务端开发之常用的登录鉴权方式
43
【架构师(第四十三篇)】 服务端开发之单元测试和接口测试
44
【架构师(第四十四篇)】 服务端开发之 pm2 和 nginx 介绍
45
【架构师(第四十五篇)】 服务端开发之认识 Github actions
46
【架构师(第四十六篇)】 服务端开发之安装 Docker
47
【架构师(第四十七篇)】 服务端开发之认识 Docker
48
【架构师(第四十八篇)】 服务端开发之 Dockerfile
49
【架构师(第四十九篇)】 服务端开发之认识 Docker-compose
50
【架构师(第五十篇)】 服务端开发之自动发布到测试机
清单首页架构文章详情

【架构师(第二篇)】脚手架架构设计和框架搭建


脚手架架构设计和框架搭建

将收获什么

  • 脚手架的实现原理
  • Lerna 的常用方法
  • 架构设计技巧和架构图绘制方法

主要内容

  • 学习如何以架构师的角度思考基础架构问题
  • Package 项目管理痛点和解决方案,基于 Lerna 脚手架框架搭建
  • 脚手架需求分析和架构设计,架构设计图
  • 脚手架调试技巧
  • Lerna 源码分析
  • nodemodule 模块分析
  • yargs 使用方法
  • 剖析 Lerna 架构设计

开发脚手架的必要性

开发脚手架的核心目标是:提升前端研发效能

以下内容如果全靠脚手架进行自动化处理,可以提高相当大的研发效率了。

创建项目 + 通用代码

  • 埋点
  • http 请求
  • 工具方法
  • 组件库

git 操作

  • 创建仓库
  • 代码冲突
  • 远程代码同步
  • 创建版本
  • 发布打 tag

构建 + 发布上线

  • 依赖安装和构建
  • 资源上传 cdn
  • 域名绑定
  • 测试/正式服务器

脚手架核心价值

将研发过程

  • 自动化:项目重复代码拷贝、git 操作、发布上线操作
  • 标准化:项目创建、git flow、发布流程、回滚流程
  • 数据化:研发过程系统化、数据化、使得研发过程可量化

和自动化构建工具的区别

问题:jenkinstravis 等自动化构建工具已经很成熟了,为什么还要自研脚手架?

  • 不满足需求:jenkinstravis 通常在 git hooks 中触发,需要在服务端执行,无法覆盖研发人员本地的功能,如:创建项目自动化,本地 git 操作自动化等。
  • 定制复杂: jenkinstravis 定制过程需要开发插件,其过程较为复杂,需要使用 java 语言,对前端同学不太友好。

什么是脚手架

脚手架本质是一个操作系统的客户端,他通过命令行执行,比如

代码语言:javascript
复制
vue create vue-test-app

上面这条命令由 3 个部分组成:

  • 主命令vue
  • commandcreate
  • command 的 paramvue-test-app

他表示创建一个 vue 项目,项目的名称为 vue-test-app,这是一个比较简单的脚手架命令,但实际场景往往更加复杂,比如:

当前目录已经有文件了,我们需要覆盖当前目录的文件,强制进行安装 vue 项目,此时我们就可以输入

代码语言:javascript
复制
vue create vue-test-app --force

这里的 --force 叫做 option ,用来辅助脚手架确认在特定场景下用户的选择(可以理解为配置)。还有一种场景:

通过 vue create 创建项目时,会自动执行 npm install 帮助用户安装依赖,如果我们希望使用淘宝源来安装,可以输入命令

代码语言:javascript
复制
vue create vue-test-app --force -r https://registry.npm.taobao.org

这里的 -r 也叫做 option,它与 --force 不同的是它使用 - ,并且使用简写,这里的 -r 也可以替换成 --registry,输入下面的命令就可以看到 vue create 支持的所有 options

代码语言:javascript
复制
vue create --helps

-r 后面的 https://registry.npm.taobao.org 成为 optionparam ,其实 --force 可以理解为:--force true ,简写为 --force-f

脚手架的执行原理

脚手架执行原理如下

  • 在终端输入vue create project
  • 终端解析出 vue
  • 在环境变量中通过 which vue 找到 vue 命令, 目录所在 /node/bin/vue,所以我们执行的 vue,实际上运行的是/node/bin/vue 的这个 vue
  • 这个 vue 只是一个链接,终端根据 vue 命令链接到实际文件 /node/lib/node_modules/@vue/cli/bin/vue.js
  • 终端利用 node 执行 vue.js
  • vue.js 解析 command 以及 param
  • vue.js 执行 command
  • 执行完毕,退出执行

如何开发一个脚手架

以 vue-cli 为例

  • 开发一个 npm 项目,该项目中应包含一个 bin/vue.js 文件,并将这个项目发布到 npm
  • 将这个项目发布到 npm
  • 将 npm 项目上的项目全局安装到 node 的 lib/node_modules
  • 在 node 的 bin 目录下配置 vue 软链接指向 lib/node_modules/@vue/cli/bin/vue.js

这样我们在执行 vue 命令的时候就可以找到 vue.js 进行相关操作。

脚手架实现原理问题

为什么全局安装 @vue/cli 后会添加一个 vue 的命令呢?

代码语言:javascript
复制
npm i -g @vue/cli

运行 vue 命令时,实际走的是 node/bin/vue ,而这个文件只是一个软连接,指向lib/node_modules/@vue/cli/bin/vue.js

回到上级目录 lib/node_modules/@vue/cli,打开 package.json 文件,里面的 bin 字段定义了这样的绑定关系。

代码语言:javascript
复制
// lib/node_modules/@vue/cli/package.json
{
  "bin": {
    "vue": "bin/vue.js"
  },
}

总结:执行 vue 命令的时候,启动的是 bin/vue 这个文件,而这个文件指向lib/node_modules/@vue/cli/bin/vue.js ,所以最终启动的是 lib/node_modules/@vue/cli/bin/vue.js

全局安装 @vue/cli 的时候发生了什么?

  • @vue/cli 的包通过 npm 安装到 node/lib/node_modules 这个目录下。
  • 解析 package.json 文件 ,根据文件中的 bin 字段,在 /node/bin 目录下创建软连接,软连接指向 bin 字段中规定的文件,也就是 lib/node_modules/@vue/cli/bin/vue.js

执行 vue 命令时发生了什么?

  • 根据 which vue 这条指令(在环境变量中查找),找到 vue 命令所在文件
  • 运行这个文件,执行 vue 和执行 node/bin/vue 的结果是一样的
  • 根据软连接,执行真实的 lib/node_modules/@vue/cli/bin/vue.js 文件

为什么 vue 指向一个 js 文件,我们却可以直接通过 vue 命令去执行它?

查看 lib/node_modules/@vue/cli/bin/vue.js 文件的源码,会发现第一行代码是这样的

代码语言:javascript
复制
#!/usr/bin/env node

它的意思就是在环境变量中查找使用 node 命令来运行此文件。

为什么说脚手架本质是操作系统的客户端?

因为 node 本身是一个客户端,在 windows 系统下,可以看到 node 的安装目录中,node 是以 node.exe 的形式出现的。

而我们编写的脚手架文件,如 vue.js 只是 node 运行时的一个参数。

代码语言:javascript
复制
node vue.js

如何为 node 脚手架创建别名?

软连接是可以嵌套的,只需让别名指向原来的名字即可。

脚手架执行的全过程

脚手架开发流程

开发流程

  • 创建 npm 项目
  • 创建脚手架入口文件,最上方添加 #!/usr/bin/env node
  • 配置 package.json 文件,添加 bin 属性,指定脚手架名称和入口文件地址
  • 编写脚手架代码
  • 将脚手架发布到 npm

使用流程

  • 安装脚手架
代码语言:javascript
复制
npm i -g @vue/cli
  • 使用脚手架
代码语言:javascript
复制
vue create project

脚手架开发难点

  • 分包:将复杂的系统拆分成多个模块
  • 命令注册
  • 参数解析
  • 帮助文档
  • 命令行交互
  • 日志打印
  • 命令行文字变色
  • 网络通信:HTTP/WebSocket
  • 文件处理
  • ... ...

开发一个简单的脚手架

  • 新建文件夹 test-cli
代码语言:javascript
复制
mkdir test-cli
  • 进入到 test-cli ,- 初始化 npm 包,通过 code . 可以快速使用 vscode 打开当前文件夹。
代码语言:javascript
复制
cd test-cli
npm init -y
code .
  • 添加 bin/index.js 文件,内容如下
代码语言:javascript
复制
// bin/index.js

#!/usr/bin/env node

console.log('🚀🚀~ 脚手架开发 测试');
  • 修改 package.json 文件,添加 bin 属性,指定脚手架名称和入口文件地址
代码语言:javascript
复制
// package.json
{
  "name": "test-cli-0174",
  "version": "1.0.0",
  "description": "",
  "bin": {
    "test-cli": "bin/index.js"
  },
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
  • 发布包到 npm

👉👉 从0到1发布属于自己的库到npm

  • 全局安装
代码语言:javascript
复制
npm i -g test-cli
  • 命令行执行命令 test-cli

结果如下,控制台输出 🚀🚀~ 脚手架开发 测试

调试本地脚手架

进入到 test-cli 目录中

先全局移除之前通过 npm 安装的包,然后执行 npm link

代码语言:javascript
复制
npm remove test-cli -g
npm link

就会安装本地的脚手架了

随便修改本地代码后,然后再通过命令 test-cli 去启动脚手架

如果工程很复杂需要分包

test-cli 目录同级新建一个 test-cli-lib 目录,同样进行初始化。

代码语言:javascript
复制
npm init -y

然后新建 lib/index.js 文件,写上一个方法。

代码语言:javascript
复制
// lib/index.js
module.exports = {
  sum(a, b) {
    return a + b
  }
}

修改 package.json 文件中的 main 属性

代码语言:javascript
复制
 "main": "lib/index.js",

进入 test-cli-lib 目录 , 执行 npm link ,把这个包也安装到本地。

返回 test-cli 目录, 执行

代码语言:javascript
复制
npm link test-cli-lib

然后手动的修改 package.json 文件中的 dependencies 属性

代码语言:javascript
复制
  "dependencies": {
    "test-cli-lib"
  }

就可以把这个包连接起来了,然后再修改本地代码测试一下。

代码语言:javascript
复制
// test-cli/bin/index.js
#!/usr/bin/env node

const lib = require("test-cli-0174-lib")
console.log(lib);
console.log('🚀🚀~ 本地脚手架开发 测试!!!!');

运行 test-cli 命令

可以把函数正常的打印出来了。

注意:当开发完成后需要发布到 npm 上,然后通过 npm 安装的时候,需要执行

代码语言:javascript
复制
npm unlink  test-cli
npm unlink  test-cli-lib
npm remove -g test-cli
npm remove -g test-cli-lib

然后再通过 npm 安装就行了

代码语言:javascript
复制
npm i -g test-cli
npm i -g test-cli-lib
下一篇
举报
领券