这一类插件在内部动态注册新的 CLI 命令,开发者即可通过 npm script 的形式去启动对应的 CLI 命令服务。
'./config/base'
'./config/css'
'./config/dev'
'./config/prod'
'./config/app'
这一类插件主要是完成 webpack 本地编译构建时的各种相关的配置。@vue/cli-service 将 webpack 的开发构建功能收敛到内部来完成。
插件加载完成,开始调用 service.run 方法,在这个方法内部开始执行所有被加载的插件:
this.plugins.forEach(({ id, apply }) => { apply(new PluginAPI(id, this), this.projectOptions) })
在每个插件执行的过程中,接收到的第一个参数都是 PluginAPI 的实例,PluginAPI 也是整个 @vue/cli-service 服务当中一个核心的基类:
class PluginAPI { constructor (id, service) { this.id = id // 对应这个插件名 this.service = service // 对应 Service 类的实例(单例) } ... registerCommand (name, opts, fn) { // 注册自定义 cli 命令 if (typeof opts === 'function') { fn = opts opts = null } this.service.commands[name] = { fn, opts: opts || {}} } chainWebpack (fn) { // 缓存变更的 webpack 配置 this.service.webpackChainFns.push(fn) } configureWebpack (fn) { // 缓存变更的 webpack 配置 this.service.webpackRawConfigFns.push(fn) } ... }
每个由 PluginAPI 实例化的 api 实例都提供了:
首先我们来看下 @vue/cli-service 提供的关于动态注册 CLI 服务的插件,拿 serve 服务( ./commands/serve )来说:
// commands/serve module.exports = (api, options) => { api.registerCommand( 'serve', { description: 'start development server', usage: 'vue-cli-service serve [options] [entry]', options: { '--open': `open browser on server start`, '--copy': `copy url to clipboard on server start`, '--mode': `specify env mode (default: development)`, '--host': `specify host (default: ${defaults.host})`, '--port': `specify port (default: ${defaults.port})`, '--https': `use https (default: ${defaults.https})`, '--public': `specify the public network URL for the HMR client` } }, async function serve(args) { // do something } ) }
./commands/serve 对外暴露一个函数,接收到的第一个参数 PluginAPI 的实例 api,并通过 api 提供的 registerCommand 方法来完成 CLI 命令(即 serve 服务)的注册。
再来看下 @vue/cli-service 内部提供的关于 webpack 配置的插件( ./config/base ):
module.exports = (api, options) => { api.chainWebpack(webpackConfig => { webpackConfig.module .rule('vue') .test(/\.vue$/) .use('cache-loader') .loader('cache-loader') .options(vueLoaderCacheConfig) .end() .use('vue-loader') .loader('vue-loader') .options( Object.assign( { compilerOptions: { preserveWhitespace: false } }, vueLoaderCacheConfig ) ) }) }
这个插件完成了 webpack 的基本配置内容,例如 entry、output、加载不同文件类型的 loader 的配置。 不同于之前使用的配置式的 webpack 使用方式,@vue/cli-service 默认使用 webpack-chain( 链接请戳我 ) 来完成 webpack 配置的修改 。这种方式也使得 webpack 的配置更加灵活,当你的项目迁移至 @vue/cli@3.0,使用的 webpack 插件也必须要使用 API 式的配置,同时插件不仅仅要提供插件自身的功能,同时也需要帮助调用方完成插件的注册等工作。
@vue/cli-service 将基于 webpack 的本地开发构建配置收敛至内部来实现,当你没有特殊的开发构建需求的时候,内部配置可以开箱即用,不用开发者去关心一些细节。当然在实际团队开发当中,内部配置肯定是无法满足的,得益于 @vue-cli@3.0 的插件构建设计,开发者不需要将内部的配置进行 Eject,而是直接使用 @vue/cli-service 暴露出来的 API 去完成对于特殊的开发构建需求。
以上介绍了 @vue/cli-service 插件系统当中几个核心的模块,即:
Service.js 提供服务的基类,它提供了 @vue/cli 生态当中本地开发构建时:插件加载(包括内部插件和项目应用插件)、插件的初始化,它的单例被所有的插件所共享,插件使用它的单例去完成 webpack 的更新。
PluginAPI.js 提供供插件使用的对象接口,它和插件是一一对应的关系。所有供 @vue/cli-service 使用的本地开发构建的插件接收的第一个参数都是 PluginAPI 的实例( api ),插件使用这个实例去完成 CLI 命令的注册及对应服务的执行、webpack 配置的更新等。