背景
使用 vue 进行开发的同学对vue-cli一定不会陌生,最初 vue-cli@2x的时代,我们使用的时候通常会去修改webpack来满足我们团队的需求,又或者通过自己维护一个脚手架,满足日常开发。
在vue-cli 升级为3x之后提供了插件的选项。cli插件作为vue-cli的部分,为我们提供了便利的开发环境,他使得我们的开发环境插件化,让我们可以针对不同的情况定制不同的插件,例如 vue-cli-plugin-typescript vue-cli-plugin-vant
。
那么如何实现这么一个cli插件呢?
vue-cli-plugin-kg-request
为了在项目初始化的时候就能将我们自己封装的请求,内置在项目中,我们决定实现一个 vue-cli-plugin-kg-request
。下面是一个基本的目录结构:
├── README.md
├── index.js # service plugin
└── package.json
service 插件
service plugin
主要修改webpack配置
module.exports = (api, opts) => {
}
通过generatorAPI
生成模板
一个已经实现的目录结构
.
├── README.md
├── generator
│ ├── index.js # generator
│ └── template # plugins template file
│ └── plugins
│ └── request.js
├── index.js # sevirce plugin
└── package.json
通过 generator
可以往 package.json
注入依赖字段,或者添加文件到项目中。api.extendPackage
方法拓展 package.json
, 默认情况下,该方法会merge已有依赖项,如果想这么做,可以设置参数 merge: false
。
// generator/index.js
module.exports = (api, options, rootOptions) => {
api.extendPackage({
dependencies: {
"axios": "^0.18.0"
}
})
}
编写模板文件以备之后注入到我们创建的项目中。 这里封装了常用数据请求方法,设置了请求拦截,响应数据拦截
// /src/plugins/request.js
import axios from 'axios'
import querystring from 'query-string'
// 请求拦截回调
const requestInterceptors = function(config) {
if (config.method.toLocaleUpperCase() === 'POST') {
config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
config.data = querystring.stringify(config.data)
}
return config
}
// 响应拦截回调
const responseInterceptors = function(response) {
let { data } = response
// ..
return Promise.resolve(data)
}
// 响应拦截错误回调
const responseErrorInterceptors = function (error) {
try {
let { status } = error.response
} catch(err) {
console.error(JSON.stringify(err))
}
return Promise.reject(error)
}
const instance = axios.create()
instance.defaults.withCredentials = true
instance.interceptors.request.use(requestInterceptors)
instance.interceptors.response.use(responseInterceptors, responseErrorInterceptors)
export default instance
修改main.js
模板导入之后,我们还要在入口文件进行导入,这样就避免了手动操作。具体做法就是使用fs
模块,读取入门文件main.js
,然后写入文本。
// generator/index.js
api.onCreateComplete(() => {
// 添加字串
const iviewLines = `\nimport request from '@/plugins/request'\n\nVue.use(request)`
// 获取文件内容
let contentMain = fs.readFileSync(api.entryFile, { encoding: 'utf-8' })
// 反转内容
const lines = contentMain.split(/\r?\n/g).reverse()
// 找到import的下标
const importIndex = lines.findIndex(line => line.match(/^import/))
// 在反转第一个import的下面添加引入语句
lines[importIndex] += iviewLines
// 回归main内容
contentMain = lines.reverse().join('\n')
// 写入入口文件
fs.writeFileSync(api.entryFile, contentMain, { encoding: 'utf-8' })
})
api.render
调用时,生成器将使用EJS渲染./template
中的文件。
// generator/index.js
// 渲染模板
api.render('./template')
调试
调试, 编写好之后我们本地调试下我们的代码,测试是否满足。
# 创建一个新项目
vue create plugin-test
# 进入项目目录
cd plugin-test
# 本地安装vue-cli插件
npm install file://localPath/vue-cli-plugin-kg-request
# cli 调用
vue invoke vue-cli-plugin-kg-request
发布
vue-cli插件写完可以发布到npm让更多人使用,这里只是实现了一个简单的例子,各位可以根据自己的需求,自己拓展实现,将自己的开发环境插件化,组装起来,需要注意的是插件的命名必须是这样的vue-cli-plugin-<name>
,以备vue add 的时候能够拉取到。官方文档
# 登录你的 npm 账号
npm login
# 发布
npm publish