上一篇已讲了create敕令;
那末这一篇我们来看一下add和invoke这个敕令。之所以放一同讲,是因为当add实行的时刻,也会去实行invoke
add
vue add vue-cli-plugin-xxx 或 vue add @vue/xxx
经由过程这类情势就是vue-cli3.0内部能辨认的插件了
起首来看一下进口
program
.command('add <plugin> [pluginOptions]')
.description('install a plugin and invoke its generator in an already created project')
.option('--registry <url>', 'Use specified npm registry when installing dependencies (only for npm)') // 能够设置源
.allowUnknownOption()
.action((plugin) => {
require('../lib/add')(plugin, minimist(process.argv.slice(3)))
})
进口比较简单,接下来我们来看一下add.js文件
async function add (pluginName, options = {}, context = process.cwd()) {
// special internal "plugins"
// 这边对@vue/router和@vue/vuex这2个插件做特别处置惩罚,直接从cli-service下拉模块
if (/^(@vue\/)?router$/.test(pluginName)) {
return addRouter(context)
}
if (/^(@vue\/)?vuex$/.test(pluginName)) {
return addVuex(context)
}
const packageName = resolvePluginId(pluginName) // 剖析插件名
log()
log(`📦 Installing ${chalk.cyan(packageName)}...`)
log()
const packageManager = loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : 'npm')
// 是用什么装置 npm、yarn
await installPackage(context, packageManager, options.registry, packageName) // 最先装置插件
log(`${chalk.green('✔')} Successfully installed plugin: ${chalk.cyan(packageName)}`)
log()
const generatorPath = resolveModule(`${packageName}/generator`, context) // 剖析途径
// 最先加载插件下面的generator
if (generatorPath) {
invoke(pluginName, options, context)
} else {
log(`Plugin ${packageName} does not have a generator to invoke`)
}
}
这边也比较简单一览无余。
async function addRouter (context) {
const inquirer = require('inquirer')
const options = await inquirer.prompt([{
name: 'routerHistoryMode',
type: 'confirm',
message: `Use history mode for router? ${chalk.yellow(`(Requires proper server setup for index fallback in production)`)}`
}])
invoke.runGenerator(context, {
id: 'core:router',
apply: loadModule('@vue/cli-service/generator/router', context),
options
})
}
async function addVuex (context) {
invoke.runGenerator(context, {
id: 'core:vuex',
apply: loadModule('@vue/cli-service/generator/vuex', context)
})
}
这2个就是零丁增加router和vuex
exports.resolvePluginId = id => {
// already full id
// e.g. vue-cli-plugin-foo, @vue/cli-plugin-foo, @bar/vue-cli-plugin-foo
if (pluginRE.test(id)) {
return id
}
// scoped short
// e.g. @vue/foo, @bar/foo
if (id.charAt(0) === '@') {
const scopeMatch = id.match(scopeRE)
if (scopeMatch) {
const scope = scopeMatch[0]
const shortId = id.replace(scopeRE, '')
return `${scope}${scope === '@vue/' ? `` : `vue-`}cli-plugin-${shortId}`
}
}
// default short
// e.g. foo
return `vue-cli-plugin-${id}`
}
将@vue/xxx的外形剖析为vue-cli-plugin-xxx
这边的重要流程就是装置插件并注入invoke
invoke
一样我们先来看一看进口
program
.command('invoke <plugin> [pluginOptions]')
.description('invoke the generator of a plugin in an already created project')
.option('--registry <url>', 'Use specified npm registry when installing dependencies (only for npm)')
.allowUnknownOption()
.action((plugin) => {
require('../lib/invoke')(plugin, minimist(process.argv.slice(3)))
})
在add中的代码与进口挪用是一样的,都是经由过程挪用invoke.js
invoke(pluginName, options, context)
那末就来看看invoke.js内部是怎样完成的,重要就是分为以下几步
- 信息考证
- 加载插件信息generator/prompts
- 运转Generator
信息考证:
const pkg = getPkg(context) // package文件
// attempt to locate the plugin in package.json
const findPlugin = deps => {
if (!deps) return
let name
// official
if (deps[(name = `@vue/cli-plugin-${pluginName}`)]) {
return name
}
// full id, scoped short, or default short
if (deps[(name = resolvePluginId(pluginName))]) {
return name
}
}
const id = findPlugin(pkg.devDependencies) || findPlugin(pkg.dependencies)
// 在devDependencies和dependencies依靠中寻觅vue-cli插件
if (!id) {
throw new Error(
`Cannot resolve plugin ${chalk.yellow(pluginName)} from package.json. ` +
`Did you forget to install it?`
)
}
以上考证是不是存在package.json文件,以及package文件内是不是装置了vue-cli插件
加载插件
const pluginGenerator = loadModule(`${id}/generator`, context)
// 加载插件下的generator文件
if (!pluginGenerator) {
throw new Error(`Plugin ${id} does not have a generator.`)
}
// resolve options if no command line options (other than --registry) are passed,
// and the plugin contains a prompt module.
// eslint-disable-next-line prefer-const
let { registry, ...pluginOptions } = options
if (!Object.keys(pluginOptions).length) {
let pluginPrompts = loadModule(`${id}/prompts`, context)
// 加载插件下的prompts,对话
if (pluginPrompts) {
if (typeof pluginPrompts === 'function') {
pluginPrompts = pluginPrompts(pkg)
}
if (typeof pluginPrompts.getPrompts === 'function') {
pluginPrompts = pluginPrompts.getPrompts(pkg)
}
pluginOptions = await inquirer.prompt(pluginPrompts)
}
}
以上就是加载了generator和prompts,用来运转插件的一些内置代码
Generator
const generator = new Generator(context, {
pkg,
plugins: [plugin],
files: await readFiles(context),
completeCbs: createCompleteCbs,
invoking: true
})
这边的跟create中一样结果
末了
router和vuex是直接到Generator步骤,前面的加载省略了。