前言:初始化一个vue的项目,很多人会下载一个vue的脚手架,通过脚手架快速初始化一个项目
一、初始化流程
1、npm install -g @vue/cli
下载一个脚手架
2、vue create xxx
脚手架创建一个名为xxx的项目
3、进行项目配置
选择最后一个手动配置
选择项目所需要的依赖
版本号以及其他配置单独保存一个文件还是都保存到package.json中
4、进入项目,安装配置、运行项目
cd xxx
npm install
npm run serve
二、脚手架执行大致流程
后续挑重点步骤有说明
1、从入口文件入手@vue/cli/bin/vue.js
,执行create函数
2、create函数中实例化Creator
3、通过Creator的实例挂载所有的交互配置
4、调用Creator的实例的create函数
5、询问用户自定义配置
6、初始化 Generator 实例 generator
7、初始化各种插件
8、执行插件的 generator 逻辑,写 package.json、渲染模板等
9、将文件写入硬盘
三、脚手架原理
1、源码中用到的npm包(只列举了部分)
commander
:命令行框架,提供了用户命令行输入和参数解析强大功能inquirer
:交互式命令行工具(使用cli搭建自定义依赖包的时候会让用户选择)handlebars
:javascript 语义模版库,通过 Handlebars 的 compile 方法将模板编译成 html,还有很多其他方法chalk
:修改控制台字符串的样式,包括字体样式(加粗),颜色以及背景颜色等download-git-repo
: 从 GitHub, GitLab, Bitbucket 下载一个 git 仓库
2、从package.json
开始分析,找到入口文件bin/vue.js
3、从入口开始分析
在vue上注册了create
、add
、ui
等
入口地址:
4、探讨created
函数
- 请求依赖文件
- 接受两个参数,
projectName
(文件名称)和options
(参数) - 校验
projectName
,最后创建一个项目目录 - 重要:执行
creator = new Creator(name, targetDir, getPromptModules())
参数解释:- name:项目名
- targetDir:目录地址
- getPromptModules():获取了 babel,typescript,pwa,router,vuex, cssPreprocessors,linter,unit,e2e 的 Prompt 的配置信息(获取第三方包的配置信息),用户和终端交互的模块
- 执行
creator.create()
5、Creator类
- 继承
EventEmitter
类(node的事件模块) constructor
构造函数:主要逻辑在resolveIntroPrompts
、resolveOutroPrompts
和PromptModuleAPI
中resolveIntroPrompts
: 获取了 presetPrompt list,在初始化项目的时候提供选择
-resolveOutroPrompts
:PromptModuleAPI
:内部函数injectFeature
,injectPrompt
,injectOptionForPrompt
,onPromptComplete
,实例调用这些函数,并保存到Creator
实例对应的变量中。- 将实例传入
getPromptModules
方法中,执行实例上的方法,初始化Creator
实例中featurePrompt
,injectedPrompts
,promptCompleteCbs
变量 - 遍历promptModules将所有的交互插入
Creator
中
create
方法,接收两个参数cliOptions
、preset
- cliOptions:终端命令行传入的参数
- preset:Vue-cli预设参数
①presetprompt
:预设选项,选择Vue2或者是Vue3
②featurePrompt
: 自定义 feature 选项
③injectedPrompts
: 具体 feature 选项
④outroPrompts
:其它选项
总结以上:用户完成以上所有的交互,进行了选择,后面开始根据这些选择生成对应的代码
6、初始化项目基础文件
- 创建目录写下基础
package.json
文件 - 初始化Git,执行
await run('git init');
- 初始化 README.md
- 安装依赖,自动判断 NPM 源(通过
await Promise.race([ ping(defaultRegistry), ping(registries.taobao) ])
),先返回的是淘宝安装源,就会让用户确认一次,是否使用淘宝安装源,默认安装源则直接安装
7、使用Generator类生成代码
- 执行Generator中的
initPlugins
函数:给package.json
中的每一个插件初始化一个GeneratorAPI
实例,并将实例传入generator
方法
8、GeneratorAPI类
vue-cli是一套插件架构,插件向自定义项目模板、修改模板中的一些文件或者添加一些依赖,就需要通过generator向外暴露的函数,参数就是GeneratorAPI实例,通过GeneratorAPI提供的方法去完成。
- extendPackage: 扩展
package.json
的配置
9、将内存中的文件输出到硬盘
四、额外知识点
1、EventEmitter类
Node.js 中事件触发与事件监听等功能的封装
2、输入命令有误,会猜测用户意图,以下示例:
输入vue creat vue_test
,会有以下提示
使用了leven
这个包,包是用于计算字符串编辑距离算法的JS实现,这里主要是用来计算输入的命令和当前已挂载的所有命令的编辑距离,从而猜测用户想输入的命令是哪个
五、从源码中我们可以的知识点
- 整体的交互流程的挂载:各个模块交互逻辑通过一个类的实例维护,执行时机和成功回调设计很好
- 插件机制很重要:插件机制将功能和脚手架进行解耦,将能力开放出去再将功能集成进来,有了足够的开放性和扩展性
- 实用工具,解析通过
--
传入的参数,使用commander
- 通过
semver.satisfies
比较node版本 - 读取 package.json,通过node的模块
fs
、path