概览
一个 CLI 插件是一个 npm 包,它能够为 Vue CLI 创建的项目添加额外的功能,这些功能包括:
- 修改项目的 webpack 配置 - 例如,如果你的插件希望去针对某种类型的文件工作,你可以为这个特定的文件扩展名添加新的 webpack 解析规则。比如说,@vue/cli-plugin-typescript 就添加这样的规则来解析 .ts 和 .tsx 扩展的文件;
- 添加新的 vue-cli-service 命令 - 例如,@vue/cli-plugin-unit-jest 添加了 test:unit 命令,允许开发者运行单元测试;
- 扩展 package.json - 当你的插件添加了一些依赖到项目中,你需要将他们添加到 package 的 dependencies 部分时,这是一个有用的选项;
- 在项目中创建新文件、或者修改老文件。有时创建一个示例组件或者通过给入口文件(main.js)添加导入(imports)是一个好的主意;
- 提示用户选择一个特定的选项 - 例如,你可以询问用户是否创建我们前面提到的示例组件。
通常的 CLI 插件目录结构看起来像下面这样:
.
├── README.md
├── generator.js # generator(可选)
├── index.js # service 插件
├── package.json
├── prompts.js # prompt 文件(可选)
└── ui.js # Vue UI 集成(可选)
为了让一个 CLI 插件在 Vue CLI 项目中被正常使用,它必须遵循vue-cli-plugin-<name>
或者 @scope/vue-cli-plugin-<name>
Generator
插件的 Generator 部分通常在你想要为项目扩展包依赖,创建新的文件或者编辑已经存在的文件时需要。
它将在以下两个场景被调用:
- 项目初始创建期间,CLI 插件被作为项目创建 preset 的一部分被安装时。
- 当插件在项目创建完成和通过 vue add 或者 vue invoke 单独调用被安装时。
一个 generator 应该导出一个接收三个参数的函数:
// generator/index.js
module.exports = (api, options, rootOptions) => {}
创建新的模板
当你调用 api.render(‘./template’) 时,该 generator 将会使用 EJS 渲染 ./template 中的文件 (相对于 generator 中的文件路径进行解析)
module.exports = api => {
api.render('./template')
}
.env 在 templete 中要写成 _env __variables.css 在 templete 中要写成 _variables.css
扩展包
如果你需要向项目中添加额外的依赖,创建一个 npm 脚本或者修改 package.json 的其他任何一处,你可以使用 API extendPackage 方法1
module.exports = api => {
api.extendPackage({
dependencies: {
'vue-router-layout': '^0.1.2'
}
})
}
修改主文件
api.injectImports(api.entryFile, `import router from './router'`)
我们可以使用 afterInvoke 钩子,这个钩子将在文件被写入硬盘之后被调用。
module.exports.hooks = (api) => {
api.afterInvoke(() => {
//
})
}
Service
Service 插件可以修改 webpack 配置,创建新的 vue-cli service 命令或者修改已经存在的命令(如 serve 和 build)。
Service 插件在 Service 实例被创建后自动加载 - 例如,每次 vue-cli-service 命令在项目中被调用的时候。它位于 CLI 插件根目录的 index.js 文件。
一个 service 插件应该导出一个函数,这个函数接受两个参数:
- 一个 PluginAPI 实例
- 一个包含 vue.config.js 内指定的项目本地选项的对象,或者在 package.json 内的 vue 字段。
修改 webpack 配置
const VueAutoRoutingPlugin = require('vue-auto-routing/lib/webpack-plugin')
module.exports = (api, options) => {
api.chainWebpack(webpackConfig => {
webpackConfig
.plugin('vue-auto-routing')
.use(VueAutoRoutingPlugin, [
{
pages: 'src/pages',
nested: true
}
])
})
}
添加一个新的 cli-service 命令
通过 service 插件你可以注册一个新的 cli-service 命令,除了标准的命令(即 serve 和 build)。你可以使用 registerCommand API 方法实现。
api.registerCommand(
'greet',
{
description: 'Write a greeting to the console',
usage: 'vue-cli-service greet'
},
() => {
console.log(`👋 Hello`)
}
)
在这个例子中,我们提供了命令的名字(’greet’)、一个有 description 和 usage 选项的对象,和一个在执行 vue-cli-service greet 命令时会调用的函数。
修改已经存在的 cli-service 命令
如果你想修改一个已经存在的 cli-service 命令,你可以使用 api.service.commands 获取到命令对象并且做些改变。我们将在应用程序运行的端口打印一条信息到控制台:
const { serve } = api.service.commands
const serveFn = serve.fn
serve.fn = (...args) => {
return serveFn(...args).then(res => {
if(res && res.url) {
console.log(`Project is running now at ${res.url}`)
}
})
}
在上面的这个例子中,我们从已经存在的命令列表中获取到命令对象 serve;然后我们修改了他的 fn 部分(fn 是创建这个新命令时传入的第三个参数;它定义了在执行这个命令时要执行的函数)。修改完后,这个控制台消息将在 serve 命令成功运行后打印。
为命令指定模式
如果一个已注册的插件命令需要运行在特定的默认模式下,则该插件需要通过 module.exports.defaultModes 以 { [commandName]: mode } 的形式来暴露:
module.exports = api => {
api.registerCommand('build', () => {
// ...
})
}
module.exports.defaultModes = {
build: 'production'
}
这是因为我们需要在加载环境变量之前知道该命令的预期模式,所以需要提前加载用户选项/应用插件。
对话
对话是在创建一个新的项目或者在已有项目中添加新的插件时处理用户选项时需要的。所有的对话逻辑都存储在 prompts.js 文件中。对话内部是通过 inquirer 实现。
当用户通过调用 vue invoke 初始化插件时,如果插件根目录包含 prompts.js,他将在调用时被使用。这个文件应该导出一个问题数组 — 将被 Inquirer.js 处理。
你应该直接导出一个问题数组,或者导出一个返回这些内容的函数。
module.exports = [
{
name: 'name',
type: 'input',
message: '组件标识',
default: 'aquarius'
},
{
name: 'context',
type: 'input',
message: '服务上下文',
default: ({ name }) => {
return `${name}-web`;
}
},
{
name: 'serviceName',
type: 'input',
message: '服务名称',
default: ({ name }) => {
return `${name}-web`;
}
}
];
安装本地插件
当你开发自己的插件时,你需要测试它、查看它在使用 Vue CLI 创建的项目中如何工作。你可以使用已经存在的项目或者创建一个新的项目用来测试:
vue create test-app
安装插件,在项目根目录运行下面的命令:
npm install --save-dev file:/full/path/to/your/plugin
vue invoke <your-plugin-name>
每次插件修改后,你需要重复这个步骤。
Preset
一个 Vue CLI preset 是一个包含创建新项目所需预定义选项和插件的 JSON 对象,让用户无需在命令提示中选择它们。
在 vue create 过程中保存的 preset 会被放在你的 home 目录下的一个配置文件中 (~/.vuerc)。你可以通过直接编辑这个文件来调整、添加、删除保存好的 preset。
{
"useConfigFiles": true,
"plugins": {
"@vue/cli-plugin-babel": {},
"@vue/cli-plugin-eslint": {
"lintOn": ["save"]
},
"@vue/cli-plugin-unit-jest": {},
"@agr/vue-cli-plugin-base": {
"prompts": true,
"useTs": false,
"version": "~1.1.0"
},
"@agr/vue-cli-plugin-registry": {
"version": "~1.1.0"
},
"@agr/vue-cli-plugin-i18n": {
"version": "~1.1.0"
},
"@agr/vue-cli-plugin-theme": {
"version": "~1.1.0"
},
"@agr/vue-cli-plugin-changelog": {
"version": "~1.1.0"
}
},
"cssPreprocessor": "dart-sass"
}
“useConfigFiles”: true,configs 的值将会被合并到 vue.config.js 中。 “prompts”: true ,允许注入命令提示 “version”,可以显式地指定用到的插件的版本
https://juejin.cn/post/6844903817776103431#heading-12
脚手架
远程 Preset
你可以通过发布 git repo 将一个 preset 分享给其他开发者。这个 repo 应该包含以下文件:
- preset.json: 包含 preset 数据的主要文件(必需)。
- generator.js: 一个可以注入或是修改项目中文件的 Generator。
- prompts.js 一个可以通过命令行对话为 generator 收集选项的 prompts 文件。
发布 repo 后,你就可以在创建项目的时候通过 —preset 选项使用这个远程的 preset 了
# 从 GitHub repo 使用 preset
vue create --preset username/repo my-project
# gitlab
vue create --preset gitlab:username/repo --clone my-project
也可以使用本地的
如果 —preset 选项的值是一个相对或绝对文件路径,或是以 .json 结尾,则 Vue CLI 会加载本地的 preset:
# ./my-preset 应当是一个包含 preset.json 的文件夹
vue create --preset ./my-preset my-project
# 或者,直接使用当前工作目录下的 json 文件:
vue create --preset my-preset.json my-project