@vue/cli
Version:
Command line interface for rapid Vue.js development
168 lines (143 loc) • 4.44 kB
JavaScript
const inquirer = require('inquirer')
const {
chalk,
log,
error,
logWithSpinner,
stopSpinner,
resolvePluginId,
loadModule
} = require('@vue/cli-shared-utils')
const Generator = require('./Generator')
const confirmIfGitDirty = require('./util/confirmIfGitDirty')
const readFiles = require('./util/readFiles')
const getPkg = require('./util/getPkg')
const getChangedFiles = require('./util/getChangedFiles')
const PackageManager = require('./util/ProjectPackageManager')
async function invoke (pluginName, options = {}, context = process.cwd()) {
if (!(await confirmIfGitDirty(context))) {
return
}
delete options._
const pkg = getPkg(context)
// 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)
if (!id) {
throw new Error(
`Cannot resolve plugin ${chalk.yellow(pluginName)} from package.json. ` +
`Did you forget to install it?`
)
}
const pluginGenerator = loadModule(`${id}/generator`, context)
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, $inlineOptions, ...pluginOptions } = options
if ($inlineOptions) {
try {
pluginOptions = JSON.parse($inlineOptions)
} catch (e) {
throw new Error(`Couldn't parse inline options JSON: ${e.message}`)
}
} else if (!Object.keys(pluginOptions).length) {
let pluginPrompts = loadModule(`${id}/prompts`, context)
if (pluginPrompts) {
const prompt = inquirer.createPromptModule()
if (typeof pluginPrompts === 'function') {
pluginPrompts = pluginPrompts(pkg, prompt)
}
if (typeof pluginPrompts.getPrompts === 'function') {
pluginPrompts = pluginPrompts.getPrompts(pkg, prompt)
}
pluginOptions = await prompt(pluginPrompts)
}
}
const plugin = {
id,
apply: pluginGenerator,
options: {
registry,
...pluginOptions
}
}
await runGenerator(context, plugin, pkg)
}
async function runGenerator (context, plugin, pkg = getPkg(context)) {
const isTestOrDebug = process.env.VUE_CLI_TEST || process.env.VUE_CLI_DEBUG
const afterInvokeCbs = []
const afterAnyInvokeCbs = []
const generator = new Generator(context, {
pkg,
plugins: [plugin],
files: await readFiles(context),
afterInvokeCbs,
afterAnyInvokeCbs,
invoking: true
})
log()
log(`🚀 Invoking generator for ${plugin.id}...`)
await generator.generate({
extractConfigFiles: true,
checkExisting: true
})
const newDeps = generator.pkg.dependencies
const newDevDeps = generator.pkg.devDependencies
const depsChanged =
JSON.stringify(newDeps) !== JSON.stringify(pkg.dependencies) ||
JSON.stringify(newDevDeps) !== JSON.stringify(pkg.devDependencies)
if (!isTestOrDebug && depsChanged) {
log(`📦 Installing additional dependencies...`)
log()
const pm = new PackageManager({ context })
await pm.install()
}
if (afterInvokeCbs.length || afterAnyInvokeCbs.length) {
logWithSpinner('⚓', `Running completion hooks...`)
for (const cb of afterInvokeCbs) {
await cb()
}
for (const cb of afterAnyInvokeCbs) {
await cb()
}
stopSpinner()
log()
}
log(`${chalk.green('✔')} Successfully invoked generator for plugin: ${chalk.cyan(plugin.id)}`)
const changedFiles = getChangedFiles(context)
if (changedFiles.length) {
log(` The following files have been updated / added:\n`)
log(chalk.red(changedFiles.map(line => ` ${line}`).join('\n')))
log()
log(
` You should review these changes with ${chalk.cyan(
'git diff'
)} and commit them.`
)
log()
}
generator.printExitLogs()
}
module.exports = (...args) => {
return invoke(...args).catch(err => {
error(err)
if (!process.env.VUE_CLI_TEST) {
process.exit(1)
}
})
}
module.exports.runGenerator = runGenerator