背景
随着vue的崛起,公司的前端框架也发布了大版本,基于vue开发,所以每次创建项目都会遇到很多重复步骤,比如安装框架,加入公司通用的eslint规则等等,所以需要写一个工具,来免去这些墨迹的步骤。
当时vue cli3也刚发布没多久,我也没细看官网,大菜单上,只关注了“指南”,直接无视了“插件开发指南”菜单。所以当时想的是模仿vue cli2写一个自己的脚手架,准备工作,开始阅读vue cli2源码,源码的目录结构、代码结构、思路都很清晰,开始造轮子,大致就是在命令行询问是否安装某些组件,最终通过git仓库将模板拉取下来。
正当我卡在某些功能的实现上时,我才发现cli3已经和cli2的开发思想都不一样了,升级为了“插件”模式,初始化模块、组件,都通过调用“插件”的方式来安装,于是开始新的开发路线,完成了一个雏形。
什么是"插件"
官方链接:插件和 Preset | Vue Cli
友情提示,学习的时候对照着官网和源码一起可以了解得更快:cli3源码
插件
安装vue cli3后,可以使用 vue add 命令,这个命令就是用来安装vue插件的,比如,当执行
vue add @vue/eslintvue会将这个命令解析为:
vue add @vue/cli-plugin-eslint从npm下载 @vue/cli-plugin-eslint 这个包,并且调用这个包的安装器,安装器就是下面会提到的 Generator。
可以源码的目录结构(vue-cli/packages/@vue/)中,有很多
cli-plugin-开头的文件夹
Preset
就和单词意思一样:预设
一个json文件,保存了初始化项目所需的默认预设,使用 vue create 的时候,最后一步会问你是否保存为一个 preset,这时候保存的文件就是你当前调用vue create得最终配置文件。大概长这样:
{
"useConfigFiles": true,
"plugins": {...},
"configs": {
"vue": {...},
"postcss": {...},
"eslintConfig": {...},
"jest": {...}
}
}2
3
4
5
6
7
8
9
10
config 这个属性存的就是项目生成的 vue.config.js 配置文件的内容。
这个文件可以存在git仓库分享给其他人。可以通过 --preset 参数指定预设
vue create --preset username/repo my-project插件和preset区别
插件包含以下三个模块
- Service 插件
- generator.js 一个可以注入或是修改项目中文件的 Generator。(可选)
- prompts.js 一个可以通过命令行对话为 generator 收集选项的 prompts 文件。(可选)
preset包含以下三个模块
- preset.json 包含 preset 数据的主要文件(必需)。
- generator.js
- prompts.js
唯一不同点就是第一点,这里讨论的是 preset 这种模式,就先不用管 Service 插件
generator.js
一个发布为 npm 包的 CLI 插件可以包含一个 generator.js 或 generator/index.js 文件。插件内的 generator 将会在两种场景下被调用:
- 在一个项目的初始化创建过程中,如果 CLI 插件作为项目创建 preset 的一部分被安装。
- 插件在项目创建好之后通过 vue invoke 独立调用时被安装。
简单来说,就是在调用 vue create 或者 vue invoke 的时候回调用这个插件的 generator.js 文件,这个js文件导出一个函数,该函数接收三个参数:
- api : 一个 GeneratorAPI 实例
- options: 这个插件的 generator 选项。这些选项会在项目创建对话过程中被解析,或从一个保存在 ~/.vuerc 中的 preset 中加载。简单理解就是在命令行问“是否安装vue-router”、是否安装css预编译器的那个步骤,用户输入的内容。
- rootOptions: 整个 preset.json 对象
一个简单的示例,目录结构为:
┌─ generator
│ ├─ templates
│ │ └─ src
│ │ └─ App.vue
│ └─ index.js
├─ package.json
├─ preset.json
└─ prompts.js2
3
4
5
6
7
8
generator.js 为:
module.exports = (api, options, rootOptions) => {
// 复制并用 ejs 渲染 `./template` 内所有的文件
api.render('./templates', {hasXxtery: !!options.xxteryUI});
// 修改 `package.json` 里的字段
if (options.xxteryUI) {
api.extendPackage({
dependencies: {
'@com.xxxxxxxxx.xxtery/x-ui': '^0.1.88'
}
});
} else {
api.extendPackage({
dependencies: {
'normalize.css': '^8.0.1'
}
});
}
api.extendPackage({
devDependencies: {
"style-resources-loader": "^1.2.1",
"vue-cli-plugin-style-resources-loader": "^0.1.3"
},
scripts: {
'build:rp': 'vue-cli-service build --report'
},
});
console.log(options);
};2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
代码中的
api.render('./templates', {
hasXxtery: !!options.xxteryUI
}
);2
3
4
会去找 ./templates 文件夹,用ejs渲染这个文件夹下的所有内容,并且替换当前项目的同级目录下的内容。结合我们的目录,相当于会把项目中的 App.vue替换为我们这个插件中的 App.vue。具体使用的 ejs 相关,可以查阅官网:ejs。
这个模块导出一个函数,函数中的第二个参数 options 就是在用户使用cli时输入的内容,也就是 prompts
prompts.js
这个文件叫“对话框”,和用户做问答交互。
一个对话模块应该导出一个函数,这个函数接收一个 PromptModuleAPI 实例。这些对话的底层使用 inquirer 进行展示:
一个简单的对话模块:
module.exports = [
{
name: 'vuex',
type: 'confirm',
message: '是否安装vuex?',
default: false,
description: '默认不安装'
},
{
name: 'vuexType',
type: 'list',
when: answers => answers.vuex,
message: '请选择你要生成的vuex代码结构',
choices: [
{name: '简单模式 (一个js文件管理vuex)', value: 'simple'},
{name: '模块模式 (适用于大型应用,细分vuex,将 action、mutation 和 getter 分割到单独的文件)', value: 'modules'},
],
default: 'simple',
},
{
name: 'xxteryUI',
type: 'confirm',
message: '是否安装xxtery-ui?',
default: true,
description: '默认安装'
},
]2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
调试
这样一个简单的 cli3插件 就完成了,本地测试的话,先用 vue create 创建一个项目,然后
- 如果发布到了git或者npm仓库,就通过
vue add <name> 或 vue invoke <name>安装下来,注意:必须遵循 vue-cli-plugin-<name> 的命名约定。
- 如果是本地代码,就通过以下安装
vue invoke 本地文件路径如果想在创建项目的时候,也就是使用 vue create 的时候就调用我们的插件,那么本篇涉及的方法,项目中一定要有preset.json文件
发布 repo 后,你就可以在创建项目的时候通过 --preset 选项使用这个远程的 preset 了:
从 GitHub repo 使用 preset
vue create --preset username/repo <project-name>GitLab 和 BitBucket 也是支持的。如果要从私有 repo 获取,请确保使用 --clone 选项:
vue create --preset gitlab:username/repo --clone <project-name>
vue create --preset bitbucket:username/repo --clone <project-name>
vue create --preset direct:<git-clone-url> <project-name>2
3
加载文件系统中的 Preset
当开发一个远程 preset 的时候,你必须不厌其烦的向远程 repo 发出 push 进行反复测试。为了简化这个流程,你也可以直接在本地测试 preset。如果 --preset 选项的值是一个相对或绝对文件路径,或是以 .json 结尾,则 Vue CLI 会加载本地的 preset:
./my-preset 应当是一个包含 preset.json 的文件夹
vue create --preset ./my-preset <project-name>或者,直接使用当前工作目录下的 json 文件:
vue create --preset my-preset.json <project-name>总结
难点主要在于 ejs,需要根据用户对话框的回答,对项目内容进行修改,在开发之前,可以先大概阅读cli3的源码,会对很多官网没详细描述的地方有深入了解。
