Vue-cli@3.0 插件系统简析

2020-06-14 05:56:00易采站长站整理

我们来看下具体的代码逻辑:


// @vue/cli/lib/add.js
async function add (pluginName, options = {}, context = process.cwd()) {
...
const packageManager = loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : 'npm')
// 开始安装这个插件
await installPackage(context, packageManager, null, packageName)
log(`${chalk.green('✔')} Successfully installed plugin: ${chalk.cyan(packageName)}`)
log()
// 判断插件是否提供了 generator
const generatorPath = resolveModule(`${packageName}/generator`, context)
if (generatorPath) {
invoke(pluginName, options, context)
} else {
log(`Plugin ${packageName} does not have a generator to invoke`)
}
}

首先 cli 内部会安装这个插件,并判断这个插件是否提供了 generator,若提供了那么去执行对应的 generator。


// @vue/cli/lib/invoke.js
async function invoke (pluginName, options = {}, context = process.cwd()) {
const pkg = getPkg(context)
...
// 从项目应用package.json中获取插件名
const id = findPlugin(pkg.devDependencies) || findPlugin(pkg.dependencies)
...
// 加载对应插件提供的generator方法
const pluginGenerator = loadModule(`${id}/generator`, context)
...
const plugin = {
id,
apply: pluginGenerator,
options
}
// 开始执行generator方法
await runGenerator(context, plugin, pkg)
}
async function runGenerator (context, plugin, pkg = getPkg(context)) {
...
// 实例化一个Generator实例
const generator = new Generator(context, {
pkg
plugins: [plugin], // 插件提供的generator方法
files: await readFiles(context), // 将项目当中的文件读取为字符串的形式保存到内存当中,被读取的文件规则具体见readFiles方法
completeCbs: createCompleteCbs,
invoking: true
})
...
// resolveFiles 将内存当中的所有缓存的 files 输出到文件当中
await generator.generate({
extractConfigFiles: true,
checkExisting: true
})
}

和 @vue/cli-service 类似,在 @vue/cli 内部也有一个核心的类 Generator ,每个 @vue/cli 的插件对应一个 Generator 的实例。在实例化 Generator 方法的过程当中,完成插件提供的 generator 的执行。


// @vue/cli/lib/Generator.js
module.exports = class Generator {
constructor (context, {
pkg = {},
plugins = [],
completeCbs = [],
files = {},
invoking = false
} = {}) {
this.context = context
this.plugins = plugins
this.originalPkg = pkg
this.pkg = Object.assign({}, pkg)
this.imports = {}