Vue-cli@3.0 是一个全新的 Vue 项目脚手架。不同于 1.x/2.x 基于模板的脚手架,Vue-cli@3.0 采用了一套基于插件的架构,它将部分核心功能收敛至 CLI 内部,同时对开发者暴露可拓展的 API 以供开发者对 CLI 的功能进行灵活的拓展和配置。接下来我们就通过 Vue-cli@3.0 的源码来看下这套插件架构是如何设计的。
整个插件系统当中包含2个重要的组成部分:
@vue/cli,提供 cli 命令服务,例如vue create创建一个新的项目;
@vue/cli-service,提供了本地开发构建服务。
@vue/cli-service
当你使用
vue create <project-name> 创建一个新的 Vue 项目,你会发现生成的项目相较于 1.x/2.x 初始化一个项目时从远程拉取的模板发生了很大的变化,其中关于 webpack 相关的配置以及 npm script 都没有在模板里面直接暴露出来,而是提供了新的 npm script:
// package.json
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
}前 2 个脚本命令是项目本地安装的 @vue/cli-service 所提供的基于 webpack 及相关的插件进行封装的本地开发/构建的服务。@vue/cli-service 将 webpack 及相关插件提供的功能都收敛到 @vue/cli-service 内部来实现。
这 2 个命令对应于 node_modules/@vue/cli-service/lib/commands 下的 serve.js 和 build/index.js。
在 serve.js 和 build/index.js 的内部分别暴露了一个函数及一个 defaultModes 属性供外部来使用。 事实上这两者都是作为 built-in(内置)插件来供 vue-cli-service 来使用的 。
说到这里那么就来看看 @vue/cli-service 内部是如何搭建整个插件系统的。就拿执行 npm run serve 启动本地开发服务来说,大概流程是这样的:

首先来看下 @vue/cli-service 提供的 cli 启动入口服务(@vue/cli-service/bin/vue-cli-service.js):
#!/usr/bin/env node
const semver = require('semver')
const { error } = require('@vue/cli-shared-utils')
const Service = require('../lib/Service') // 引入 Service 基类
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd()) // 实例化 service
const rawArgv = process.argv.slice(2)
const args = require('minimist')(rawArgv)
const command = args._[0]service.run(command, args, rawArgv).catch(err => { // 开始执行对应的 service 服务
error(err)
process.exit(1)
})看到这里你会发现在 bin 里面并未提供和本地开发 serve 相关的服务,事实上在项目当中本地安装的 @vue/cli-service 提供的不管是内置的还是插件提供的服务都是动态的去完成相关 CLI 服务的注册。










