From e5d79e870fa5b9c3abb2bce802317f22301bc009 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Mon, 23 Apr 2018 01:34:04 +0200 Subject: [PATCH] docs(ui): WIP ui docs --- docs/plugin-dev-ui.md | 419 +++++++++++++++++++++++++++++++- docs/plugin-search-item.png | Bin 0 -> 16773 bytes packages/@vue/cli-service/ui.js | 2 +- 3 files changed, 419 insertions(+), 2 deletions(-) create mode 100644 docs/plugin-search-item.png diff --git a/docs/plugin-dev-ui.md b/docs/plugin-dev-ui.md index 6701a8661..c574272d6 100644 --- a/docs/plugin-dev-ui.md +++ b/docs/plugin-dev-ui.md @@ -44,6 +44,10 @@ You should add the url to the plugin website or repository in the `homepage` or } ``` +

+ +

+ ## UI API The cli-ui exposes an API that allows augmenting the project configurations and tasks, as well as sharing data and communicating with other processes. @@ -62,17 +66,430 @@ module.exports = api => { ### Project configurations +You can add a project configuration with the `api.describeConfig` method. + +First you need to pass some informations: + +```js +api.describeConfig({ + // Unique ID for the config + id: 'eslintrc', + // Displayed name + name: 'ESLint configuration', + // Shown below the name + description: 'Error checking & Code quality', + // "More info" link + link: 'https://eslint.org' +}) +``` + +Specify an icon with either a file type (like `'json'`) or a file name (like `.babelrc` to get the babel icon). This is powered by file-icons. + +```js +api.describeConfig({ + /* ... */ + // Icon generated using file-icons + icon: '.eslintrc.json' +}) +``` + +Then you can specify which files will be read when loading the configuration and then written to (JS files aren't supported yet): + +```js +api.describeConfig({ + /* ... */ + // All possible files for this config + files: { + json: ['.eslintrc', '.eslintrc.json'], + // Will read from `package.json` + package: 'eslintConfig' + }, +}) +``` + +Supported types: `json`, `yaml`, `package`. + +Use the `onRead` hook to return a list of prompts to be displayed for the configuration: + +```js +api.describeConfig({ + /* ... */ + onRead: ({ data }) => ({ + prompts: [ + // Prompt objects + ] + }) +}) +``` + +The prompt objects must be valid [inquirer](https://github.com/SBoudrias/Inquirer.js) prompts with the following additional fields (which are optional): + +```js +{ + /* ... */ + // Used to group the prompts into sections + group: 'Strongly recommended', + // Additional description + description: 'Enforce attribute naming style in template (`my-prop` or `myProp`)', + // "More info" link + link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attribute-hyphenation.md', +} +``` + +Supported inquirer types: `checkbox`, `confirm`, `input`, `password`, `list`, `rawlist`. + +Use the `onWrite` hook to write the data to the configuration file (or execute any node code): + +```js +api.describeConfig({ + /* ... */ + onWrite: ({ prompts, answers, data, file, api }) => { + // ... + } +}) +``` + +Arguments: + +- `prompts`: current prompts runtime objects +- `answers`: answers data from the user inputs +- `data`: initial data read from the file +- `file`: descriptor of the found file (`{ type: 'json', path: '...' }`) +- `api`: onWrite API + +Prompts runtime objects: + +```js +{ + id: data.name, + type: data.type, + name: data.short || null, + message: data.message, + group: data.group || null, + description: data.description || null, + link: data.link || null, + choices: null, + visible: true, + enabled: true, + // Current value (not filtered) + value: null, + // true if changed by user + valueChanged: false, + error: null, + // Original inquirer prompt object + raw: data +} +``` + +onWrite API: + +- `assignData(newData)`: use `Object.assign` to update the config data before writing. +- `setData(newData)`: each key of `newData` will be deeply set (or removed if `undefined` value) to the config data before writing. +- `async getAnswer(id, mapper)`: retrieve answer for a given prompt id and map it through `mapper` function if provide (for example `JSON.parse`). + ### Project tasks +Tasks are generated from the `scripts` field in the project `package.json` file. + +You can 'augment' the tasks with additional info and hooks thanks to the `api.describeTask` method: + +```js +api.describeTask({ + // RegExp executed on script commands to select which task will be described here + match: /vue-cli-service serve/, + description: 'Compiles and hot-reloads for development', + // "More info" link + link: 'https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#serve', + // Optional parameters (inquirer prompts) + prompts: [ + { + name: 'open', + type: 'confirm', + default: false, + description: 'Open browser on server start' + }, + { + name: 'mode', + type: 'list', + default: 'development', + choices: [ + { + name: 'development', + value: 'development' + }, + { + name: 'production', + value: 'production' + }, + { + name: 'test', + value: 'test' + } + ], + description: 'Specify env mode' + } + ], + // Hooks + // Modify arguments here + onBeforeRun: ({ answers, args }) => { + // Args + if (answers.open) args.push('--open') + if (answers.mode) args.push('--mode', answers.mode) + args.push('--dashboard') + }, + // Immediatly after running the task + onRun: ({ args, child, cwd }) => { + // child: node child process + // cwd: process working directory + }, + onExit: ({ args, child, cwd, code, signal }) => { + // code: exit code + // signal: kill signal used if any + }, + // Additional views (for example the webpack dashboard) + // By default, there is the 'output' view which displays the terminal output + views: [ + { + // Unique ID + id: 'vue-webpack-dashboard-client-addon', + // Button label + label: 'Dashboard', + // Button icon + icon: 'dashboard', + // Dynamic component to load (see 'Client addon' section below) + component: 'vue-webpack-dashboard' + } + ], + // Default selected view when displaying the task details (by default it's the output) + defaultView: 'vue-webpack-dashboard' +}) +``` + ### Client addon +A Client addon is a JS bundle which is dynamically loaded into the cli-ui. It is useful to load custom components and routes. + +#### Create a client addon + +The recommended way to create a Client addon is by creating a new project using vue-cli 3. You can either do this in a subfolder of your plugin or in a different npm package. + +Then add a `vue.config.js` file with the following content: + +```js +module.exports = { + // Change the id here + baseUrl: '/_addon/', + // You can change the port here + devBaseUrl: 'http://localhost:8042/', + configureWebpack: { + output: { + // Important + filename: 'index.js' + } + }, + // Don't extract CSS into a separate file + css: { + extract: false + }, + // Remove unneeded webpack plugins + chainWebpack: config => { + config.plugins.delete('preload') + config.plugins.delete('prefetch') + config.plugins.delete('html') + config.plugins.delete('split-vendor') + config.plugins.delete('split-vendor-async') + config.plugins.delete('split-manifest') + }, + // Configure dev server + devServer: { + headers: { + 'Access-Control-Allow-Origin': '*' + }, + // You can change the port here + port: 8042 + } +} +``` + +**Don't forget to replace `` in the `baseUrl` field with the id of your new client addon!** + +Then modify the `.eslintrc.json` file to add some allowed global objects: + +```json +{ + // ... + "globals": { + "ClientAddonApi": false, + "mapSharedData": false, + "Vue": false + } +} +``` + +You can now run the `serve` script in development and the `build` one when you are ready to publish your plugin. + +#### ClientAddonApi + +Open the `main.js` file in the client addon sources and remove all the code. + +**Don't import Vue in the client addon sources, use the global `Vue` object from the browser `window`.** + +Here is an example of code for `main.js`: + +```js +import VueProgress from 'vue-progress-path' +import WebpackDashboard from './components/WebpackDashboard.vue' +import TestView from './components/TestView.vue' + +// You can install additional vue plugins +// using the global 'Vue' variable +Vue.use(VueProgress, { + defaultShape: 'circle' +}) + +// Register a custom component +// (works like 'Vue.component') +ClientAddonApi.component('vue-webpack-dashboard', WebpackDashboard) + +// Add routes to vue-router under a /addon/ parent route. +// For example, addRoutes('foo', [ { path: '' }, { path: 'bar' } ]) +// will add the /addon/foo/ and the /addon/foo/bar routes to vue-router. +// Here we create a new '/addon/vue-webpack/' route with the 'test-webpack-route' name +ClientAddonApi.addRoutes('vue-webpack', [ + { path: '', name: 'test-webpack-route', component: TestView } +]) +``` + +The cli-ui registers `Vue` and `ClientAddonApi` as global variable in the `window` scope. + +#### Register the client addon + +**Back to the UI API (in the `ui.js` file).** + +Use the `api.addClientAddon` method with a require query to the built folder: + +```js +api.addClientAddon({ + id: 'vue-webpack', + // Folder containing the built JS files + path: '@vue/cli-ui-addon-webpack/dist' +}) +``` + +Or specify an url when developping the plugin (ideally you want to do this in the `vue-cli-ui.js` file in your test vue project): + +```js +// Useful for dev +// Will override path if already defined in a plugin +api.addClientAddon({ + id: 'vue-webpack', + // Use the same port you configured earlier + url: 'http://localhost:8042/index.js' +}) +``` + +#### Use the client addon + +You can now use the client addon in the views. For example, you can specify a view in a described task: + +```js +api.describeTask({ + /* ... */ + // Additional views (for example the webpack dashboard) + // By default, there is the 'output' view which displays the terminal output + views: [ + { + // Unique ID + id: 'vue-webpack-dashboard-client-addon', + // Button label + label: 'Dashboard', + // Button icon (material-icons) + icon: 'dashboard', + // Dynamic component to load, registered using ClientAddonApi + component: 'vue-webpack-dashboard' + } + ], + // Default selected view when displaying the task details (by default it's the output) + defaultView: 'vue-webpack-dashboard' +}) +``` + +### Custom views + +You can add a new view below the standard 'Project plugins', 'Project configuration' and 'Project tasks' ones using the `api.addView` method: + +```js +api.addView({ + // Unique id + id: 'vue-webpack-test-view', + + // Route name (from vue-router) + // Use the same name used in the 'ClientAddonApi.addRoutes' method (see above in the Client addon section) + name: 'test-webpack-route', + + // Button icon (material-icons) + icon: 'pets', + // You can also specify a custom image (see Public static files section below): + // icon: 'http://localhost:4000/_plugin/%40vue%2Fcli-service/webpack-icon.svg', + + // Button tooltip + tooltip: 'Test view from webpack addon' +}) +``` + ### Shared data +Use Shared data to communicate info with custom components in an easy way. + +In the plugin `ui.js`: + +```js +// Set or update +api.setSharedData('my-variable', 'some-data') +// Get +api.getSharedData('my-variable') +// Namespaced versions +const { setSharedData, getSharedData } = api.namespace('webpack-dashboard-') +``` + +In the custom component: + +```js +{ + // Sync Shared data + sharedData () { + return { + // You can use `status` in template + status: `webpack-dashboard-${this.mode}-status` + // You can also map namespaced Shared data + ...mapSharedData('webpack-dashboard-', { + status: `${this.mode}-status`, + progress: `${this.mode}-progress`, + operations: `${this.mode}-operations` + }) + } + }, + + // Manual methods + async created () { + const value = await this.$getSharedData('my-variable') + + this.$watchSharedData(`my-variable`, value => { + console.log(value) + }) + + await this.$setSharedData('my-variable', 'new-value') + } +} +``` + ### Plugin actions +TODO + ### IPC -### Custom views +TODO ### Public static files diff --git a/docs/plugin-search-item.png b/docs/plugin-search-item.png new file mode 100644 index 0000000000000000000000000000000000000000..004ec10da01d5b6210561f340a44ae9a369d5943 GIT binary patch literal 16773 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 X*w?Ct7`o^8C;&-|D~Q#I7zX_xo7sD+ literal 0 HcmV?d00001 diff --git a/packages/@vue/cli-service/ui.js b/packages/@vue/cli-service/ui.js index 77540d969..2590acdcb 100644 --- a/packages/@vue/cli-service/ui.js +++ b/packages/@vue/cli-service/ui.js @@ -197,7 +197,7 @@ module.exports = api => { defaultView: 'vue-webpack-dashboard' }) - // Testing client addon + // Webpack dashboard api.addClientAddon({ id: 'vue-webpack', path: '@vue/cli-ui-addon-webpack/dist'