diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 867e7c1057..5e2cd95f0b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -14,7 +14,12 @@ module.exports = { lang: 'ru', title: 'Vue CLI', description: '🛠️ Стандартный инструментарий для разработки на Vue.js' - } + }, + '/ja/': { + lang: 'ja', + title: 'Vue CLI', + description: '🛠️ Vue.js 開発用の標準ツール' + }, }, head: [ ['link', { rel: 'icon', href: '/favicon.png' }], @@ -42,7 +47,11 @@ module.exports = { '/ru/': { message: 'Доступно обновление контента', buttonText: 'Обновить' - } + }, + '/ja/': { + message: "新しいコンテンツが利用可能です。", + buttonText: "更新" + }, } } }, @@ -328,7 +337,111 @@ module.exports = { } ] } - } + }, + '/ja/': { + label: '日本語', + selectText: '言語', + lastUpdated: '最終更新日', + editLinkText: 'GitHub でこのページを編集する', + nav: [ + { + text: 'ガイド', + link: '/ja/guide/' + }, + { + text: '構成リファレンス', + link: '/ja/config/' + }, + { + text: 'プラグイン開発ガイド', + items: [ + { text: 'プラグイン開発ガイド', link: '/ja/dev-guide/plugin-dev.md' }, + { text: 'UI プラグイン情報', link: '/ja/dev-guide/ui-info.md' }, + { text: 'UI プラグイン API', link: '/ja/dev-guide/ui-api.md' }, + { text: 'UI ローカライズ', link: '/ja/dev-guide/ui-localization.md' } + ] + }, + { + text: 'プラグイン', + items: [ + { text: 'コアプラグイン', link: '/ja/core-plugins/' }, + { text: 'ブラウザプラグイン', link: 'https://awesomejs.dev/for/vue-cli/' } + ] + }, + { + text: 'v3からの移行', + link: '/ja/migrating-from-v3/' + }, + { + text: '変更履歴', + link: 'https://github.com/vuejs/vue-cli/blob/dev/CHANGELOG.md' + } + ], + sidebar: { + '/ja/guide/': [ + '/ja/guide/', + '/ja/guide/installation', + { + title: '基本', + collapsable: false, + children: [ + '/ja/guide/prototyping', + '/ja/guide/creating-a-project', + '/ja/guide/plugins-and-presets', + '/ja/guide/cli-service' + ] + }, + { + title: '開発', + collapsable: false, + children: [ + '/ja/guide/browser-compatibility', + '/ja/guide/html-and-static-assets', + '/ja/guide/css', + '/ja/guide/webpack', + '/ja/guide/mode-and-env', + '/ja/guide/build-targets', + '/ja/guide/deployment', + '/ja/guide/troubleshooting' + ] + } + ], + '/ja/dev-guide/': [ + '/ja/dev-guide/plugin-dev.md', + { + title: 'API リファレンス', + collapsable: false, + children: [ + '/ja/dev-guide/plugin-api.md', + '/ja/dev-guide/generator-api.md', + ] + }, + { + title: 'UI 開発', + collapsable: false, + children: [ + '/ja/dev-guide/ui-info.md', + '/ja/dev-guide/ui-api.md', + '/ja/dev-guide/ui-localization.md' + ] + } + ], + '/ja/core-plugins/': [{ + title: 'コア Vue CLI プラグイン', + collapsable: false, + children: [ + '/ja/core-plugins/babel.md', + '/ja/core-plugins/typescript.md', + '/ja/core-plugins/eslint.md', + '/ja/core-plugins/pwa.md', + '/ja/core-plugins/unit-jest.md', + '/ja/core-plugins/unit-mocha.md', + '/ja/core-plugins/e2e-cypress.md', + '/ja/core-plugins/e2e-nightwatch.md' + ] + }], + } + }, } } } diff --git a/docs/ja/README.md b/docs/ja/README.md new file mode 100644 index 0000000000..2e4204594d --- /dev/null +++ b/docs/ja/README.md @@ -0,0 +1,52 @@ +--- +home: true +heroImage: /favicon.png +actionText: はじめる → +actionLink: /guide/ +footer: MIT Licensed | Copyright © 2018-present Evan You +--- + +
+
+

豊富な機能

+

Babel, TypeScript, ESLint, PostCSS, PWA, Unit Test, E2E Test などを標準でサポート。

+
+
+

拡張可能

+

プラグインシステムにより、コミュニティは一般的なニーズに合わせて再利用可能なソリューションを構築および共有できます。

+
+
+

取り出す必要はない

+

Vue CLIは、取り出すことなく設定可能です。これにより、プロジェクトを長期にわたって最新の状態に保つことができます。

+
+
+

グラフィカル・ユーザー・インターフェース

+

付属のグラフィカルユーザーインターフェイスを使用して、プロジェクトを作成、開発、管理します。

+
+
+

簡単なプロトタイピング

+

単一ファイルコンポーネントを使用して、新しいアイデアを即座にプロトタイプ化します。

+
+
+

将来に向けて

+

最新のブラウザ向けにネイティブのES2015のコードを簡単に出荷するか、vueコンポーネントをネイティブのWebコンポーネントとしてビルドします。

