在 lib/Service.js 内部定义了一个核心的类 Service,它作为 @vue/cli 的运行时的服务而存在。在执行 npm run serve 后,首先完成 Service 的实例化工作:
class Service {
constructor(context) {
...
this.webpackChainFns = [] // 数组内部每项为一个fn
this.webpackRawConfigFns = [] // 数组内部每项为一个 fn 或 webpack 对象字面量配置项
this.devServerConfigFns = [] this.commands = {} // 缓存动态注册 CLI 命令
...
this.plugins = this.resolvePlugins(plugins, useBuiltIn) // 完成插件的加载
this.modes = this.plugins.reduce((modes, { apply: { defaultModes }}) => { // 缓存不同 CLI 命令执行时所对应的mode值
return Object.assign(modes, defaultModes)
}, {})
}
}在实例化 Service 的过程当中完成了两个比较重要的工作:
加载插件
将插件提供的不同命令服务所使用的 mode 进行缓存
当 Service 实例化完成后,调用实例上的 run 方法来启动对应的 CLI 命令所提供的服务。
async run (name, args = {}, rawArgv = []) {
const mode = args.mode || (name === 'build' && args.watch ? 'development' : this.modes[name])
// load env variables, load user config, apply plugins
// 执行所有被加载进来的插件
this.init(mode)
...
const { fn } = command
return fn(args, rawArgv) // 开始执行对应的 cli 命令服务
}
init (mode = process.env.VUE_CLI_MODE) {
...
// 执行plugins
// apply plugins.
this.plugins.forEach(({ id, apply }) => {
// 传入一个实例化的PluginAPI实例,插件名作为插件的id标识,在插件内部完成注册 cli 命令服务和 webpack 配置的更新的工作
apply(new PluginAPI(id, this), this.projectOptions)
})
...
// apply webpack configs from project config file
if (this.projectOptions.chainWebpack) {
this.webpackChainFns.push(this.projectOptions.chainWebpack)
}
if (this.projectOptions.configureWebpack) {
this.webpackRawConfigFns.push(this.projectOptions.configureWebpack)
}
}接下来我们先看下
@vue/cli-service 当中的 Service 实例化的过程:通过 resolvePlugins 方法去完成插件的加载工作:
resolvePlugins(inlinePlugins, useBuiltIn) {
const idToPlugin = id => ({
id: id.replace(/^.//, 'built-in:'),
apply: require(id) // 加载对应的插件
})
let plugins
// @vue/cli-service内部提供的插件
const builtInPlugins = [
'./commands/serve',
'./commands/build',
'./commands/inspect',
'./commands/help',
// config plugins are order sensitive
'./config/base',
'./config/css',










