内容简介:不久前组内有大佬发布了一个 vue-cli3 的 dll 包,作为一个在 vue 项目内摸爬滚打的萌新,是时候该学习点儿新的技术了,于是在闲暇之余,我拷贝了一份代码,同时研究该如何从“零”开始编写一个 dll 包(该部分以 webpack 的 dllPlugin 作为例子)。通篇读完官网的文档,因为知识点比较多,并且没有详细的例子(指“傻瓜式教学式”),因此开发这第三方包的学习成本还是有一些的,特别是 webpack-chain 和 node 的部分知识,这里记录总结了一些关键的点。最开始命名文件夹时我并没
不久前组内有大佬发布了一个 vue-cli3 的 dll 包,作为一个在 vue 项目内摸爬滚打的萌新,是时候该学习点儿新的技术了,于是在闲暇之余,我拷贝了一份代码,同时研究该如何从“零”开始编写一个 dll 包(该部分以 webpack 的 dllPlugin 作为例子)。
了解文档
通篇读完官网的文档,因为知识点比较多,并且没有详细的例子(指“傻瓜式教学式”),因此开发这第三方包的学习成本还是有一些的,特别是 webpack-chain 和 node 的部分知识,这里记录总结了一些关键的点。
插件命名
最开始命名文件夹时我并没有使用 vue-cli-plugin-
作为文件名前缀,结果可想而知,vue invoke 一直提示找不到该包的信息。于是我去看了看源码…… 在 @vue/cli/lib/invoke.js
内,其有一个关键的获取包 Id 的方法 resolvePluginId
,该方法在 @vue/cli-shared-utils/lib/pluginResolution.js
,源码如下:
exports.resolvePluginId = id => { // already full id // e.g. vue-cli-plugin-foo, @vue/cli-plugin-foo, @bar/vue-cli-plugin-foo if (pluginRE.test(id)) { return id } // scoped short // e.g. @vue/foo, @bar/foo if (id.charAt(0) === '@') { const scopeMatch = id.match(scopeRE) if (scopeMatch) { const scope = scopeMatch[0] const shortId = id.replace(scopeRE, '') return `${scope}${scope === '@vue/' ? `` : `vue-`}cli-plugin-${shortId}` } } // default short // e.g. foo return `vue-cli-plugin-${id}` } 复制代码
很明显,使用 vue invoke 时其只会寻找含有 vue-cli-plugin-
作为前缀的包,官网内在文档的最后部分有做对应的说明(这个是后来才看到的),原文如下:
为了让一个 CLI 插件能够被其它开发者使用,你必须遵循 vue-cli-plugin-<name>
的命名约定将其发布到 npm 上。
因此 package.json
的 name
字段符合规则即可。
creator 和 service
官网开篇就介绍了两个主要的部分: @vue/cli
和 @vue/cli-service
,首先是 @vue/cli
部分,这里介绍了插件的目录结构,因此我们可以根据此来搭一个插件框架:
vue-cli-plugin-xxx ├── README.md ├── generator | └── index.js ├── index.js ├── package.json ├── prompts | └── index.js ├── service | ├── config-file.js | └── regist-command.js └── yarn.lock 复制代码
接下来就详细分析一下各部分的作用。
generator
文档分析
文档中有提到,插件内的 generator 将会在两种场景下被调用:
vue invoke
由于开发的第三方插件使用场景多数在于更改已安装的项目配置, preset
使用场景不是很多(创建项目时一般还是手动配置,大多数情况不会选择去生成一个 ~/.vuerc),因此这边仅处理使用手动调用 generator 的情况。
触发 generator
的方法有两种:
vue invoke vue add
下面就简单介绍一下这两个命令的区别。
vue invoke 指令
此指令的适用情况为已经通过 yarn 或者 npm 将包安装至项目内,此时仅需要调用 vue invoke 即可。
注意:这里的 packageName 为不包含 vue-cli-plugin-
部分的剩余包名,比如:发布的包名为 vue-cli-plugin-xxx
,那么此时使用命令即 vue invoke xxx
vue add
此指令的使用情况为项目内还没有安装对应的包,使用方式同 vue invoke
注:如果包的源不对的话,请自己在后面加上包所在的 npm 源地址( --registry )
内容编写
分析了这么多,重点还是 generator 内我们应该写点什么,它影响的是什么。好了,让我们来继续看文档(● ˃̶͈̀ロ˂̶͈́)੭ꠥ⁾⁾
generator 有三个参数,这里就不细赘了,因为这里不关注 preset 的配置,所以对我们来说,有用的部分就只有第一个参数 api。首先我们需要改动的部分便是项目内的 package.json 了,使用方法 extendPackage
即可,例子如下:
// 修改 `package.json` 里的字段 // vue 部分的内容可以不要 module.exports = (api, options, rootOptions) => { // 修改 `package.json` 里的字段 api.extendPackage({ scripts: { test: 'vue-cli-service test' }, vue: { pluginOptions: { test: { // 需要预打包的部分 vendors: [], // 输出文件名 outputName: 'vendor.dll.js', // 输出地址 outputPath: './public/vendor', // 是否调用 cleanWebpackPlugin cleanCache: true } } } }); } 复制代码
关于此处添加的 vue
字段在 invoke 后会自动补充至 vue.config.js 或者 package.json 内。
如果你配置了 promots 并且需要该部分的内容,那么可以使用第二个 options 参数去获取配置的内容。(配置 .vuerc 的方法没有尝试,因为解构 + 默认值 + prompts 已经足够了)
如果需要配置模板方面的参考 官方源码 ,感觉配合 prompts 写个模板插件也不错。
友情提示:render() 函数内为你的 template 模板基于当前文件夹所在的路径。
prompts
该部分其实在这个项目内并没有涉及,但还是要提一下。官方文档对于此部分在内建插件有详细的说明(官方插件),第三方插件提到过一点:
这个文件应该导出一个用于 Inquirer.js 的 问题 的数组。这些被解析的答案对象会作为选项被传递给插件的 generator。
因此,如果需要的情况下,我们得通过数组的形式编写问答。例如:
module.exports = [ { name: 'entry', message: "What's the output file's name?", type: 'input', default: 'vendor' } ] 复制代码
此部分的配置结果会在 generator 部分的第二个参数捕捉到。
service
这部分就是配置的重点了,还是根据官网来吧,官网有提到 3 个命令: chainWebpack
、 configureWebpack
、 registerCommand
。直接更改原有项目的配置并不是很好(除非你很有信心),因此我们可以使用 configureWebpack
来合并变更。
这部分总的来说做三件事:
- 更改用户的 webpack 配置文件(也就是 vue.config.js)
- 向 cli-service 内注册指令
- 为注册的指令指定模式
这里从简单的部分开始一一说明吧~(顺序:3、1、2)
指定模式
嗯,这个最简单了,毕竟官网文档内有,理由也就不赘述了,代码如下:
module.exports.defaultModes = { <your direct>: <target mode> } 复制代码
其中 your direct
部分即先前的 generator 部分注册的 script 脚本内,在 vue-cli-service
后面的那个指,比如,先前写的是 test
,那么这里注册的指令也是 direct
,mode 就根据实际情况处理即可,一般使用 production
生产模式就没啥问题。
更改用户的配置文件
这里就需要有 webpack-chain 的知识了。先看看 pluginAPI 内有些啥( 传送门 ),可能会用到的一些方法包括:
- getCwd:获取当前的工作目录
- resolve:相当于 path.resolve
- registerCommand:注册指令(有三个参数!)
- chainWebpack:链式调用 webpack
- configureWebpack:用于合并 webpack
- resolveChainableWebpackConfig:用于解析 webpack
此处我们使用 configureWebpack
来更改配置,同时使用 registerCommand
来注册我们的命令。这里刚好对应的就是我们的两个文件 config-file
和 regist-command.js
了,对应开发即可。
configureWebpack
参考源码的写法,我们可以通过 options 参数获取 invoke 生成的 vue.config.js
里面的 pluginOptions
字段内的对应配置内容,配合 api.configureWebpack
来注入我们的 webpack 配置。粗略的写法为:
api.configureWebpack(config => { // 增一个 plugins config.plugins.push( /* plugin 配置 */ ) }); 复制代码
registerCommand
查看源码的写法,发现参数有三个,分别是:
- api: pluginAPI 实例
- options: 用来添加配置说明
- fn: 回调函数,用于触发执行的内容(比如运行一个 webpack 配置)
官方的写法如下,我们可以据此模仿
api.registerCommand( "test", { description: "此为指令的说明", // 指令意义 usage: "vue-cli-service test", // 命令怎么用 options: { /* 参数说明 */ } }, async args => { /* 可以写个 chain-webpack 然后调用,或者干点其它的 */ } ); 复制代码
部分问题总结
1. demo 内的 dll 打包位置问题
使用默认的打包位置: public/vendor
会产生一个问题,就是 build 文件内会包含此 vendor 文件夹,我们注入的一些配置不生效。
解决方法:将默认的 public/vendor
打包位置改改,只要不是生成在 public 文件夹内的都没问题,可看 vue-cli 官网的 public 部分的解释。
2. webpack 函数
目前第二个回调参数的使用场景不是很明确(其实不用回调也可以,外层关闭对应的 log 即可)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Gradle插件开发系列之开发第一个gradle插件
- (是时候开发属于自己的插件了)数据校验插件开发指南
- IDEA 插件:多线程文件下载插件开发
- 从头开发一个Flutter插件(二)高德地图定位插件
- Gradle插件开发系列之gradle插件调试方法
- WordPress插件开发 -- 在插件使用数据库存储数据
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。