+
+
+ +## はじめる + +インストール: + +``` bash +npm install -g @vue/cli +# もしくは +yarn global add @vue/cli +``` + +プロジェクトの作成: + +``` bash +vue create my-project +# もしくは +vue ui +``` \ No newline at end of file diff --git a/docs/ja/config/README.md b/docs/ja/config/README.md new file mode 100644 index 0000000000..1fc6b33c52 --- /dev/null +++ b/docs/ja/config/README.md @@ -0,0 +1,448 @@ +--- +sidebar: auto +--- + +# Configuration Reference + +## Global CLI Config + +Some global configurations for `@vue/cli`, such as your preferred package manager and your locally saved presets, are stored in a JSON file named `.vuerc` in your home directory. You can edit this file directly with your editor of choice to change the saved options. + +You can also use the `vue config` command to inspect or modify the global CLI config. + +## Target Browsers + +See the [Browser Compatibility](../guide/browser-compatibility.md#browserslist) section in guide. + +## vue.config.js + +`vue.config.js` is an optional config file that will be automatically loaded by `@vue/cli-service` if it's present in your project root (next to `package.json`). You can also use the `vue` field in `package.json`, but do note in that case you will be limited to JSON-compatible values only. + +The file should export an object containing options: + +``` js +// vue.config.js +module.exports = { + // options... +} +``` + +### baseUrl + +Deprecated since Vue CLI 3.3, please use [`publicPath`](#publicPath) instead. + +### publicPath + +- Type: `string` +- Default: `'/'` + + The base URL your application bundle will be deployed at (known as `baseUrl` before Vue CLI 3.3). This is the equivalent of webpack's `output.publicPath`, but Vue CLI also needs this value for other purposes, so you should **always use `publicPath` instead of modifying webpack `output.publicPath`**. + + By default, Vue CLI assumes your app will be deployed at the root of a domain, e.g. `https://www.my-app.com/`. If your app is deployed at a sub-path, you will need to specify that sub-path using this option. For example, if your app is deployed at `https://www.foobar.com/my-app/`, set `publicPath` to `'/my-app/'`. + + The value can also be set to an empty string (`''`) or a relative path (`./`) so that all assets are linked using relative paths. This allows the built bundle to be deployed under any public path, or used in a file system based environment like a Cordova hybrid app. + + ::: warning Limitations of relative publicPath + Relative `publicPath` has some limitations and should be avoided when: + + - You are using HTML5 `history.pushState` routing; + + - You are using the `pages` option to build a multi-paged app. + ::: + + This value is also respected during development. If you want your dev server to be served at root instead, you can use a conditional value: + + ``` js + module.exports = { + publicPath: process.env.NODE_ENV === 'production' + ? '/production-sub-path/' + : '/' + } + ``` + +### outputDir + +- Type: `string` +- Default: `'dist'` + + The directory where the production build files will be generated in when running `vue-cli-service build`. Note the target directory will be removed before building (this behavior can be disabled by passing `--no-clean` when building). + + ::: tip + Always use `outputDir` instead of modifying webpack `output.path`. + ::: + +### assetsDir + +- Type: `string` +- Default: `''` + + A directory (relative to `outputDir`) to nest generated static assets (js, css, img, fonts) under. + + ::: tip + `assetsDir` is ignored when overwriting the filename or chunkFilename from the generated assets. + ::: + +### indexPath + +- Type: `string` +- Default: `'index.html'` + + Specify the output path for the generated `index.html` (relative to `outputDir`). Can also be an absolute path. + +### filenameHashing + +- Type: `boolean` +- Default: `true` + + By default, generated static assets contains hashes in their filenames for better caching control. However, this requires the index HTML to be auto-generated by Vue CLI. If you cannot make use of the index HTML generated by Vue CLI, you can disable filename hashing by setting this option to `false`. + +### pages + +- Type: `Object` +- Default: `undefined` + + Build the app in multi-page mode. Each "page" should have a corresponding JavaScript entry file. The value should be an object where the key is the name of the entry, and the value is either: + + - An object that specifies its `entry`, `template`, `filename`, `title` and `chunks` (all optional except `entry`). Any other properties added beside those will also be passed directly to `html-webpack-plugin`, allowing user to customize said plugin; + - Or a string specifying its `entry`. + + ``` js + module.exports = { + pages: { + index: { + // entry for the page + entry: 'src/index/main.js', + // the source template + template: 'public/index.html', + // output as dist/index.html + filename: 'index.html', + // when using title option, + // template title tag needs to be <%= htmlWebpackPlugin.options.title %> + title: 'Index Page', + // chunks to include on this page, by default includes + // extracted common chunks and vendor chunks. + chunks: ['chunk-vendors', 'chunk-common', 'index'] + }, + // when using the entry-only string format, + // template is inferred to be `public/subpage.html` + // and falls back to `public/index.html` if not found. + // Output filename is inferred to be `subpage.html`. + subpage: 'src/subpage/main.js' + } + } + ``` + + ::: tip + When building in multi-page mode, the webpack config will contain different plugins (there will be multiple instances of `html-webpack-plugin` and `preload-webpack-plugin`). Make sure to run `vue inspect` if you are trying to modify the options for those plugins. + ::: + +### lintOnSave + +- Type: `boolean | 'warning' | 'default' | 'error'` +- Default: `true` + + Whether to perform lint-on-save during development using [eslint-loader](https://github.com/webpack-contrib/eslint-loader). This value is respected only when [`@vue/cli-plugin-eslint`](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint) is installed. + + When set to `true` or `'warning'`, `eslint-loader` will emit lint errors as warnings. By default, warnings are only logged to the terminal and does not fail the compilation, so this is a good default for development. + + To make lint errors show up in the browser overlay, you can use `lintOnSave: 'default'`. This will force `eslint-loader` to actually emit errors. this also means lint errors will now cause the compilation to fail. + + Setting it to `'errors'` will force eslint-loader to emit warnings as errors as well, which means warnings will also show up in the overlay. + + Alternatively, you can configure the overlay to display both warnings and errors: + + ``` js + // vue.config.js + module.exports = { + devServer: { + overlay: { + warnings: true, + errors: true + } + } + } + ``` + + When `lintOnSave` is a truthy value, `eslint-loader` will be applied in both development and production. If you want to disable `eslint-loader` during production build, you can use the following config: + + ``` js + // vue.config.js + module.exports = { + lintOnSave: process.env.NODE_ENV !== 'production' + } + ``` + +### runtimeCompiler + +- Type: `boolean` +- Default: `false` + + Whether to use the build of Vue core that includes the runtime compiler. Setting it to `true` will allow you to use the `template` option in Vue components, but will incur around an extra 10kb payload for your app. + + See also: [Runtime + Compiler vs. Runtime only](https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only). + +### transpileDependencies + +- Type: `Array` +- Default: `[]` + + By default `babel-loader` ignores all files inside `node_modules`. If you want to explicitly transpile a dependency with Babel, you can list it in this option. + +::: warning Jest config +This option is not respected by the [cli-unit-jest plugin](#jest), because in jest, we don't have to transpile code from `/node_modules` unless it uses non-standard features - Node >8.11 supports the latest ECMAScript features already. + +However, jest sometimes has to transform content from node_modules if that code uses ES6 `import`/`export` syntax. In that case, use the `transformIgnorePatterns` option in `jest.config.js`. + +See [the plugin's README](https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-plugin-unit-jest/README.md) for more information. +::: + +### productionSourceMap + +- Type: `boolean` +- Default: `true` + + Setting this to `false` can speed up production builds if you don't need source maps for production. + +### crossorigin + +- Type: `string` +- Default: `undefined` + + Configure the `crossorigin` attribute on `` and ` +``` + +It's also possible to do multiple replaces, although you will need to wrap your replace strings within `<%# REPLACE %>` and `<%# END_REPLACE %>` blocks: + +``` ejs +--- +extend: '@vue/cli-service/generator/template/src/App.vue' +replace: + - !!js/regexp /Welcome to Your Vue\.js App/ + - !!js/regexp / +<%# END_REPLACE %> +``` + +### Filename edge cases + +If you want to render a template file that either begins with a dot (i.e. `.env`) you will have to follow a specific naming convention, since dotfiles are ignored when publishing your plugin to npm: + +```bash +# dotfile templates have to use an underscore instead of the dot: + +/generator/template/_env + +# When calling api.render('./template'), this will be rendered in the project folder as: + +/generator/template/.env +``` + +Consequently, this means that you also have to follow a special naming convention if you want to render file whose name actually begins with an underscore: + +```bash +# such templates have to use two underscores instead of one: + +/generator/template/__variables.scss + +# When calling api.render('./template'), this will be rendered in the project folder as: + +/generator/template/_variables.scss +``` + + +### Extending package + +If you need to add an additional dependency to the project, create a new npm script or modify `package.json` in any other way, you can use API `extendPackage` method. + +```js +// generator/index.js + +module.exports = api => { + api.extendPackage({ + dependencies: { + 'vue-router-layout': '^0.1.2' + } + }) +} +``` + +In the example above we added one dependency: `vue-router-layout`. During the plugin invocation this npm module will be installed and this dependency will be added to the user `package.json` file. + +With the same API method we can add new npm tasks to the project. To do so, we need to specify task name and a command that should be run in the `scripts` section of the user `package.json`: + +```js +// generator/index.js + +module.exports = api => { + api.extendPackage({ + scripts: { + greet: 'vue-cli-service greet' + } + }) +} +``` + +In the example above we're adding a new `greet` task to run a custom vue-cli service command created in [Service section](#add-a-new-cli-service-command). + +### Changing main file + +With generator methods you can make changes to the project files. The most usual case is some modifications to `main.js` or `main.ts` file: new imports, new `Vue.use()` calls etc. + +Let's consider the case where we have created a `router.js` file via [templating](#creating-new-templates) and now we want to import this router to the main file. We will use two Generator API methods: `entryFile` will return the main file of the project (`main.js` or `main.ts`) and `injectImports` serves for adding new imports to this file: + +```js +// generator/index.js + +api.injectImports(api.entryFile, `import router from './router'`) +``` + +Now, when we have a router imported, we can inject this router to the Vue instance in the main file. We will use `afterInvoke` hook which is to be called when the files have been written to disk. + +First, we need to read main file content with Node `fs` module (which provides an API for interacting with the file system) and split this content on lines: + +```js +// generator/index.js + +module.exports.hooks = (api) => { + api.afterInvoke(() => { + const fs = require('fs') + const contentMain = fs.readFileSync(api.entryFile, { encoding: 'utf-8' }) + const lines = contentMain.split(/\r?\n/g) + }) +} +``` + +Then we should to find the string containing `render` word (it's usually a part of Vue instance) and add our `router` as a next string: + +```js{9-10} +// generator/index.js + +module.exports.hooks = (api) => { + api.afterInvoke(() => { + const fs = require('fs') + const contentMain = fs.readFileSync(api.entryFile, { encoding: 'utf-8' }) + const lines = contentMain.split(/\r?\n/g) + + const renderIndex = lines.findIndex(line => line.match(/render/)) + lines[renderIndex] += `\n router,` + }) +} +``` + +Finally, you need to write the content back to the main file: + +```js{12-13} +// generator/index.js + +module.exports.hooks = (api) => { + api.afterInvoke(() => { + const { EOL } = require('os') + const fs = require('fs') + const contentMain = fs.readFileSync(api.entryFile, { encoding: 'utf-8' }) + const lines = contentMain.split(/\r?\n/g) + + const renderIndex = lines.findIndex(line => line.match(/render/)) + lines[renderIndex] += `${EOL} router,` + + fs.writeFileSync(api.entryFile, lines.join(EOL), { encoding: 'utf-8' }) + }) +} +``` + +## Service Plugin + +Service plugin serves for modifying webpack config, creating new vue-cli service commands or changing existing commands (such as `serve` and `build`). + +Service plugins are loaded automatically when a Service instance is created - i.e. every time the `vue-cli-service` command is invoked inside a project. It's located in the `index.js` file in CLI plugin root folder. + +A service plugin should export a function which receives two arguments: + +- A [PluginAPI](plugin-api.md) instance + +- An object containing project local options specified in `vue.config.js`, or in the `"vue"` field in `package.json`. + +The minimal required code in the service plugin file is the following: + +```js +module.exports = () => {} +``` + +### Modifying webpack config + +The API allows service plugins to extend/modify the internal webpack config for different environments. For example, here we're modifying webpack config with webpack-chain to include `vue-auto-routing` webpack plugin with given parameters: + +```js +const VueAutoRoutingPlugin = require('vue-auto-routing/lib/webpack-plugin') + +module.exports = (api, options) => { + api.chainWebpack(webpackConfig => { + webpackConfig + .plugin('vue-auto-routing') + .use(VueAutoRoutingPlugin, [ + { + pages: 'src/pages', + nested: true + } + ]) + }) +} +``` + +You can also use `configureWebpack` method to modify the webpack config or return object to be merged with webpack-merge. + +### Add a new cli-service command + +With service plugin you can register a new cli-service command in addition to standard ones (i.e. `serve` and `build`). You can do it with a `registerCommand` API method. + +Here is an example of creating a simple new command that will print a greeting to developer console: + +```js +api.registerCommand( + 'greet', + { + description: 'Writes a greeting to the console', + usage: 'vue-cli-service greet' + }, + () => { + console.log(`👋 Hello`) + } +) +``` + +In this example we provided the command name (`'greet'`), an object of command options with `description` and `usage`, and a function that will be run on `vue-cli-service greet` command. + +:::tip +You can add new command to the list of project npm scripts inside the `package.json` file [via Generator](#extending-package). +::: + +If you try to run a new command in the project with your plugin installed, you will see the following output: + +```bash +$ vue-cli-service greet +👋 Hello! +``` + +You can also specify a list of available options for a new command. Let's add the option `--name` and change the function to print this name if it's provided. + +```js +api.registerCommand( + 'greet', + { + description: 'Writes a greeting to the console', + usage: 'vue-cli-service greet [options]', + options: { '--name': 'specifies a name for greeting' } + }, + args => { + if (args.name) { + console.log(`👋 Hello, ${args.name}!`); + } else { + console.log(`👋 Hello!`); + } + } +); +``` + +Now, if you a `greet` command with a specified `--name` option, this name will be added to console message: + +```bash +$ vue-cli-service greet --name 'John Doe' +👋 Hello, John Doe! +``` + +### Modifying existing cli-service command + +If you want to modify an existing cli-service command, you can retrieve it with `api.service.commands` and add some changes. We're going to print a message to the console with a port where application is running: + +```js +const { serve } = api.service.commands + +const serveFn = serve.fn + +serve.fn = (...args) => { + return serveFn(...args).then(res => { + if (res && res.url) { + console.log(`Project is running now at ${res.url}`) + } + }) +} +``` + +In the example above we retrieve the `serve` command from the list of existing commands; then we modify its `fn` part (`fn` is the third parameter passed when you create a new command; it specifies the function to run when running the command). With the modification done the console message will be printed after `serve` command has run successfully. + +### Specifying Mode for Commands + +If a plugin-registered command needs to run in a specific default mode, the plugin needs to expose it via `module.exports.defaultModes` in the form of `{ [commandName]: mode }`: + +``` js +module.exports = api => { + api.registerCommand('build', () => { + // ... + }) +} + +module.exports.defaultModes = { + build: 'production' +} +``` + +This is because the command's expected mode needs to be known before loading environment variables, which in turn needs to happen before loading user options / applying the plugins. + +## Prompts + +Prompts are required to handle user choices when creating a new project or adding a new plugin to the existing one. All prompts logic is stored inside the `prompts.js` file. The prompts are presented using [inquirer](https://github.com/SBoudrias/Inquirer.js) under the hood. + +When user initialize the plugin by calling `vue invoke`, if the plugin contains a `prompts.js` in its root directory, it will be used during invocation. The file should export an array of [Questions](https://github.com/SBoudrias/Inquirer.js#question) that will be handled by Inquirer.js. + +You should export directly array of questions, or export function that return those. + +e.g. directly array of questions: +```js +// prompts.js + +module.exports = [ + { + type: 'input', + name: 'locale', + message: 'The locale of project localization.', + validate: input => !!input, + default: 'en' + }, + // ... +] +``` + +e.g. function that return array of questions: +```js +// prompts.js + +// pass `package.json` of project to function argument +module.exports = pkg => { + const prompts = [ + { + type: 'input', + name: 'locale', + message: 'The locale of project localization.', + validate: input => !!input, + default: 'en' + } + ] + + // add dynamically prompt + if ('@vue/cli-plugin-eslint' in (pkg.devDependencies || {})) { + prompts.push({ + type: 'confirm', + name: 'useESLintPluginVueI18n', + message: 'Use ESLint plugin for Vue I18n ?' + }) + } + + return prompts +} +``` + +The resolved answers object will be passed to the plugin's generator as options. + +Alternatively, the user can skip the prompts and directly initialize the plugin by passing options via the command line, e.g.: + +``` bash +vue invoke my-plugin --mode awesome +``` + +Prompt can have [different types](https://github.com/SBoudrias/Inquirer.js#prompt-types) but the most widely used in CLI are `checkbox` and `confirm`. Let's add a `confirm` prompt and then use it in plugin generator to create a condition for [template rendering](#creating-new-templates). + +```js +// prompts.js + +module.exports = [ + { + name: `addExampleRoutes`, + type: 'confirm', + message: 'Add example routes?', + default: false + } +] +``` + +On plugin invoke user will be prompted with the question about example routes and the default answer will be `No`. + +![Prompts example](/prompts-example.png) + +If you want to use the result of the user's choice in generator, it will be accessible with the prompt name. We can add a modification to `generator/index.js`: + +```js +if (options.addExampleRoutes) { + api.render('./template', { + ...options + }) +} +``` + +Now template will be rendered only if user agreed to create example routes. + + +## Installing plugin locally + +While working on your plugin, you need to test it and check how it works locally on a project using Vue CLI. You can use an existing project or create a new one just for testing purposes: + +```bash +vue create test-app +``` + +To add the plugin, run the following command in the root folder of the project: + +```bash +npm install --save-dev file:/full/path/to/your/plugin +vue invoke +``` + +You need to repeat these steps every time you make changes to your plugin. + +Another way to add a plugin is to leverage the power of Vue UI. You can run it with: + +```bash +vue ui +``` + +You will have a UI open in browser window on `localhost:8000`. Go to the `Vue Project Manager` tab: + +![Vue Project Manager](/ui-project-manager.png) + +And look for your test project name there: + +![UI Plugins List](/ui-select-plugin.png) + +Click on your application name, go to the Plugins tab (it has a puzzle icon) and then click the `Add new plugin` button on the top right. In the new view you will see a list of Vue CLI plugins accessible via npm. There is also a `Browse local plugin` button on the bottom of the page: + +![Browse local plugins](/ui-browse-local-plugin.png) + +After you click it, you can easily search for you plugin and add it to the project. After this you will be able to see it in plugins list and apply all changes done to the plugin via simply clicking on `Refresh` icon: + +![Refresh plugin](/ui-plugin-refresh.png) + +## UI Integration + +Vue CLI has a great UI tool which allows user to scaffold and manage a project with a nice graphical interface. The Vue CLI plugin can be integrated to this interface. UI provides an additional functionality to CLI plugins: + +- you can run npm tasks, including plugin-specific ones, directly from the UI; +- you can display custom configurations for your plugin. For example, [vue-cli-plugin-apollo](https://github.com/Akryum/vue-cli-plugin-apollo) provides the following configuration screen for Apollo server: + +![UI Configuration Screen](/ui-configuration.png) +- when creating the project, you can display [prompts](#prompts) visually +- you can add localizations for your plugin if you want to support multiple languages +- you can make your plugin discoverable in the Vue UI search + +All the logic connected to Vue UI should be placed to `ui.js` file in the root folder or in the `ui/index.js`. The file should export a function which gets the api object as argument: + +```js +module.exports = api => { + // Use the API here... +} +``` + +### Augment the task in the UI + +Vue CLI plugin allows you not only add new npm tasks to the project [via Generator](#extending-package) but also create a view for them in Vue UI. It's useful when you want to run the the task right from the UI and see its output there. + +Let's add a `greet` task created with [Generator](#extending-package) to the UI. 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. Let's provide some additional information about our task: + +```js +module.exports = api => { + api.describeTask({ + match: /greet/, + description: 'Prints a greeting in the console', + link: 'https://cli.vuejs.org/dev-guide/plugin-dev.html#core-concepts' + }) +} +``` + +Now if you explore your project in the Vue UI, you will find your task added to the `Tasks` section. You can see a name of the task, provided description, a link icon that leads to the provided URL and also an output screen to show the task output: + +![UI Greet task](/ui-greet-task.png) + +### Display a configuration screen + +Sometimes your project can have custom configuration files for different features or libraries. With Vue CLI plugin you can display this config in Vue UI, change it and save (saving will change the corresponding config file in your project). By default, Vue CLI project has a main configuration screen representing `vue.config.js` settings. If you included ESLint to your project, you will see also a ESLint configuration screen: + +![UI Configuration Screen](/ui-configuration-default.png) + +Let's build a custom configuration for our plugin. First of all, after you add your plugin to the existing project, there should be a file containing this custom config. This means you need to add this file to `template` folder on the [templating step](#creating-new-templates). + +By default, a configuration UI might read and write to the following file types: `json`, `yaml`, `js`, `package`. Let's name our new file `myConfig.js` and place in it the root of `template` folder: + +``` +. +└── generator + ├── index.js + └── template + ├── myConfig.js + └── src + ├── layouts + ├── pages + └── router.js +``` + +Now you need to add some actual config to this file: + +```js +// myConfig.js + +module.exports = { + color: 'black' +} +``` + +After your plugin is invoked, the `myConfig.js` file will be rendered in the project root directory. Now let's add a new configuration screen with the `api.describeConfig` method in the `ui.js` file: + +First you need to pass some information: + +```js +// ui.js + +api.describeConfig({ + // Unique ID for the config + id: 'org.ktsn.vue-auto-routing.config', + // Displayed name + name: 'Greeting configuration', + // Shown below the name + description: 'This config defines the color of the greeting printed', + // "More info" link + link: 'https://github.com/ktsn/vue-cli-plugin-auto-routing#readme' +}) +``` + +:::danger Warning +Make sure to namespace the id correctly, since it must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation) +::: + +#### Config logo + +You can also select an icon for your config. It can be either a [Material icon](https://material.io/tools/icons/?style=baseline) code or a custom image (see [Public static files](ui-api.md#public-static-files)). + +```js +// ui.js + +api.describeConfig({ + /* ... */ + // Config icon + icon: 'color_lens' +}) +``` + +If you don't specify an icon, the plugin logo will be displayed if any (see [Logo](#logo)). + +#### Config files + +Now you need to provide your configuration file to UI: this way you could read its content and save changes to it. You need to choose a name for your config file, select its format and provide a path to the file: + +```js +api.describeConfig({ + // other config properties + files: { + myConfig: { + js: ['myConfig.js'] + } + } +}) +``` + +There can be more than one file provided. Say, if we have `myConfig.json`, we can provide it with `json: ['myConfig.json']` property. The order is important: the first filename in the list will be used to create the config file if it doesn't exist. + +#### Display config prompts + +We want to display an input field for color property on the configuration screen. To do so, we need a `onRead` hook that will return a list of prompts to be displayed: + +```js +api.describeConfig({ + // other config properties + onRead: ({ data }) => ({ + prompts: [ + { + name: `color`, + type: 'input', + message: 'Define the color for greeting message', + value: 'white' + } + ] + }) +}) +``` + +In the example above we specified the input prompt with the value of 'white'. This is how our configuration screen will look with all the settings provided above: + +![UI Config Start](/ui-config-start.png) + +Now let's replace hardcoded `white` value with the property from the config file. In the `onRead` hook `data` object contains the JSON result of each config file content. In our case, the content of `myConfig.js` was + +```js +// myConfig.js + +module.exports = { + color: 'black' +} +``` + +So, the `data` object will be + +```js +{ + // File + myConfig: { + // File data + color: 'black' + } +} +``` + +It's easy to see that we need `data.myConfig.color` property. Let's change `onRead` hook: + +```js +// ui.js + +onRead: ({ data }) => ({ + prompts: [ + { + name: `color`, + type: 'input', + message: 'Define the color for greeting message', + value: data.myConfig && data.myConfig.color + } + ] +}), +``` + +::: tip +Note that `myConfig` may be undefined if the config file doesn't exist when the screen is loaded. +::: + +You can see that on the configuration screen `white` is replaced with `black`. + +We can also provide a default value if the config file is not present: + +```js +// ui.js + +onRead: ({ data }) => ({ + prompts: [ + { + name: `color`, + type: 'input', + message: 'Define the color for greeting message', + value: data.myConfig && data.myConfig.color, + default: 'black', + } + ] +}), +``` + +#### Save config changes + +We just read the content of `myConfig.js` and used it on the configuration screen. Now let's try to save any changes done in the color input field to the file. We can do it with the `onWrite` hook: + +```js +// ui.js + +api.describeConfig({ + /* ... */ + onWrite: ({ prompts, api }) => { + // ... + } +}) +``` + +`onWrite` hook can take a lot of [arguments](ui-api.html#save-config-changes) but we will need only two of them: `prompts` and `api`. First one is current prompts runtime objects - we will get a prompt id from it and retrieve an answer with this id. To retrieve the answer we'll use `async getAnswer()` method from the `api`: + +```js +// ui.js + +async onWrite({ api, prompts }) { + const result = {} + for (const prompt of prompts) { + result[`${prompt.id}`] = await api.getAnswer(prompt.id) + } + api.setData('myConfig', result) +} +``` + +Now if you try to change the value in the color input field from `black` to `red` on the config screen and press `Save the changes`, you will observe that `myConfig.js` file in your project has been changed as well: + +```js +// myConfig.js + +module.exports = { + color: 'red' +} +``` + +### Display prompts + +If you want, you can display [prompts](#prompts) in the Vue UI as well. When installing your plugin through the UI, prompts will be shown on the plugin invocation step. + +You can extend the [inquirer object](#prompts-for-3rd-party-plugins) with additional properties. They are optional and only used by the UI: + +```js +// prompts.js + +module.exports = [ + { + // basic prompt properties + name: `addExampleRoutes`, + type: 'confirm', + message: 'Add example routes?', + default: false, + // UI-related prompt properties + group: 'Strongly recommended', + description: 'Adds example pages, layouts and correct router config', + link: + 'https://github.com/ktsn/vue-cli-plugin-auto-routing/#vue-cli-plugin-auto-routing' + } +] +``` + +As a result, you will have this screen on plugin invocation: + +![UI Prompts](/ui-prompts.png) + +### Logo + +You can put a `logo.png` file in the root directory of the folder that will be published on npm. It will be displayed in several places: + - When searching for a plugin to install + - In the installed plugin list + - In the configurations list (by default) + - In the tasks list for augmented tasks (by default) + +![Plugins](/plugins.png) + +The logo should be a square non-transparent image (ideally 84x84). + +## Publish Plugin to npm + +To publish your plugin, you need to be registered an [npmjs.com](npmjs.com) and you should have `npm` installed globally. If it's your first npm module, please run + +```bash +npm login +``` + +Enter your username and password. This will store the credentials so you don’t have to enter it for every publish. + +:::tip +Before publishing a plugin, make sure you choose a right name for it! Name convention is `vue-cli-plugin-`. Check [Discoverability](#discoverability) section for more information +::: + +To publish a plugin, go to the plugin root folder and run this command in the terminal: + +```bash +npm publish +``` + +After successful publish, you should be able to add your plugin to the project created with Vue CLI with `vue add ` command. diff --git a/docs/ja/dev-guide/ui-api.md b/docs/ja/dev-guide/ui-api.md new file mode 100644 index 0000000000..a742100d9e --- /dev/null +++ b/docs/ja/dev-guide/ui-api.md @@ -0,0 +1,1416 @@ +# 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. + +![UI Plugin architecture](/vue-cli-ui-schema.png) + +## UI files + +Inside each installed vue-cli plugins, the cli-ui will try to load an optional `ui.js` file in the root folder of the plugin. Note that you can also use folders (for example `ui/index.js`). + +The file should export a function which gets the api object as argument: + +```js +module.exports = api => { + // Use the API here... +} +``` + +**⚠️ The files will be reloaded when fetching the plugin list in the 'Project plugins' view. To apply changes, click on the 'Project plugins' button in the navigation sidebar on the left in the UI.** + +Here is an example folder structure for a vue-cli plugin using the UI API: + +``` +- vue-cli-plugin-test + - package.json + - index.js + - generator.js + - prompts.js + - ui.js + - logo.png +``` + +### Project local plugins + +If you need access to the plugin API in your project and don't want to create a full plugin for it, you can use the `vuePlugins.ui` option in your `package.json` file: + +```json +{ + "vuePlugins": { + "ui": ["my-ui.js"] + } +} +``` + +Each file will need to export a function taking the plugin API as the first argument. + +## Dev mode + +While building your plugin, you may want to run the cli-ui in Dev mode, so it will output useful logs to you: + +``` +vue ui --dev +``` + +Or: + +``` +vue ui -D +``` + +## Project configurations + +![Configuration ui](/config-ui.png) + +You can add a project configuration with the `api.describeConfig` method. + +First you need to pass some information: + +```js +api.describeConfig({ + // Unique ID for the config + id: 'org.vue.eslintrc', + // Displayed name + name: 'ESLint configuration', + // Shown below the name + description: 'Error checking & Code quality', + // "More info" link + link: 'https://eslint.org' +}) +``` + +::: danger +Make sure to namespace the id correctly, since it must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +::: + +### Config icon + +It can be either a [Material icon](https://material.io/tools/icons) code or a custom image (see [Public static files](#public-static-files)): + +```js +api.describeConfig({ + /* ... */ + // Config icon + icon: 'application_settings' +}) +``` + +If you don't specify an icon, the plugin logo will be displayed if any (see [Logo](./ui-info.md#logo)). + +### Config files + +By default, a configuration UI might read and write to one or more configuration files, for example both `.eslintrc.js` and `vue.config.js`. + +You can provide what are the possible files to be detected in the user project: + +```js +api.describeConfig({ + /* ... */ + // All possible files for this config + files: { + // eslintrc.js + eslint: { + js: ['.eslintrc.js'], + json: ['.eslintrc', '.eslintrc.json'], + // Will read from `package.json` + package: 'eslintConfig' + }, + // vue.config.js + vue: { + js: ['vue.config.js'] + } + }, +}) +``` + +Supported types: `json`, `yaml`, `js`, `package`. The order is important: the first filename in the list will be used to create the config file if it doesn't exist. + +### Display config prompts + +Use the `onRead` hook to return a list of prompts to be displayed for the configuration: + +```js +api.describeConfig({ + /* ... */ + onRead: ({ data, cwd }) => ({ + prompts: [ + // Prompt objects + ] + }) +}) +``` + +Those prompts will be displayed in the configuration details pane. + +See [Prompts](#prompts) for more info. + +The `data` object contains the JSON result of each config file content. + +For example, let's say the user has the following `vue.config.js` in his project: + +```js +module.exports = { + lintOnSave: false +} +``` + +We declare the config file in our plugin like this: + +```js +api.describeConfig({ + /* ... */ + // All possible files for this config + files: { + // vue.config.js + vue: { + js: ['vue.config.js'] + } + }, +}) +``` + +Then the `data` object will be: + +```js +{ + // File + vue: { + // File data + lintOnSave: false + } +} +``` + +Multiple files example: if we add the following `eslintrc.js` file in the user project: + +```js +module.exports = { + root: true, + extends: [ + 'plugin:vue/essential', + '@vue/standard' + ] +} +``` + +And change the `files` option in our plugin to this: + +```js +api.describeConfig({ + /* ... */ + // All possible files for this config + files: { + // eslintrc.js + eslint: { + js: ['.eslintrc.js'], + json: ['.eslintrc', '.eslintrc.json'], + // Will read from `package.json` + package: 'eslintConfig' + }, + // vue.config.js + vue: { + js: ['vue.config.js'] + } + }, +}) +``` + +Then the `data` object will be: + +```js +{ + eslint: { + root: true, + extends: [ + 'plugin:vue/essential', + '@vue/standard' + ] + }, + vue: { + lintOnSave: false + } +} +``` + +### Configuration tabs + +You can organize the prompts into several tabs: + +```js +api.describeConfig({ + /* ... */ + onRead: ({ data, cwd }) => ({ + tabs: [ + { + id: 'tab1', + label: 'My tab', + // Optional + icon: 'application_settings', + prompts: [ + // Prompt objects + ] + }, + { + id: 'tab2', + label: 'My other tab', + prompts: [ + // Prompt objects + ] + } + ] + }) +}) +``` + +### Save config changes + +Use the `onWrite` hook to write the data to the configuration file (or execute any nodejs code): + +```js +api.describeConfig({ + /* ... */ + onWrite: ({ prompts, answers, data, files, cwd, api }) => { + // ... + } +}) +``` + +Arguments: + +- `prompts`: current prompts runtime objects (see below) +- `answers`: answers data from the user inputs +- `data`: read-only initial data read from the config files +- `files`: descriptors of the found files (`{ type: 'json', path: '...' }`) +- `cwd`: current working directory +- `api`: `onWrite API` (see below) + +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, + tabId: null, + // Original inquirer prompt object + raw: data +} +``` + +`onWrite` API: + +- `assignData(fileId, newData)`: use `Object.assign` to update the config data before writing. +- `setData(fileId, 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 provided (for example `JSON.parse`). + +Example (from the ESLint plugin): + +```js +api.describeConfig({ + // ... + + onWrite: async ({ api, prompts }) => { + // Update ESLint rules + const result = {} + for (const prompt of prompts) { + result[`rules.${prompt.id}`] = await api.getAnswer(prompt.id, JSON.parse) + } + api.setData('eslint', result) + } +}) +``` + +## Project tasks + +![Tasks ui](/tasks-ui.png) + +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' +}) +``` + +You can also use a function for `match`: + +```js +api.describeTask({ + match: (command) => /vue-cli-service serve/.test(command), +}) +``` + +### Task icon + +It can be either a [Material icon](https://material.io/tools/icons) code or a custom image (see [Public static files](#public-static-files)): + +```js +api.describeTask({ + /* ... */ + // Task icon + icon: 'application_settings' +}) +``` + +If you don't specify an icon, the plugin logo will be displayed if any (see [Logo](./ui-info.md#logo)). + +### Tasks parameters + +You can add prompts to modify the command arguments. They will be displayed in a 'Parameters' modal. + +Example: + +```js +api.describeTask({ + // ... + + // 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' + } + ] +}) +``` + +See [Prompts](#prompts) for more info. + +### Task hooks + +Several hooks are available: + +- `onBeforeRun` +- `onRun` +- `onExit` + +For example, you can use the answers to the prompts (see above) to add new arguments to the command: + +```js +api.describeTask({ + // ... + + // Hooks + // Modify arguments here + onBeforeRun: async ({ answers, args }) => { + // Args + if (answers.open) args.push('--open') + if (answers.mode) args.push('--mode', answers.mode) + args.push('--dashboard') + }, + // Immediately after running the task + onRun: async ({ args, child, cwd }) => { + // child: node child process + // cwd: process working directory + }, + onExit: async ({ args, child, cwd, code, signal }) => { + // code: exit code + // signal: kill signal used if any + } +}) +``` + +### Task views + +You can display custom views in the task details pane using the `ClientAddon` API: + +```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 + 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' +}) +``` + +See [Client addon](#client-addon) for more info. + + +### Add new tasks + +You can also add entirely new tasks which aren't in the `package.json` scripts with `api.addTask` instead of `api.describeTask`. Those tasks will only appear in the cli UI. + +**You need to provide a `command` option instead of `match`.** + +Example: + +```js +api.addTask({ + // Required + name: 'inspect', + command: 'vue-cli-service inspect', + // Optional + // The rest is like `describeTask` without the `match` option + description: '...', + link: 'https://github.com/vuejs/vue-cli/...', + prompts: [ /* ... */ ], + onBeforeRun: () => {}, + onRun: () => {}, + onExit: () => {}, + views: [ /* ... */ ], + defaultView: '...' +}) +``` + +**⚠️ The `command` will run a node context. This means you can call node bin commands like you would normally do in the `package.json` scripts.** + +## Prompts + +The prompt objects must be valid [inquirer](https://github.com/SBoudrias/Inquirer.js) objects. + +However, you can add the following additional fields (which are optional and only used by the UI): + +```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`, `editor`. + +In addition to those, the UI supports special types that only works with it: + +- `color`: displays a color picker. + +### Switch example + +```js +{ + name: 'open', + type: 'confirm', + default: false, + description: 'Open the app in the browser' +} +``` + +### Select example + +```js +{ + name: 'mode', + type: 'list', + default: 'development', + choices: [ + { + name: 'Development mode', + value: 'development' + }, + { + name: 'Production mode', + value: 'production' + }, + { + name: 'Test mode', + value: 'test' + } + ], + description: 'Build mode', + link: 'https://link-to-docs' +} +``` + +### Input example + +```js +{ + name: 'host', + type: 'input', + default: '0.0.0.0', + description: 'Host for the development server' +} +``` + +### Checkbox example + +Displays multiple switches. + +```js +{ + name: 'lintOn', + message: 'Pick additional lint features:', + when: answers => answers.features.includes('linter'), + type: 'checkbox', + choices: [ + { + name: 'Lint on save', + value: 'save', + checked: true + }, + { + name: 'Lint and fix on commit' + (hasGit() ? '' : chalk.red(' (requires Git)')), + value: 'commit' + } + ] +} +``` + +### Color picker example + +```js +{ + name: 'themeColor', + type: 'color', + message: 'Theme color', + description: 'This is used to change the system UI color around the app', + default: '#4DBA87' +} +``` + +### Prompts for invocation + +In your vue-cli plugin, you may already have a `prompts.js` file which asks the user a few questions when installing the plugin (with the CLI or the UI). You can add the additional UI-only fields (see above) to those prompt objects as well so they will provide more information if the user is using the UI. + +**⚠️ Currently, the inquirer types which aren't supported (see above) will not work properly in the UI.** + +## 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. You can either do this in a subfolder of your plugin or in a different npm package. + +Install `@vue/cli-ui` as a dev dependency. + +Then add a `vue.config.js` file with the following content: + +```js +const { clientAddonConfig } = require('@vue/cli-ui') + +module.exports = { + ...clientAddonConfig({ + id: 'org.vue.webpack.client-addon', + // Development port (default 8042) + port: 8042 + }) +} +``` + +The `clientAddonConfig` method will generate the needed vue-cli configuration. Among other things, it disables CSS extraction and outputs the code to `./dist/index.js` in the client addon folder. + +::: danger +Make sure to namespace the id correctly, since it must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +::: + +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('org.vue.webpack.components.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('org.vue.webpack', [ + { path: '', name: 'org.vue.webpack.routes.test', component: TestView } +]) + +// You can translate your plugin components +// Load the locale files (uses vue-i18n) +const locales = require.context('./locales', true, /[a-z0-9]+\.json$/i) +locales.keys().forEach(key => { + const locale = key.match(/([a-z0-9]+)\./i)[1] + ClientAddonApi.addLocalization(locale, locales(key)) +}) +``` + +::: danger +Make sure to namespace the ids correctly, since they must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +::: + +The cli-ui registers `Vue` and `ClientAddonApi` as global variables in the `window` scope. + +In your components, you can use all the components and the CSS classes of [@vue/ui](https://github.com/vuejs/ui) and [@vue/cli-ui](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-ui/src/components) in order to keep the look and feel consistent. You can also translate the strings with [vue-i18n](https://github.com/kazupon/vue-i18n) which is included. + +### Register the client addon + +Back to the `ui.js` file, use the `api.addClientAddon` method with a require query to the built folder: + +```js +api.addClientAddon({ + id: 'org.vue.webpack.client-addon', + // Folder containing the built JS files + path: '@vue/cli-ui-addon-webpack/dist' +}) +``` + +This will use the nodejs `require.resolve` API to find the folder and serve the `index.js` file built from the client addon. + +Or specify an url when developing 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: 'org.vue.webpack.client-addon', + // 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: 'org.vue.webpack.views.dashboard', + // Button label + label: 'Dashboard', + // Button icon (material-icons) + icon: 'dashboard', + // Dynamic component to load, registered using ClientAddonApi + component: 'org.vue.webpack.components.dashboard' + } + ], + // Default selected view when displaying the task details (by default it's the output) + defaultView: 'org.vue.webpack.views.dashboard' +}) +``` + +Here is the client addon code that register the `'org.vue.webpack.components.dashboard'` component (like we saw earlier): + +```js +/* In `main.js` */ +// Import the component +import WebpackDashboard from './components/WebpackDashboard.vue' +// Register a custom component +// (works like 'Vue.component') +ClientAddonApi.component('org.vue.webpack.components.dashboard', WebpackDashboard) +``` + +![Task view example](/task-view.png) + +## 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: 'org.vue.webpack.views.test', + + // Route name (from vue-router) + // Use the same name used in the 'ClientAddonApi.addRoutes' method (see above in the Client addon section) + name: 'org.vue.webpack.routes.test', + + // 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' +}) +``` + +Here is the code in the client addon that register the `'org.vue.webpack.routes.test'` (like we saw earlier): + +```js +/* In `main.js` */ +// Import the component +import TestView from './components/TestView.vue' +// 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('org.vue.webpack', [ + { path: '', name: 'org.vue.webpack.routes.test', component: TestView } +]) +``` + +![Custom view example](/custom-view.png) + +## Shared data + +Use Shared data to communicate info with custom components in an easy way. + +> For example, the Webpack dashboard shares the build stats between the UI client and the UI server using this API. + +In the plugin `ui.js` (nodejs): + +```js +// Set or update +api.setSharedData('com.my-name.my-variable', 'some-data') + +// Get +const sharedData = api.getSharedData('com.my-name.my-variable') +if (sharedData) { + console.log(sharedData.value) +} + +// Remove +api.removeSharedData('com.my-name.my-variable') + +// Watch for changes +const watcher = (value, id) => { + console.log(value, id) +} +api.watchSharedData('com.my-name.my-variable', watcher) +// Unwatch +api.unwatchSharedData('com.my-name.my-variable', watcher) + +// Namespaced versions +const { + setSharedData, + getSharedData, + removeSharedData, + watchSharedData, + unwatchSharedData +} = api.namespace('com.my-name.') +``` + +::: danger +Make sure to namespace the ids correctly, since they must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +::: + +In the custom component: + +```js +// Vue component +export default { + // Sync Shared data + sharedData () { + return { + // You can use `myVariable` in template + myVariable: 'com.my-name.my-variable' + // You can also map namespaced Shared data + ...mapSharedData('com.my-name.', { + myVariable2: 'my-variable2' + }) + } + }, + + // Manual methods + async created () { + const value = await this.$getSharedData('com.my-name.my-variable') + + this.$watchSharedData(`com.my-name.my-variable`, value => { + console.log(value) + }) + + await this.$setSharedData('com.my-name.my-variable', 'new-value') + } +} +``` + +If you use the `sharedData` option, the shared data can be updated by assigning a new value to the corresponding property. + +```html + + + +``` + +This is very useful if you create a settings component for example. + +## Plugin actions + +Plugin actions are calls sent between the cli-ui (browser) and plugins (nodejs). + +> For example, you might have a button in a custom component (see [Client addon](#client-addon)) which calls some nodejs code on the server using this API. + +In the `ui.js` file in the plugin (nodejs), you can use two methods from `PluginApi`: + +```js +// Call an action +api.callAction('com.my-name.other-action', { foo: 'bar' }).then(results => { + console.log(results) +}).catch(errors => { + console.error(errors) +}) +``` + +```js +// Listen for an action +api.onAction('com.my-name.test-action', params => { + console.log('test-action called', params) +}) +``` + +::: danger +Make sure to namespace the ids correctly, since they must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +::: + +You can use namespaced versions with `api.namespace` (similar to Shared data): + +```js +const { onAction, callAction } = api.namespace('com.my-name.') +``` + +In the client addon components (browser), you have access to `$onPluginActionCalled`, `$onPluginActionResolved` and `$callPluginAction`: + +```js +// Vue component +export default { + created () { + this.$onPluginActionCalled(action => { + // When the action is called + // before being run + console.log('called', action) + }) + this.$onPluginActionResolved(action => { + // After the action is run and completed + console.log('resolved', action) + }) + }, + + methods: { + testPluginAction () { + // Call a plugin action + this.$callPluginAction('com.my-name.test-action', { + meow: 'meow' + }) + } + } +} +``` + +## Inter-process communication (IPC) + +IPC stands for Inter-Process Communication. This system allows you to easily send messages from child processes (for example, tasks!). And it's pretty fast and lightweight. + +> To display the data in the webpack dashboard UI, the `serve` and `build` commands from `@vue/cli-service` send IPC messages to the cli-ui nodejs server when the `--dashboard` argument is passed in. + +In you process code (which can be a Webpack plugin or a nodejs task script), you can use the `IpcMessenger` class from `@vue/cli-shared-utils`: + +```js +const { IpcMessenger } = require('@vue/cli-shared-utils') + +// Create a new IpcMessenger instance +const ipc = new IpcMessenger() + +function sendMessage (data) { + // Send a message to the cli-ui server + ipc.send({ + 'com.my-name.some-data': { + type: 'build', + value: data + } + }) +} + +function messageHandler (data) { + console.log(data) +} + +// Listen for message +ipc.on(messageHandler) + +// Don't listen anymore +ipc.off(messageHandler) + +function cleanup () { + // Disconnect from the IPC network + ipc.disconnect() +} +``` + +Manual connection: + +```js +const ipc = new IpcMessenger({ + autoConnect: false +}) + +// This message will be queued +ipc.send({ ... }) + +ipc.connect() +``` + +Auto disconnect on idle (after some time without sending any message): + +```js +const ipc = new IpcMessenger({ + disconnectOnIdle: true, + idleTimeout: 3000 // Default +}) + +ipc.send({ ... }) + +setTimeout(() => { + console.log(ipc.connected) // false +}, 3000) +``` + +Connect to another IPC network: + +```js +const ipc = new IpcMessenger({ + networkId: 'com.my-name.my-ipc-network' +}) +``` + +In a vue-cli plugin `ui.js` file, you can use the `ipcOn`, `ipcOff` and `ipcSend` methods: + +```js +function onWebpackMessage ({ data: message }) { + if (message['com.my-name.some-data']) { + console.log(message['com.my-name.some-data']) + } +} + +// Listen for any IPC message +api.ipcOn(onWebpackMessage) + +// Don't listen anymore +api.ipcOff(onWebpackMessage) + +// Send a message to all connected IpcMessenger instances +api.ipcSend({ + webpackDashboardMessage: { + foo: 'bar' + } +}) +``` + +## Local storage + +A plugin can save and load data from the local [lowdb](https://github.com/typicode/lowdb) database used by the ui server. + +```js +// Store a value into the local DB +api.storageSet('com.my-name.an-id', { some: 'value' }) + +// Retrieve a value from the local DB +console.log(api.storageGet('com.my-name.an-id')) + +// Full lowdb instance +api.db.get('posts') + .find({ title: 'low!' }) + .assign({ title: 'hi!'}) + .write() + +// Namespaced helpers +const { storageGet, storageSet } = api.namespace('my-plugin.') +``` + +::: danger +Make sure to namespace the ids correctly, since they must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +::: + +## Notification + +You can display notifications using the user OS notification system: + +```js +api.notify({ + title: 'Some title', + message: 'Some message', + icon: 'path-to-icon.png' +}) +``` + +There are some builtin icons: + +- `'done'` +- `'error'` + +## Progress screen + +You can display a progress screen with some text and a progress bar: + +```js +api.setProgress({ + status: 'Upgrading...', + error: null, + info: 'Step 2 of 4', + progress: 0.4 // from 0 to 1, -1 means hidden progress bar +}) +``` + +Remove the progress screen: + +```js +api.removeProgress() +``` + +## Hooks + +Hooks allows to react to certain cli-ui events. + +### onProjectOpen + +Called when the plugin is loaded for the first time for the current project. + +```js +api.onProjectOpen((project, previousProject) => { + // Reset data +}) +``` + +### onPluginReload + +Called when the plugin is reloaded. + +```js +api.onPluginReload((project) => { + console.log('plugin reloaded') +}) +``` + +### onConfigRead + +Called when a configuration screen is open or refreshed. + +```js +api.onConfigRead(({ config, data, onReadData, tabs, cwd }) => { + console.log(config.id) +}) +``` + +### onConfigWrite + +Called when the user saves in a configuration screen. + +```js +api.onConfigWrite(({ config, data, changedFields, cwd }) => { + // ... +}) +``` + +### onTaskOpen + +Called when the user open a task details pane. + +```js +api.onTaskOpen(({ task, cwd }) => { + console.log(task.id) +}) +``` + +### onTaskRun + +Called when the user run a task. + +```js +api.onTaskRun(({ task, args, child, cwd }) => { + // ... +}) +``` + +### onTaskExit + +Called when a task exists. It can be called both called on success or failure. + +```js +api.onTaskExit(({ task, args, child, signal, code, cwd }) => { + // ... +}) +``` + +### onViewOpen + +Called when the users open a view (like 'Plugins', 'Configurations' or 'Tasks'). + +```js +api.onViewOpen(({ view, cwd }) => { + console.log(view.id) +}) +``` + +## Suggestions + +Suggestions are buttons meant to propose an action to the user. They are displayed in the top bar. For example, we can have a button that suggest installing vue-router if the package isn't detected in the app. + +```js +api.addSuggestion({ + id: 'com.my-name.my-suggestion', + type: 'action', // Required (more types in the future) + label: 'Add vue-router', + // This will be displayed in a details modal + message: 'A longer message for the modal', + link: 'http://link-to-docs-in-the-modal', + // Optional image + image: '/_plugin/my-package/screenshot.png', + // Function called when suggestion is activated by user + async handler () { + // ... + return { + // By default removes the button + keep: false + } + } +}) +``` + +::: danger +Make sure to namespace the id correctly, since it must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +::: + +![UI Suggestion](/suggestion.png) + +Then you can remove the suggestion: + +```js +api.removeSuggestion('com.my-name.my-suggestion') +``` + +You can also open a page instead when the user activates the suggestion with `actionLink`: + +```js +api.addSuggestion({ + id: 'com.my-name.my-suggestion', + type: 'action', // Required + label: 'Add vue-router', + // Open a new tab + actionLink: 'https://vuejs.org/' +}) +``` + +Typically, you will use hooks to display the suggestion in the right context: + +```js +const ROUTER = 'vue-router-add' + +api.onViewOpen(({ view }) => { + if (view.id === 'vue-project-plugins') { + if (!api.hasPlugin('router')) { + api.addSuggestion({ + id: ROUTER, + type: 'action', + label: 'org.vue.cli-service.suggestions.vue-router-add.label', + message: 'org.vue.cli-service.suggestions.vue-router-add.message', + link: 'https://router.vuejs.org/', + async handler () { + await install(api, 'router') + } + }) + } + } else { + api.removeSuggestion(ROUTER) + } +}) +``` + +In this example we only display the vue-router suggestion in the plugins view and if the project doesn't have vue-router installed already. + +Note: `addSuggestion` and `removeSuggestion` can be namespaced with `api.namespace()`. + +## Widgets + +You can register a widget for the project dashboard in your plugin ui file: + +```js +registerWidget({ + // Unique ID + id: 'org.vue.widgets.news', + // Basic infos + title: 'org.vue.widgets.news.title', + description: 'org.vue.widgets.news.description', + icon: 'rss_feed', + // Main component used to render the widget + component: 'org.vue.widgets.components.news', + // (Optional) Secondary component for widget 'fullscreen' view + detailsComponent: 'org.vue.widgets.components.news', + // Size + minWidth: 2, + minHeight: 1, + maxWidth: 6, + maxHeight: 6, + defaultWidth: 2, + defaultHeight: 3, + // (Optional) Limit the maximum number of this widget on the dashboard + maxCount: 1, + // (Optional) Add a 'fullscreen' button in widget header + openDetailsButton: true, + // (Optional) Default configuration for the widget + defaultConfig: () => ({ + url: 'https://vuenews.fireside.fm/rss' + }), + // (Optional) Require user to configure widget when added + // You shouldn't use `defaultConfig` with this + needsUserConfig: true, + // (Optional) Display prompts to configure the widget + onConfigOpen: async ({ context }) => { + return { + prompts: [ + { + name: 'url', + type: 'input', + message: 'org.vue.widgets.news.prompts.url', + validate: input => !!input // Required + } + ] + } + } +}) +``` + +Note: `registerWidget` can be namespaced with `api.namespace()`. + +## Other methods + +### hasPlugin + +Returns `true` if the project uses the plugin. + +```js +api.hasPlugin('eslint') +api.hasPlugin('apollo') +api.hasPlugin('vue-cli-plugin-apollo') +``` + +### getCwd + +Retrieve the current working directory. + +```js +api.getCwd() +``` + +### resolve + +Resolves a file within the current project. + +```js +api.resolve('src/main.js') +``` + +### getProject + +Get currently open project. + +```js +api.getProject() +``` + +### requestRoute + +Switch the user on a specific route in the web client. + +```js +api.requestRoute({ + name: 'foo', + params: { + id: 'bar' + } +}) + +api.requestRoute('/foobar') +``` + +## Public static files + +You may need to expose some static files over the cli-ui builtin HTTP server (typically if you want to specify an icon to a custom view). + +Any file in an optional `ui-public` folder in the root of the plugin package folder will be exposed to the `/_plugin/:id/*` HTTP route. + +For example, if you put a `my-logo.png` file into the `vue-cli-plugin-hello/ui-public/` folder, it will be available with the `/_plugin/vue-cli-plugin-hello/my-logo.png` URL when the cli-ui loads the plugin. + +```js +api.describeConfig({ + /* ... */ + // Custom image + icon: '/_plugin/vue-cli-plugin-hello/my-logo.png' +}) +``` diff --git a/docs/ja/dev-guide/ui-info.md b/docs/ja/dev-guide/ui-info.md new file mode 100644 index 0000000000..f1c2d888b5 --- /dev/null +++ b/docs/ja/dev-guide/ui-info.md @@ -0,0 +1,41 @@ +# UI Plugin Info + +When used in the UI, your plugin can show additional information to make it more discoverable and recognizable. + +## Logo + +You can put a `logo.png` file in the root directory of the folder that will be published on npm. It will be displayed in several places: + - When searching for a plugin to install + - In the installed plugin list + +![Plugins](/plugins.png) + +The logo should be a square non-transparent image (ideally 84x84). + +## Discoverability + +For better discoverability when a user searches for your plugin, put keywords describing your plugin in the `description` field of the plugin `package.json` file. + +Example: + +```json +{ + "name": "vue-cli-plugin-apollo", + "version": "0.7.7", + "description": "vue-cli plugin to add Apollo and GraphQL" +} +``` + +You should add the url to the plugin website or repository in the `homepage` or `repository` field so that a 'More info' button will be displayed in your plugin description: + +```json +{ + "repository": { + "type": "git", + "url": "git+https://github.com/Akryum/vue-cli-plugin-apollo.git" + }, + "homepage": "https://github.com/Akryum/vue-cli-plugin-apollo#readme" +} +``` + +![Plugin search item](/plugin-search-item.png) diff --git a/docs/ja/dev-guide/ui-localization.md b/docs/ja/dev-guide/ui-localization.md new file mode 100644 index 0000000000..8ea036ce8e --- /dev/null +++ b/docs/ja/dev-guide/ui-localization.md @@ -0,0 +1,51 @@ +# UI Localization + +## Translate the standard UI + +To make collaboration and synchronisation easier, the English source locale from the `dev` branch is automatically imported to [Transifex](https://www.transifex.com/vuejs/vue-cli/dashboard/), a platform for collaborative translation. + +For existing languages, you can [sign up as a translator](https://www.transifex.com/vuejs/vue-cli/dashboard/). +For new languages, you can [request the new language](https://www.transifex.com/vuejs/vue-cli/dashboard/) after signing up. + +In either case you will be able to translate keys as they are added or changed in the source locale. + +## Translate your plugin + +You can put locale files compatible with [vue-i18n](https://github.com/kazupon/vue-i18n) in a `locales` folder at the root of your plugin. They will be automatically loaded into the client when the project is opened. You can then use `$t` to translate strings in your components and other vue-i18n helpers. Also, the strings used in the UI API (like `describeTask`) will go through vue-i18n as well to you can localize them. + +Example `locales` folder: + +``` +vue-cli-plugin/locales/en.json +vue-cli-plugin/locales/fr.json +``` + +Example usage in API: + +```js +api.describeConfig({ + // vue-i18n path + description: 'com.my-name.my-plugin.config.foo' +}) +``` + +::: danger +Make sure to namespace the id correctly, since it must be unique across all plugins. It's recommended to use the [reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +::: + +Example usage in components: + +```html +{{ $t('com.my-name.my-plugin.actions.bar') }} +``` + +You can also load the locale files in a client addon if you prefer, using the `ClientAddonApi`: + +```js +// Load the locale files (uses vue-i18n) +const locales = require.context('./locales', true, /[a-z0-9]+\.json$/i) +locales.keys().forEach(key => { + const locale = key.match(/([a-z0-9]+)\./i)[1] + ClientAddonApi.addLocalization(locale, locales(key)) +}) +``` diff --git a/docs/ja/guide/README.md b/docs/ja/guide/README.md new file mode 100644 index 0000000000..68accb50bf --- /dev/null +++ b/docs/ja/guide/README.md @@ -0,0 +1,53 @@ +--- +sidebarDepth: 0 +--- + +# Overview + +::: warning +This documentation is for `@vue/cli`. For the old `vue-cli`, see [here](https://github.com/vuejs/vue-cli/tree/v2#vue-cli--). +::: + +Vue CLI is a full system for rapid Vue.js development, providing: + +- Interactive project scaffolding via `@vue/cli`. +- Zero config rapid prototyping via `@vue/cli` + `@vue/cli-service-global`. +- A runtime dependency (`@vue/cli-service`) that is: + - Upgradeable; + - Built on top of webpack, with sensible defaults; + - Configurable via in-project config file; + - Extensible via plugins +- A rich collection of official plugins integrating the best tools in the frontend ecosystem. +- A full graphical user interface to create and manage Vue.js projects. + +Vue CLI aims to be the standard tooling baseline for the Vue ecosystem. It ensures the various build tools work smoothly together with sensible defaults so you can focus on writing your app instead of spending days wrangling with configurations. At the same time, it still offers the flexibility to tweak the config of each tool without the need for ejecting. + +## Components of the System + +There are several moving parts of Vue CLI - if you look at the [source code](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue), you will find that it is a monorepo containing a number of separately published packages. + +### CLI + +The CLI (`@vue/cli`) is a globally installed npm package and provides the `vue` command in your terminal. It provides the ability to quickly scaffold a new project via `vue create`, or instantly prototype new ideas via `vue serve`. You can also manage your projects using a graphical user interface via `vue ui`. We will walk through what it can do in the next few sections of the guide. + +### CLI Service + +The CLI Service (`@vue/cli-service`) is a development dependency. It's an npm package installed locally into every project created by `@vue/cli`. + +The CLI Service is built on top of [webpack](http://webpack.js.org/) and [webpack-dev-server](https://github.com/webpack/webpack-dev-server). It contains: + +- The core service that loads other CLI Plugins; +- An internal webpack config that is optimized for most apps; +- The `vue-cli-service` binary inside the project, which comes with the basic `serve`, `build` and `inspect` commands. + +If you are familiar with [create-react-app](https://github.com/facebookincubator/create-react-app), `@vue/cli-service` is roughly the equivalent of `react-scripts`, although the feature set is different. + +The section on [CLI Service](./cli-service.md) covers its detailed usage. + +### CLI Plugins + +CLI Plugins are npm packages that provide optional features to your Vue CLI projects, such as Babel/TypeScript transpilation, ESLint integration, unit testing, and end-to-end testing. It's easy to spot a Vue CLI plugin as their names start with either `@vue/cli-plugin-` (for built-in plugins) or `vue-cli-plugin-` (for community plugins). + +When you run the `vue-cli-service` binary inside your project, it automatically resolves and loads all CLI Plugins listed in your project's `package.json`. + +Plugins can be included as part of your project creation process or added into the project later. They can also be grouped into reusable presets. We will discuss these in more depth in the [Plugins and Presets](./plugins-and-presets.md) section. diff --git a/docs/ja/guide/browser-compatibility.md b/docs/ja/guide/browser-compatibility.md new file mode 100644 index 0000000000..8942f8a5cd --- /dev/null +++ b/docs/ja/guide/browser-compatibility.md @@ -0,0 +1,101 @@ +# Browser Compatibility + +## browserslist + +You will notice a `browserslist` field in `package.json` (or a separate `.browserslistrc` file) specifying a range of browsers the project is targeting. This value will be used by [@babel/preset-env][babel-preset-env] and [autoprefixer][autoprefixer] to automatically determine the JavaScript features that need to be transpiled and the CSS vendor prefixes needed. + +See [here][browserslist] for how to specify browser ranges. + +## Polyfills + +A default Vue CLI project uses [@vue/babel-preset-app][babel-preset-app], which uses `@babel/preset-env` and the `browserslist` config to determine the Polyfills needed for your project. + +### useBuiltIns: 'usage' + +By default, it passes [`useBuiltIns: 'usage'`](https://new.babeljs.io/docs/en/next/babel-preset-env.html#usebuiltins-usage) to `@babel/preset-env` which automatically detects the polyfills needed based on the language features used in your source code. This ensures only the minimum amount of polyfills are included in your final bundle. However, this also means **if one of your dependencies has specific requirements on polyfills, by default Babel won't be able to detect it.** + +If one of your dependencies need polyfills, you have a few options: + +1. **If the dependency is written in an ES version that your target environments do not support:** Add that dependency to the [`transpileDependencies`](../config/#transpiledependencies) option in `vue.config.js`. This would enable both syntax transforms and usage-based polyfill detection for that dependency. + +2. **If the dependency ships ES5 code and explicitly lists the polyfills needed:** you can pre-include the needed polyfills using the [polyfills](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/babel-preset-app#polyfills) option for `@vue/babel-preset-app`. **Note that `es6.promise` is included by default because it's very common for libs to depend on Promises.** + + ``` js + // babel.config.js + module.exports = { + presets: [ + ['@vue/app', { + polyfills: [ + 'es6.promise', + 'es6.symbol' + ] + }] + ] + } + ``` + + ::: tip + It's recommended to add polyfills this way instead of directly importing them in your source code, because polyfills listed here can be automatically excluded if your `browserslist` targets don't need them. + ::: + +3. **If the dependency ships ES5 code, but uses ES6+ features without explicitly listing polyfill requirements (e.g. Vuetify):** Use `useBuiltIns: 'entry'` and then add `import '@babel/polyfill'` to your entry file. This will import **ALL** polyfills based on your `browserslist` targets so that you don't need to worry about dependency polyfills anymore, but will likely increase your final bundle size with some unused polyfills. + +See [@babel-preset/env docs](https://new.babeljs.io/docs/en/next/babel-preset-env.html#usebuiltins-usage) for more details. + +### Polyfills when Building as Library or Web Components + +When using Vue CLI to [build a library or Web Components](./build-targets.md), it is recommended to pass `useBuiltIns: false` to `@vue/babel-preset-app` to disable automatic polyfill injection. This ensures you don't include unnecessary polyfills in your code, as it should be the responsibility of the consuming app to include polyfills. + +## Modern Mode + +With Babel we are able to leverage all the newest language features in ES2015+, but that also means we have to ship transpiled and polyfilled bundles in order to support older browsers. These transpiled bundles are often more verbose than the original native ES2015+ code, and also parse and run slower. Given that today a good majority of the modern browsers have decent support for native ES2015, it is a waste that we have to ship heavier and less efficient code to those browsers just because we have to support older ones. + +Vue CLI offers a "Modern Mode" to help you solve this problem. When building for production with the following command: + +``` bash +vue-cli-service build --modern +``` + +Vue CLI will produce two versions of your app: one modern bundle targeting modern browsers that support [ES modules](https://jakearchibald.com/2017/es-modules-in-browsers/), and one legacy bundle targeting older browsers that do not. + +The cool part though is that there are no special deployment requirements. The generated HTML file automatically employs the techniques discussed in [Phillip Walton's excellent post](https://philipwalton.com/articles/deploying-es2015-code-in-production-today/): + +- The modern bundle is loaded with ` + + + + +``` + +### Bundle that Registers Multiple Web Components + +When building a web component bundle, you can also target multiple components by using a glob as entry: + +``` +vue-cli-service build --target wc --name foo 'src/components/*.vue' +``` + +When building multiple web components, `--name` will be used as the prefix and the custom element name will be inferred from the component filename. For example, with `--name foo` and a component named `HelloWorld.vue`, the resulting custom element will be registered as ``. + +### Async Web Component + +When targeting multiple web components, the bundle may become quite large, and the user may only use a few of the components your bundle registers. The async web component mode produces a code-split bundle with a small entry file that provides the shared runtime between all the components, and registers all the custom elements upfront. The actual implementation of a component is then fetched on-demand only when an instance of the corresponding custom element is used on the page: + +``` +vue-cli-service build --target wc-async --name foo 'src/components/*.vue' +``` + +``` +File Size Gzipped + +dist/foo.0.min.js 12.80 kb 8.09 kb +dist/foo.min.js 7.45 kb 3.17 kb +dist/foo.1.min.js 2.91 kb 1.02 kb +dist/foo.js 22.51 kb 6.67 kb +dist/foo.0.js 17.27 kb 8.83 kb +dist/foo.1.js 5.24 kb 1.64 kb +``` + +Now on the page, the user only needs to include Vue and the entry file: + +``` html + + + + + +``` + + +## Using vuex in builds + +When building a [Webcomponent](#web-component) or [Library](#library), the entry point is not `main.js`, but an `entry-wc.js` file, generated here: [https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-service/lib/commands/build/resolveWcEntry.js](https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-service/lib/commands/build/resolveWcEntry.js) + +So to use vuex in web component target, you need to initialize the store in `App.vue`: + +``` js +import store from './store' + +// ... + +export default { + store, + name: 'App', + // ... +} +``` diff --git a/docs/ja/guide/cli-service.md b/docs/ja/guide/cli-service.md new file mode 100644 index 0000000000..1a4ba4560b --- /dev/null +++ b/docs/ja/guide/cli-service.md @@ -0,0 +1,182 @@ +# CLI Service + +## Using the Binary + +Inside a Vue CLI project, `@vue/cli-service` installs a binary named `vue-cli-service`. You can access the binary directly as `vue-cli-service` in npm scripts, or as `./node_modules/.bin/vue-cli-service` from the terminal. + +This is what you will see in the `package.json` of a project using the default preset: + +``` json +{ + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build" + } +} +``` + +You can invoke these scripts using either npm or Yarn: + +``` bash +npm run serve +# OR +yarn serve +``` + +If you have [npx](https://github.com/npm/npx) available (should be bundled with an up-to-date version of npm), you can also invoke the binary directly with: + +``` bash +npx vue-cli-service serve +``` + +::: tip +You can run scripts with additional features using the GUI with the `vue ui` command. +::: + +Here is the Webpack Analyzer from the GUI in action: + +![UI Webpack Analyzer](/ui-analyzer.png) + +## vue-cli-service serve + +``` +Usage: vue-cli-service serve [options] [entry] + +Options: + + --open open browser on server start + --copy copy url to clipboard on server start + --mode specify env mode (default: development) + --host specify host (default: 0.0.0.0) + --port specify port (default: 8080) + --https use https (default: false) + --public specify the public network URL for the HMR client + --skip-plugins comma-separated list of plugin names to skip for this run +``` + +::: tip --copy +Copying to clipboard might not work on a few platforms. +If copying was successful, `(copied to clipboard)` is displayed next to the local dev server URL. +::: + +The `vue-cli-service serve` command starts a dev server (based on [webpack-dev-server](https://github.com/webpack/webpack-dev-server)) that comes with Hot-Module-Replacement (HMR) working out of the box. + +In addition to the command line flags, you can also configure the dev server using the [devServer](../config/#devserver) field in `vue.config.js`. + +`[entry]` in the CLI command is defined as *the entry file*, not *an additional entry file*. If you overwrite the entry in the CLI, then the entries from `config.pages` are no longer considered, which may cause an error. + +## vue-cli-service build + +``` +Usage: vue-cli-service build [options] [entry|pattern] + +Options: + + --mode specify env mode (default: production) + --dest specify output directory (default: dist) + --modern build app targeting modern browsers with auto fallback + --no-unsafe-inline build app without introducing inline scripts + --target app | lib | wc | wc-async (default: app) + --formats list of output formats for library builds (default: commonjs,umd,umd-min) + --inline-vue include the Vue module in the final bundle of library or web component target + --name name for lib or web-component mode (default: "name" in package.json or entry filename) + --filename file name for output, only usable for 'lib' target (default: value of --name), + --no-clean do not remove the dist directory before building the project + --report generate report.html to help analyze bundle content + --report-json generate report.json to help analyze bundle content + --skip-plugins comma-separated list of plugin names to skip for this run + --watch watch for changes +``` + +`vue-cli-service build` produces a production-ready bundle in the `dist/` directory, with minification for JS/CSS/HTML and auto vendor chunk splitting for better caching. The chunk manifest is inlined into the HTML. + +There are a few useful flags: + +- `--modern` builds your app using [Modern Mode](./browser-compatibility.md#modern-mode), shipping native ES2015 code to modern browsers that support it, with auto fallback to a legacy bundle. + +- `--target` allows you to build any component(s) inside your project as a library or as web components. See [Build Targets](./build-targets.md) for more details. + +- `--report` and `--report-json` will generate reports based on your build stats that can help you analyze the size of the modules included in your bundle. + +## vue-cli-service inspect + +``` +Usage: vue-cli-service inspect [options] [...paths] + +Options: + + --mode specify env mode (default: development) +``` + +You can use `vue-cli-service inspect` to inspect the webpack config inside a Vue CLI project. See [Inspecting Webpack Config](./webpack.md#inspecting-the-project-s-webpack-config) for more details. + +## Checking All Available Commands + +Some CLI plugins will inject additional commands to `vue-cli-service`. For example, `@vue/cli-plugin-eslint` injects the `vue-cli-service lint` command. You can see all injected commands by running: + +``` bash +npx vue-cli-service help +``` + +You can also learn about the available options of each command with: + +``` bash +npx vue-cli-service help [command] +``` + +## Skipping Plugins + +Sometimes, you may want to not use a certain CLI Plugin when running a command. For example you might want to build a version of your app that doesn't include the PWA plugin. You can do that by passing the name of the plugin to the `--skip-plugins` option. + +```bash +npx vue-cli-service build --skip-plugins pwa +``` + +::: tip +This option is available for _every_ `vue-cli-service` command, including custom ones added by other plugins. +::: + +You can skip multiple plugins by passing their names as a comma-separated list: + +```bash +npx vue-cli-service build --skip-plugins pwa,apollo +``` + +Plugin names are resolved the same way they are during install, as described [here](./plugins-and-presets.md#installing-plugins-in-an-existing-project) + +``` bash +# these are all equivalent +npx vue-cli-service build --skip-plugins pwa + +npx vue-cli-service build --skip-plugins @vue/pwa + +npx vue-cli-service build --skip-plugins @vue/cli-plugin-pwa +``` + +## Caching and Parallelization + +- `cache-loader` is enabled for Vue/Babel/TypeScript compilations by default. Files are cached inside `node_modules/.cache` - if running into compilation issues, always try deleting the cache directory first. + +- `thread-loader` will be enabled for Babel/TypeScript transpilation when the machine has more than 1 CPU cores. + +## Git Hooks + +When installed, `@vue/cli-service` also installs [yorkie](https://github.com/yyx990803/yorkie), which allows you to easily specify Git hooks using the `gitHooks` field in your `package.json`: + +``` json +{ + "gitHooks": { + "pre-commit": "lint-staged" + } +} +``` + +::: warning +`yorkie` is a fork of [`husky`](https://github.com/typicode/husky) and is not compatible with the latter. +::: + +## Configuration without Ejecting + +Projects created via `vue create` are ready to go without the need for additional configuration. The plugins are designed to work with one another so in most cases, all you need to do is pick the features you want during the interactive prompts. + +However, we also understand that it's impossible to cater to every possible need, and the needs of a project may also change over time. Projects created by Vue CLI allow you to configure almost every aspect of the tooling without ever needing to eject. Check out the [Config Reference](../config/) for more details. diff --git a/docs/ja/guide/creating-a-project.md b/docs/ja/guide/creating-a-project.md new file mode 100644 index 0000000000..6183a92cd3 --- /dev/null +++ b/docs/ja/guide/creating-a-project.md @@ -0,0 +1,82 @@ +# Creating a Project + +## vue create + +To create a new project, run: + +``` bash +vue create hello-world +``` + +::: warning +If you are on Windows using Git Bash with minTTY, the interactive prompts will not work. You must launch the command as `winpty vue.cmd create hello-world`. +If you however want to still use the `vue create hello-world` syntax, you can alias the command by adding the following line to your `~/.bashrc` file. +`alias vue='winpty vue.cmd'` +You will need to restart your Git Bash terminal session to pull in the updated bashrc file. +::: + +You will be prompted to pick a preset. You can either choose the default preset which comes with a basic Babel + ESLint setup, or select "Manually select features" to pick the features you need. + +![CLI preview](/cli-new-project.png) + +The default setup is great for quickly prototyping a new project, while the manual setup provides more options that are likely needed for more production-oriented projects. + +![CLI preview](/cli-select-features.png) + +If you chose to manually select features, at the end of the prompts you also have the option to save your selections as a preset so that you can reuse it in the future. We will discuss presets and plugins in the next section. + +::: tip ~/.vuerc +Saved presets will be stored in a JSON file named `.vuerc` in your user home directory. If you wish to modify saved presets / options, you can do so by editing this file. + +During the project creation process, you may also be prompted to select a preferred package manager, or use the [Taobao npm registry mirror](https://npm.taobao.org/) for faster dependency installation. Your choices will also be saved in `~/.vuerc`. +::: + +The `vue create` command has a number of options and you can explore them all by running: + +``` bash +vue create --help +``` + +``` +Usage: create [options] + +create a new project powered by vue-cli-service + + +Options: + + -p, --preset Skip prompts and use saved or remote preset + -d, --default Skip prompts and use default preset + -i, --inlinePreset Skip prompts and use inline JSON string as preset + -m, --packageManager Use specified npm client when installing dependencies + -r, --registry Use specified npm registry when installing dependencies + -g, --git [message|false] Force / skip git initialization, optionally specify initial commit message + -n, --no-git Skip git initialization + -f, --force Overwrite target directory if it exists + -c, --clone Use git clone when fetching remote preset + -x, --proxy Use specified proxy when creating project + -b, --bare Scaffold project without beginner instructions + -h, --help Output usage information +``` + +## Using the GUI + +You can also create and manage projects using a graphical interface with the `vue ui` command: + +``` bash +vue ui +``` + +The above command will open a browser window with a GUI that guides you through the project creation process. + +![UI preview](/ui-new-project.png) + +## Pulling 2.x Templates (Legacy) + +Vue CLI >= 3 uses the same `vue` binary, so it overwrites Vue CLI 2 (`vue-cli`). If you still need the legacy `vue init` functionality, you can install a global bridge: + +``` bash +npm install -g @vue/cli-init +# vue init now works exactly the same as vue-cli@2.x +vue init webpack my-project +``` diff --git a/docs/ja/guide/css.md b/docs/ja/guide/css.md new file mode 100644 index 0000000000..aac1986dbf --- /dev/null +++ b/docs/ja/guide/css.md @@ -0,0 +1,171 @@ +# Working with CSS + +Vue CLI projects comes with support for [PostCSS](http://postcss.org/), [CSS Modules](https://github.com/css-modules/css-modules) and pre-processors including [Sass](https://sass-lang.com/), [Less](http://lesscss.org/) and [Stylus](http://stylus-lang.com/). + +## Referencing Assets + +All compiled CSS are processed by [css-loader](https://github.com/webpack-contrib/css-loader), which parses `url()` and resolves them as module requests. This means you can refer to assets using relative paths based on the local file structure. Note if you want to reference a file inside an npm dependency or via webpack alias, the path must be prefixed with `~` to avoid ambiguity. See [Static Asset Handling](./html-and-static-assets.md#static-assets-handling) for more details. + +## Pre-Processors + +You can select pre-processors (Sass/Less/Stylus) when creating the project. If you did not do so, the internal webpack config is still pre-configured to handle all of them. You just need to manually install the corresponding webpack loaders: + +``` bash +# Sass +npm install -D sass-loader sass + +# Less +npm install -D less-loader less + +# Stylus +npm install -D stylus-loader stylus +``` + +Then you can import the corresponding file types, or use them in `*.vue` files with: + +``` vue + +``` + +::: tip A Tip on Sass Performance +Note that when using Dart Sass, **synchronous compilation is twice as fast as asynchronous compilation** by default, due to the overhead of asynchronous callbacks. To avoid this overhead, you can use the [fibers](https://www.npmjs.com/package/fibers) package to call asynchronous importers from the synchronous code path. To enable this, simply install `fibers` as a project dependency: +``` +npm install -D fibers +``` +Please also be aware, as it's a native module, there may be compatibility issues vary on the OS and build environment. In that case, please run `npm uninstall -D fibers` to fix the problem. +::: + +### Automatic imports + +If you want to automatically import files (for colors, variables, mixins...), you can use the [style-resources-loader](https://github.com/yenshih/style-resources-loader). Here is an example for stylus that imports `./src/styles/imports.styl` in every SFC and every stylus files: + +```js +// vue.config.js +const path = require('path') + +module.exports = { + chainWebpack: config => { + const types = ['vue-modules', 'vue', 'normal-modules', 'normal'] + types.forEach(type => addStyleResource(config.module.rule('stylus').oneOf(type))) + }, +} + +function addStyleResource (rule) { + rule.use('style-resource') + .loader('style-resources-loader') + .options({ + patterns: [ + path.resolve(__dirname, './src/styles/imports.styl'), + ], + }) +} +``` + +You can also use the [vue-cli-plugin-style-resources-loader](https://www.npmjs.com/package/vue-cli-plugin-style-resources-loader). + +## PostCSS + +Vue CLI uses PostCSS internally. + +You can configure PostCSS via `.postcssrc` or any config source supported by [postcss-load-config](https://github.com/michael-ciniawsky/postcss-load-config), and configure [postcss-loader](https://github.com/postcss/postcss-loader) via `css.loaderOptions.postcss` in `vue.config.js`. + +The [autoprefixer](https://github.com/postcss/autoprefixer) plugin is enabled by default. To configure the browser targets, use the [browserslist](../guide/browser-compatibility.html#browserslist) field in `package.json`. + +::: tip Note on Vendor-prefixed CSS Rules +In the production build, Vue CLI optimizes your CSS and will drop unnecessary vendor-prefixed CSS rules based on your browser targets. With `autoprefixer` enabled by default, you should always use only non-prefixed CSS rules. +::: + +## CSS Modules + +You can [use CSS Modules in `*.vue` files](https://vue-loader.vuejs.org/en/features/css-modules.html) out of the box with `