搜索
您的当前位置:首页正文

Vue-cli@3.0 插件系统简析

2020-11-27 来源:步旅网

这一类插件在内部动态注册新的 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 实例都提供了:

  • 注册 cli 命令服务( api.registerCommand )
  • 通过 api 形式去更新的 webpack 配置( api.chainWebpack )
  • 通过 raw 配置形式去更新的 webpack 配置( api.configureWebpack ),与 api.chainWebpack 提供的链式 api 操作 webpack 配置的方式不同, api.configureWebpack 可接受raw式的配置形式,并通过 webpack-merge 对 webpack 配置进行合并。
  • resolve wepack 配置( api.resolveWebpackConfig ),调用之前通过 chainWebpack 和 configureWebpack 上完成的对于 webpack 配置的改造,并生成最终的 webpack 配置
  • ...
  • 首先我们来看下 @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 配置的更新等。

    Top