脚手架原理和基本搭建
什么是脚手架
脚手架本质是一个操作系统的客户端,它通过命令执行,如:
vue create vue-test-app
上面命令由三部分组成
- 主命令:Vue
- command:create
- command 的 parm:vue-test-app
执行此命令后,就会在对应目录下创建一个叫做 vue-test-app 的项目,并自动执行 npm install 按照对应的依赖,通常可以输入下面的命令就可以看到 vue create 支持的所有 options
vue create --help
为什么要研发脚手架?
开发脚手架的核心目标就是:提升前端研发效率
在大的开发团队中,提升研发效率是非常有必要的,减少重复操作劳动,统一代码风格和结构。我们通过脚手架讲研发过程:
- 自动化:项目重复代码拷贝/git操作/发布上线操作
- 标准化:项目创建/git flow/发布流程/回滚操作
- 数据化:研发过程系统化、数据化、使得研发过程可量化
脚手架的执行原理
脚手架的执行原理如下:
- 在终端输入
vue create vue-test-app
- 终端解析出
vue
命令 - 终端在环境变量中找到
vue
命令 - 终端根据
vue
命令链接到实际文件vue.js
- 终端利用
node
执行vue.js
vue.js
解析 command/optionsvue.js
执行 command- 执行完毕退出执行
疑问🤔️
- 为什么全局安装了
@vue/cli
后会添加的命令为vue
?
npm install -g @vue/cli
- 全局安装
@vue/cli
时发生了什么? - 执行
vue
命令时发生了什么?为什么vue
指向一个js
文件,我们却可以通过vue
命令去执行?
带着问题我们来一一刨析!
这里以我本地 create-react-app
脚手架为演示,在执行命令时,终端首先会执行如下命令进行查找:
which create-react-app
如图,可以看到在环境变量 /usr/local/bin
目录下创建一个了叫做 create-react-app
的软链接
OK,现在让我们进入到对应的目录,看看
在对应目录下我们看到了 create-react-app
项目的目录结构,查看 pack.json
的 bin
属性,发现如下
"bin": {
"create-react-app": "./index.js"
},
同样 @vue/cli
也是该原理,到此,我们就可以回到前面两个问题。
在全局安装 @vue/cli
、create-react-app
时,首先会创建一个软链接,然后指向它真是所在的项目目录,通过上面的图可以看到,通过全局安装会被放在 /yarn/global/node_modules/.bin/
目录下
通过配置文件 pack.json
的 bin 文件,设置命令的名字,如 vue、create-react-app,cli 就会去执行对应的文件。我们打开 create-react-app
对应的 ./index.js
看看,在头部我们发现这么一行代码
#!/usr/bin/env node
这段代码的作用就是在环境变量中查找 node
,然后用 node
去执行,到此基本回到了上面三个问题,下面来进阶一下脚手架原理
脚手架原理进阶
- 为什么说脚手架的本质操作系统的客户端?它和我们在PC上安装的应用/软件有什么区别?
- 如何为
Node
脚手架创建别名?
我们知道编写的脚手架JS
文件,必须在 Node
环境中运行,我们找到安装 Node 的目录发现,Node 本身就是一个可执行文件,只不过没有 GUI
可视化的操作页面,它和我们在PC上安装的应用本质没有任何区别
可以通过创建软链接的方式给脚手架创建别名
ln -s ./create-react-app create-react-app2
新起的名字叫做 create-react-app2
会指向 create-react-app
,create-react-app
会指向真实的地方
用一张图总结脚手架执行的全过程.
脚手架开发流程
在之前文章 从零创建自己的脚手架 中实现了一个脚手架的简单搭建和发布,那么有那些难点没有解决呢?
脚手架开发难点解析
分包:将复杂的系统分开成若干个模块
注册命令
vue add vue create
- 参数解析
- optinos全称:--version、--help
- options简写:-V、-h
- 带params的optinos:--path /Users/xikun/Aotu
示例代码:
vue commadn [options] <params>
- 帮助文档
- globale help
以 create-react-app
示例:
sage: create-react-app <project-directory> [options]
Options:
-V, --version output the version number
--verbose print additional logs
--info print environment debug info
--scripts-version <alternative-package> use a non-standard version of react-scripts
--template <path-to-template> specify a template for the created project
--use-npm
--use-pnp
-h, --help output usage information
Only <project-directory> is required.
A custom --scripts-version can be one of:
- a specific npm version: 0.8.2
- a specific npm tag: @next
- a custom fork published on npm: my-react-scripts
- a local path relative to the current working directory: file:../my-react-scripts
- a .tgz archive: https://mysite.com/my-react-scripts-0.8.2.tgz
- a .tar.gz archive: https://mysite.com/my-react-scripts-0.8.2.tar.gz
It is not needed unless you specifically want to use a fork.
A custom --template can be one of:
- a custom template published on npm: cra-template-typescript
- a local path relative to the current working directory: file:../my-custom-template
- a .tgz archive: https://mysite.com/my-custom-template-0.8.2.tgz
- a .tar.gz archive: https://mysite.com/my-custom-template-0.8.2.tar.gz
If you have any problems, do not hesitate to file an issue:
https://github.com/facebook/create-react-app/issues/new
还有很多,比如:
- 命令行交互
- 日志打印
- 命令行文字颜色
- 网络通信:HTTP/WebSocket
- 文件处理
等等。。。
原生脚手架开发痛点分析
痛点一:重复操作
- 多Pageage本地link
- 多Pageage依赖安装
- 多Pageage单元测试
- 多Pageage代码提测
- 多Pageage代码发布
- 痛点二:版本一致性
- 发布时版本一致性
- 发布后相互依赖版本升级
Pageage 越多,管理复杂度越高
脚手架本地link标准流程
链接本地脚手架
cd your-cli-dir
npm link
链接本地库文件
cd your-lib-dir
npm link
cd your-cli-dir
npm link your-lib
取消链接本地库文件
cd your-lib-dir
npm unlink
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 unlink
:将当前项目从node
全局node_modules
移除npm unlink your-lib
:将当前项目的库文件依赖移除
Lerna 简介
Learn 是一个优化基于 git + npm 的多 pageage 项目管理的工具,像 bable、vue-cli、create-react-app 都使用 Lerna
进行管理
Lerna 开发脚手架流程
基于Lerna创建脚手架
全局安装 Lerna
npm install -g lerna
在项目目录执行 lerna 初始化命令
lerna init
发现会生成一个 lerna.json
文件和 packages
目录,并且为我们初始化了 git
仓库
使用 Lerna
创建一个 package
lerna create core
lerna create utils
在输入 package 的 name,我们选择使用 npm 包组织管理默认,如 @aotu-cli/core、@aotu-cli/utils
如下图在 npm
上注册一个命令 aotu-cli
的组织,这样我们所有的包文件都在它下面
使用 Lerna
添加依赖
// 给所有package依赖依赖
lerna add loadash
// 给指定package依赖依赖
lerna add loadash packages/core
使用 Lerna
移除所有依赖
lerna add loadash
只会删除
node_modules
,不会删除package.json
中的依赖
使用 Lerna
执行所有命令
lerna run test
使用 Lerna
进行批量发布
lerna publish
初次执行会报错,提示告诉我们 执行 git commit
ok,首先在 github 上创建工程并链接到本地进行推送,再次执行 lerna publish
告诉我们需要先进行 npm
登陆,我们执行 npm login
进行登陆,输入账户密码,发现又出现新的报错
这个错误是 npm
要求在发布的时候要求设置环境为原地址,执行以下命令
npm config set registry http://registry.npmjs.org
再次执行 lerna publish
,又发现报错
这个错误是因为 Lerna
的项目默认都是私有项目,在每个 packages 的 package.json
里面添加配置
"publishConfig": {
"access": "public"
}
再次执行 lerna publish
如图发布成功,在 npm
进行搜索,找到了我们刚才发布的两个包