5.2 KiB
Plugin Development Guide
Important Development Note
A plugin with a generator that injects additional dependencies other than packages in this repo (e.g. chai is injected by @vue/cli-plugin-unit-mocha/generator/index.js) should have those dependencies listed in its own devDependencies field. This ensures that:
-
the package always exist in this repo's root
node_modulesso that we don't have to reinstall them on every test. -
yarn.lockstays consistent so that CI can better use it for inferring caching behavior.
Core Concepts
There are two major parts of the system:
@vue/cli: globally installed, exposes thevue create <app>command;@vue/cli-service: locally installed, exposes thevue-cli-servicecommands.
Both utilize a plugin-based architecture.
Creator
Creator is the class created when invoking vue create <app>. Responsible for prompting for preferences, invoking generators and installing dependencies.
Service
Service is the class created when invoking vue-cli-service <command> [...args]. Responsible for managing the internal webpack configuration, and exposes commands for serving and building the project.
Plugin
Plugins are locally installed into the project as dependencies. @vue/cli-service's built-in commands and config modules are also all implemented as plugins. This repo also contains a number of plugins that are published as individual packages.
A plugin should export a function which receives two arguments:
-
A PluginAPI instance
-
Project local options specified in
vue.config.js, or in the"vue-cli"field inpackage.json.
The API allows plugins to extend/modify the internal webpack config for different environments and inject additional commands to vue-cli-service. Example:
module.exports = (api, projectOptions) => {
api.chainWebpack(webpackConfig => {
// modify webpack config with webpack-chain
})
api.configureWepback(webpackConfig => {
// modify webpack config
// or return object to be merged with webpack-merge
})
api.regsiterCommand('test', args => {
// register `vue-cli-service test`
})
}
Generator
A plugin published as a package can also contain a generator.js or generator/index.js file. The generator inside a plugin will be invoked after the plugin is installed.
The GeneratorAPI allows a generator to inject additional dependencies or fields into package.json and add files to the project.
A generator should export a function which receives three arguments:
-
A
GeneratorAPIinstance; -
The generator options for this plugin. These options are resolved during the prompt phase of project creation, or loaded from a saved
~/.vuerc. For example, if the saved~/.vuerclooks like this:{ "plugins": { "@vue/cli-plugin-foo": { "option": "bar" } } }Then the plugin
@vue/cli-plugin-foowill receive{ option: 'bar' }as its second argument. -
The entire
.vuercobject will be passed as the third argument.
Example:
module.exports = (api, options, rootOptions) => {
// modify package.json fields
api.extendPackage({
scripts: {
test: 'vue-cli-service test'
}
})
// copy and render all files in ./template with ejs
api.render('./template')
if (options.foo) {
// conditionally generate files
}
}
Prompt Modules
Currently, only built-in plugins have the ability to customize the prompts when creating a new project, and the prompt modules are located inside the @vue/cli package.
A prompt module should export a function that recieves a [PromptModuleAPI][prompt-api] instance. The prompts uses inquirer under the hood:
module.exports = api => {
// a feature object should be a valid inquirer choice object
cli.injectFeature({
name: 'Some great feature',
value: 'my-feature'
})
// injectPrompt expects a valid inquirer prompt object
cli.injectPrompt({
name: 'someFlag',
// make sure your prompt only shows up if user has picked your feature
when: answers => answers.features.include('my-feature'),
message: 'Do you want to turn on flag foo?',
type: 'confirm'
})
// when all prompts are done, inject your plugin into the options that
// will be passed on to Generators
cli.onPromptComplete((answers, options) => {
if (answers.features.includes('my-feature')) {
options.plugins['vue-cli-plugin-my-feature'] = {
someFlag: answers.someFlag
}
}
})
}