mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-01-23 23:59:02 -06:00
* docs: (ru) config/README.md update devServer example * docs: (ru) creating-a-project.md update * docs: css.md add less examples * docs: browser-compatibility.md update * docs: deployment.md update * docs: (ru) config/readme.md update * docs: (ru) deployment.md update * docs: (ru) prototyping.md add yarn command * docs: config.md fix * docs: ui-localization.md typo * docs: [RU] Translation update * docs: [RU] Translation update * docs: vuex.md added * docs: router.md added * docs: migration from v3 added * docs: config.js updated * docs: config/readme.md updated * docs: unit-mocha.md updated * docs: css.md updated * docs: cli-service.md updated * docs: generator-api.md updated * docs: build-target.md update * docs: deployment.md update * docs: e2e-nightwatch.md update * docs: unit-jest.md update * docs: e2e-nightwatch.md update * docs: migrating-from-v3.md update * docs: plugin-dev.md update * docs: plugin-dev.md update * docs: plugin-dev.md update * docs: plugin-dev.md update
881 lines
47 KiB
Markdown
881 lines
47 KiB
Markdown
---
|
||
sidebarDepth: 3
|
||
---
|
||
|
||
# Руководство по разработке плагинов
|
||
|
||
## Введение
|
||
|
||
Плагин CLI — это npm-пакет, который может добавлять дополнительные возможности в проект с помощью Vue CLI. Эти функции могут включать в себя:
|
||
|
||
- изменение конфигурации webpack проекта — например, можно добавить новое правило для поддержки файлов определённых расширений, если плагин должен работать с ними. Например, `@vue/cli-plugin-typescript` добавляет такое правило для работы с файлами `.ts` и `.tsx`;
|
||
- добавление новых команд vue-cli-service — например, `@vue/cli-plugin-unit-jest` добавляет новую команду `test:unit`, которая позволяет разработчику запускать модульные тесты;
|
||
- расширение файла `package.json` — полезная опция, когда плагину для работы требуются новые зависимости и необходимо добавить их в раздел зависимостей проекта;
|
||
- создание новых и/или изменение существующих файлов в проекте. Иногда полезно создать файл с примером компонента или изменить основной файл для добавления новых импортов;
|
||
- предоставление пользователю возможности выбора требуемых опций — например, можно уточнить необходимость создания примера компонента, упомянутого выше.
|
||
|
||
:::tip Совет
|
||
Не злоупотребляйте плагинами vue-cli! При необходимости просто добавить какую-то новую зависимость в проект, например [Lodash](https://lodash.com/) — лучше сделать это вручную, через npm, чем создавать специальный плагин для этого.
|
||
:::
|
||
|
||
Плагин CLI всегда должен содержать [плагин для сервиса](#пnагин-дnя-сервиса) в качестве своего основного экспорта, и может опционально содержать [генератор](#генератор), [файл интерактивных подсказок](#интерактивные-подсказки) и [интеграцию с Vue UI](#интеграция-с-ui).
|
||
|
||
Как npm-пакет, плагин CLI должен иметь файл `package.json`. Также рекомендуется, чтобы у плагина было описание в файле `README.md`, чтобы помочь другим найти ваш плагин в npm.
|
||
|
||
Типичная структура плагина CLI выглядит следующим образом:
|
||
|
||
```bash
|
||
.
|
||
├── README.md
|
||
├── generator.js # генератор (опционально)
|
||
├── index.js # плагин для сервиса
|
||
├── package.json
|
||
├── prompts.js # файл интерактивных подсказок (опционально)
|
||
└── ui.js # интеграция с Vue UI (опционально)
|
||
```
|
||
|
||
## Именование и обнаруживаемость в поиске
|
||
|
||
Чтобы плагин CLI мог использоваться в проекте Vue CLI, он должен соответствовать определённому соглашению по именованию `vue-cli-plugin-<name>` или `@scope/vue-cli-plugin-<name>`. Такой подход позволяет вашему плагину быть:
|
||
|
||
- Обнаруживаемым `@vue/cli-service`;
|
||
- Обнаруживаемым другими разработчиками при поиске;
|
||
- Устанавливаемым с помощью команд `vue add <name>` или `vue invoke <name>`.
|
||
|
||
:::warning Предупреждение
|
||
Убедитесь в правильности указанного имени плагина, иначе его невозможно будет установить через команду `vue add` или найти с помощью поиска плагинов в Vue UI!
|
||
:::
|
||
|
||
Для лучшей обнаруживаемости при поиске плагина пользователем, укажите ключевые слова, описывающие плагин, в поле `description` в его файле `package.json`.
|
||
|
||
Например:
|
||
|
||
```json
|
||
{
|
||
"name": "vue-cli-plugin-apollo",
|
||
"version": "0.7.7",
|
||
"description": "vue-cli plugin to add Apollo and GraphQL"
|
||
}
|
||
```
|
||
|
||
Для отображения кнопки «More info» возле описания плагина нужно указать URL-адрес веб-сайта плагина или его репозитория в полях `homepage` или `repository`:
|
||
|
||
```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"
|
||
}
|
||
```
|
||
|
||

|
||
|
||
## Генератор
|
||
|
||
Генератор — это часть плагина CLI, которая обычно используется если требуется расширить пакет новыми зависимостями, создать новые файлы в проекте или изменить существующие.
|
||
|
||
В структуре плагина CLI генератор должен располагаться в файле `generator.js` или `generator/index.js`. Он будет вызываться в двух случаях:
|
||
|
||
- При первоначальном создании проекта, если подключаемый плагин CLI необходим в рамках выбранного пресета настроек создания проекта.
|
||
|
||
- При установке плагина в созданном проекте командой `vue add` или `vue invoke`.
|
||
|
||
Генератор должен экспортировать функцию, которая принимает три аргумента:
|
||
|
||
1. Экземпляр [GeneratorAPI](generator-api.md);
|
||
|
||
2. Настройки генератора для плагина. Эти настройки разрешаются с помощью [интерактивных подсказок](#интерактивные-подсказки) во время фазы создания проекта или загружаются из сохранённого пресета в `~/.vuerc`. Например, если сохранённый файл `~/.vuerc` выглядит так:
|
||
|
||
```json
|
||
{
|
||
"presets" : {
|
||
"foo": {
|
||
"plugins": {
|
||
"@vue/cli-plugin-foo": { "option": "bar" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
То когда пользователь создаёт проект, используя пресет `foo`, генератор `@vue/cli-plugin-foo` получит `{ option: 'bar' }` вторым аргументом.
|
||
|
||
Для сторонних плагинов настройки разрешаются из интерактивных подсказок или аргументов командной строки, когда пользователь вызывает `vue invoke` (см. [интерактивные подсказки](#интерактивные-подсказки)).
|
||
|
||
3. Всё содержимое пресета (`presets.foo`) передаётся третьим аргументом.
|
||
|
||
### Создание новых шаблонов
|
||
|
||
Генератор при вызове команды `api.render('./template')` будет создавать файлы из шаблонов в каталоге `./template` (путь разрешается относительно файла генератора) с помощью [EJS](https://github.com/mde/ejs).
|
||
|
||
Представим, что разрабатываем плагин [vue-cli-auto-routing](https://github.com/ktsn/vue-cli-plugin-auto-routing) и хотим внести следующие изменения в проект при вызове генератора:
|
||
|
||
- создать каталог `layouts` с файлом шаблона страниц по умолчанию;
|
||
- создать каталог `pages` со страницами `about` и `home`;
|
||
- добавить файл `router.js` в каталоге `src`
|
||
|
||
Для создания такой структуры нужно сначала повторить её внутри каталога `generator/template`:
|
||
|
||

|
||
|
||
После создания необходимо добавить вызов `api.render` в файле `generator/index.js`:
|
||
|
||
```js
|
||
module.exports = api => {
|
||
api.render('./template')
|
||
}
|
||
```
|
||
|
||
### Изменение существующих шаблонов
|
||
|
||
Кроме того, можно унаследовать или заменить части существующего шаблона файла (даже из другого пакета) с помощью YAML front-matter:
|
||
|
||
```ejs
|
||
---
|
||
extend: '@vue/cli-service/generator/template/src/App.vue'
|
||
replace: !!js/regexp /<script>[^]*?<\/script>/
|
||
---
|
||
|
||
<script>
|
||
export default {
|
||
// Скрипт по умолчанию который заменится другим
|
||
}
|
||
</script>
|
||
```
|
||
|
||
Также есть возможность заменять сразу несколько мест в файле одновременно, для этого потребуется обернуть заменяющие строки в блоки `<%# REPLACE %>` и `<%# END_REPLACE %>`:
|
||
|
||
```ejs
|
||
---
|
||
extend: '@vue/cli-service/generator/template/src/App.vue'
|
||
replace:
|
||
- !!js/regexp /Добро пожаловать в приложение Vue\.js/
|
||
- !!js/regexp /<script>[^]*?<\/script>/
|
||
---
|
||
|
||
<%# REPLACE %>
|
||
Сообщение с приветствием которое заменим
|
||
<%# END_REPLACE %>
|
||
|
||
<%# REPLACE %>
|
||
<script>
|
||
export default {
|
||
// Скрипт по умолчанию который заменится другим
|
||
}
|
||
</script>
|
||
<%# END_REPLACE %>
|
||
```
|
||
|
||
### Ограничения по именованию файлов
|
||
|
||
При необходимости создания шаблона файла, имя которого начинается с точки (например, `.env`), нужно следовать определённому соглашению об именовании, поскольку при публикации плагина в npm такие файлы игнорируются:
|
||
|
||
```bash
|
||
# Шаблон файла должен использовать символ подчёркивания вместо точки:
|
||
|
||
/generator/template/_env
|
||
|
||
# При вызове api.render('./template') в каталоге проекта он будет сгенерирован как:
|
||
|
||
/generator/template/.env
|
||
```
|
||
|
||
Следовательно, также потребуется придерживаться определённого соглашения об именовании, если потребуется сгенерировать файл, имя которого начинается с подчёркивания:
|
||
|
||
```bash
|
||
# Шаблоны таких файлов должны использовать 2 символа подчёркивания вместо одного:
|
||
|
||
/generator/template/__variables.scss
|
||
|
||
# При вызове api.render('./template') в каталоге проекта он будет сгенерирован как:
|
||
|
||
/generator/template/_variables.scss
|
||
```
|
||
|
||
|
||
### Расширение пакета
|
||
|
||
Если нужно добавить новую зависимость в проект, создать npm-задачу или изменить `package.json` любым другим способом, можно использовать метод API `extendPackage`.
|
||
|
||
```js
|
||
// generator/index.js
|
||
|
||
module.exports = api => {
|
||
api.extendPackage({
|
||
dependencies: {
|
||
'vue-router-layout': '^0.1.2'
|
||
}
|
||
})
|
||
}
|
||
```
|
||
|
||
В примере выше добавляется одна зависимость: `vue-router-layout`. При вызове плагина этот npm-пакет будет установлен и зависимость добавлена в пользовательский файл `package.json`.
|
||
|
||
Этим же методом API можно добавлять npm-задачи в проект. Для этого нужно указать имя задачи и команду, которая будет выполняться, для добавления в секцию `scripts` файла `package.json`:
|
||
|
||
```js
|
||
// generator/index.js
|
||
|
||
module.exports = api => {
|
||
api.extendPackage({
|
||
scripts: {
|
||
greet: 'vue-cli-service greet'
|
||
}
|
||
})
|
||
}
|
||
```
|
||
|
||
В примере выше добавляется новая задача `greet`, которая будет запускать специальную команду сервиса vue-cli, создание которой подробнее описано в разделе [плагина для сервиса](#добавnение-новой-команды-в-cli-service).
|
||
|
||
### Изменение основного файла
|
||
|
||
С помощью методов генератора можно вносить изменения и в файлы проекта. Наиболее распространённым случаем является изменение основного файла `main.js` или `main.ts`: добавление новых импортов, вызовы новых `Vue.use()` и т.д.
|
||
|
||
Рассмотрим случай, когда файл `router.js` создан с помощью [генерации новых шаблонов](#создание-новых-шабnонов) и теперь требуется импортировать этот маршрутизатор в основной файл. Для этого используем два метода API генератора: `entryFile` вернёт основной файл проекта (`main.js` или `main.ts`), а `injectImports` предоставит возможность добавить новые импорты в этот файл:
|
||
|
||
```js
|
||
// generator/index.js
|
||
|
||
api.injectImports(api.entryFile, `import router from './router'`)
|
||
```
|
||
|
||
Теперь, когда маршрутизатор импортирован, можно внедрить его в экземпляр Vue в основном файле. Используем для этого хук `afterInvoke`, который вызывается после записи файлов на диск.
|
||
|
||
Сначала нужно прочитать содержимое основного файла с помощью модуля Node `fs` (который предоставляет API для взаимодействия с файловой системой) и разделить содержимое на строки:
|
||
|
||
```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)
|
||
})
|
||
}
|
||
```
|
||
|
||
Затем находим строку, содержащую слово `render` (это обычно будет часть экземпляра Vue), и добавляем `router` в качестве следующей строки:
|
||
|
||
```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,`
|
||
})
|
||
}
|
||
```
|
||
|
||
Наконец, сохраняем содержимое обратно в основной файл:
|
||
|
||
```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' })
|
||
})
|
||
}
|
||
```
|
||
|
||
## Плагин для сервиса
|
||
|
||
Плагин для сервиса позволяет вносить изменения в конфигурацию webpack, создавать новые команды vue-cli или изменять существующие (такие как `serve` и `build`).
|
||
|
||
Плагин для сервиса автоматически загружается при создании экземпляра сервиса — т.е. при каждом вызове команды `vue-cli-service` внутри проекта. Он располагается в файле `index.js` в корневом каталоге плагина CLI.
|
||
|
||
Плагин для сервиса должен экспортировать функцию, которая принимает два аргумента:
|
||
|
||
- Экземпляр [PluginAPI](plugin-api.md)
|
||
|
||
- Объект, содержащий локальные настройки проекта, указанные в файле `vue.config.js` или в поле `"vue"` файла `package.json`.
|
||
|
||
Минимально необходимый код файла плагина для сервиса приведён ниже:
|
||
|
||
```js
|
||
module.exports = () => {}
|
||
```
|
||
|
||
### Изменение конфигурации webpack
|
||
|
||
API позволяет плагину для сервиса расширять/изменять внутреннюю конфигурацию webpack для различных окружений. Например, модифицируем конфигурацию webpack с помощью webpack-chain для добавления плагина `vue-auto-routing` с заданными параметрами:
|
||
|
||
```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
|
||
}
|
||
])
|
||
})
|
||
}
|
||
```
|
||
|
||
Также можно использовать метод `configureWebpack` для изменении конфигурации webpack или возврата объекта, который будет объединяться с конфигурацией с помощью webpack-merge.
|
||
|
||
### Добавление новой команды в cli-service
|
||
|
||
С помощью плагина для сервиса можно зарегистрировать новую команду в cli-service в дополнение к стандартным (т.е. `serve` и `build`). Для этого можно использовать метод API `registerCommand`.
|
||
|
||
Пример создания простой новой команды, которая выводит приветствие в консоли разработчика:
|
||
|
||
```js
|
||
api.registerCommand(
|
||
'greet',
|
||
{
|
||
description: 'Выводит приветствие в консоли',
|
||
usage: 'vue-cli-service greet'
|
||
},
|
||
() => {
|
||
console.log(`👋 Привет`)
|
||
}
|
||
)
|
||
```
|
||
|
||
В этом примере мы задаём имя команды (`'greet'`), объект настроек с опциями `description` и `usage`, а также функцию, которая выполняется при запуске команды `vue-cli-service greet`.
|
||
|
||
:::tip Совет
|
||
Можно также добавить новую команду в список npm-задач проекта в файле `package.json` [с помощью генератора](#расширение-пакета).
|
||
:::
|
||
|
||
При запуске новой команды в проекте с установленным плагином появится сообщение в консоли:
|
||
|
||
```bash
|
||
$ vue-cli-service greet
|
||
👋 Привет!
|
||
```
|
||
|
||
Можно указать список доступных опций для новой команды. Добавим опцию `--name` и изменим функцию для вывода этого имени, если оно было указано.
|
||
|
||
```js
|
||
api.registerCommand(
|
||
'greet',
|
||
{
|
||
description: 'Выводит приветствие в консоль',
|
||
usage: 'vue-cli-service greet [options]',
|
||
options: { '--name': 'определяет имя для приветствия' }
|
||
},
|
||
args => {
|
||
if (args.name) {
|
||
console.log(`👋 Привет, ${args.name}!`);
|
||
} else {
|
||
console.log(`👋 Привет!`);
|
||
}
|
||
}
|
||
);
|
||
```
|
||
|
||
Теперь при запуске команды `greet` с указанной опцией `--name`, это имя будет выводиться вместе с сообщением в консоли:
|
||
|
||
```bash
|
||
$ vue-cli-service greet --name 'Джон'
|
||
👋 Привет, Джон!
|
||
```
|
||
|
||
### Изменение существующей команды в cli-service
|
||
|
||
Если необходимо изменить существующую команду cli-service, сначала нужно получить её через `api.service.commands` и затем внести некоторые изменения. К примеру, выведем сообщение в консоли с номером порта, на котором запущено приложение:
|
||
|
||
```js
|
||
const { serve } = api.service.commands
|
||
|
||
const serveFn = serve.fn
|
||
|
||
serve.fn = (...args) => {
|
||
return serveFn(...args).then(res => {
|
||
if (res && res.url) {
|
||
console.log(`Проект запущен по адресу ${res.url}`)
|
||
}
|
||
})
|
||
}
|
||
```
|
||
|
||
В примере выше сначала получаем команду `serve` из списка существующих команд; затем изменяем её `fn`-часть (`fn` — это третий параметр, передаваемый при создании новой команды; он определяет функцию, запускаемую при выполнении команды). После внесения модификаций сообщение в консоли будет выводиться после успешного выполнения команды `serve`.
|
||
|
||
### Определение режима работы команды
|
||
|
||
Если команда, зарегистрированная плагином, должна запускаться в определённом режиме, плагин должен определять его через `module.exports.defaultModes` в виде `{ [commandName]: mode }`:
|
||
|
||
```js
|
||
module.exports = api => {
|
||
api.registerCommand('build', () => {
|
||
// ...
|
||
})
|
||
}
|
||
|
||
module.exports.defaultModes = {
|
||
build: 'production'
|
||
}
|
||
```
|
||
|
||
Это связано с тем, что ожидаемый режим для работы команды должен быть известен до загрузки переменных окружения, что произойдёт перед загрузкой пользовательских настроек / применением плагинов.
|
||
|
||
## Интерактивные подсказки
|
||
|
||
Интерактивные подсказки предназначены для обработки пользовательского выбора при создании нового проекта или добавлении нового плагина в существующий проект. Вся логика интерактивных подсказок расположена в файле `prompts.js`. Сами подсказки реализованы с помощью пакета [inquirer](https://github.com/SBoudrias/Inquirer.js) под капотом.
|
||
|
||
При инициализации плагина пользователем командой `vue invoke`, если плагин содержит `prompts.js` в своем корневом каталоге, он будет использован во время вызова. Файл должен экспортировать массив [вопросов](https://github.com/SBoudrias/Inquirer.js#question), которые затем будут обработаны Inquirer.js.
|
||
|
||
Необходимо экспортировать сам массив вопросов или функцию, которая возвращает его.
|
||
|
||
Например, экспорт непосредственно массива вопросов:
|
||
```js
|
||
// prompts.js
|
||
|
||
module.exports = [
|
||
{
|
||
type: 'input',
|
||
name: 'locale',
|
||
message: 'Используемый язык для локализации проекта.',
|
||
validate: input => !!input,
|
||
default: 'en'
|
||
},
|
||
// ...
|
||
]
|
||
```
|
||
|
||
Или экспорт функции, которая возвращает массив вопросов:
|
||
```js
|
||
// prompts.js
|
||
|
||
// в качестве аргумента функции передаётся `package.json` проекта
|
||
module.exports = pkg => {
|
||
const prompts = [
|
||
{
|
||
type: 'input',
|
||
name: 'locale',
|
||
message: 'Используемый язык для локализации проекта.',
|
||
validate: input => !!input,
|
||
default: 'en'
|
||
}
|
||
]
|
||
|
||
// динамическое добавление интерактивной подсказки
|
||
if ('@vue/cli-plugin-eslint' in (pkg.devDependencies || {})) {
|
||
prompts.push({
|
||
type: 'confirm',
|
||
name: 'useESLintPluginVueI18n',
|
||
message: 'Использовать ESLint-плагин для Vue I18n?'
|
||
})
|
||
}
|
||
|
||
return prompts
|
||
}
|
||
```
|
||
|
||
Итоговый объект с ответами будет передаваться в генератор плагина в качестве настроек.
|
||
|
||
Кроме того, пользователь может пропустить этап в интерактивными подсказками и напрямую инициализировать плагин, передав опции через командную строку, например:
|
||
|
||
```bash
|
||
vue invoke my-plugin --mode awesome
|
||
```
|
||
|
||
Интерактивные подсказки могут быть [различных типов](https://github.com/SBoudrias/Inquirer.js#prompt-types), но наиболее широко в CLI применяются `checkbox` и `confirm`. Добавим интерактивную подсказку `confirm` и используем её в генераторе плагина чтобы создавать по условию [новый файл из шаблона](#создание-новых-шабnонов).
|
||
|
||
```js
|
||
// prompts.js
|
||
|
||
module.exports = [
|
||
{
|
||
name: `addExampleRoutes`,
|
||
type: 'confirm',
|
||
message: 'Добавить примеры маршрутов?',
|
||
default: false
|
||
}
|
||
]
|
||
```
|
||
|
||
При вызове плагина пользователю будет предложено ответить на вопрос о добавлении примеров маршрутов с ответом по умолчанию «Нет».
|
||
|
||

|
||
|
||
Если необходимо использовать результат выбора пользователя в генераторе, ответ будет доступен по имени интерактивной подсказки. Теперь можно модифицировать `generator/index.js` так:
|
||
|
||
```js
|
||
if (options.addExampleRoutes) {
|
||
api.render('./template', {
|
||
...options
|
||
})
|
||
}
|
||
```
|
||
|
||
Шаблон будет генерироваться только если пользователь согласился создать примеры маршрутов.
|
||
|
||
## Локальная установка плагина
|
||
|
||
При разработке плагина может потребоваться протестировать его и проверить локально как он работает на проекте с помощью Vue CLI. Можно использовать существующий проект или создать новый в целях тестирования:
|
||
|
||
```bash
|
||
vue create test-app
|
||
```
|
||
|
||
Для добавления плагина выполняем следующую команду в корневом каталоге проекта:
|
||
|
||
```bash
|
||
npm install --save-dev file:/full/path/to/your/plugin
|
||
vue invoke <your-plugin-name>
|
||
```
|
||
|
||
Вызов этих команд необходимо повторять каждый раз при внесении изменений в плагин.
|
||
|
||
Другой способ добавления плагина — воспользоваться возможностями Vue UI. Выполните команду:
|
||
|
||
```bash
|
||
vue ui
|
||
```
|
||
|
||
Пользовательский интерфейс откроется в браузере по адресу `localhost:8000`. Перейдите на вкладку `Vue Project Manager`:
|
||
|
||

|
||
|
||
И найдите в списке название тестового проекта:
|
||
|
||

|
||
|
||
Нажмите на название приложения, перейдите на вкладку плагинов (значок пазла) и затем нажмите кнопку `Add new plugin` (Добавить новый плагин) в правом верхнем углу. На новой странице будет отображён список плагинов Vue CLI, доступных через npm. В нижней части страницы будет кнопка `Browse local plugin` (Выбор локального плагина):
|
||
|
||

|
||
|
||
В окне выбора находим тестируемый плагин и добавляем в проект. После этого он станет виден в списке плагинов, а применить изменения к плагину можно просто нажав на иконку обновления:
|
||
|
||

|
||
|
||
## Интеграция с UI
|
||
|
||
Vue CLI имеет отличный UI с помощью которого пользователь может разворачивать и управлять проектом в удобном графическом интерфейсе. Плагины Vue CLI могут интегрироваться в этот интерфейс. Также UI предоставляет дополнительные возможности для плагинов CLI:
|
||
|
||
- можно напрямую из UI запускать npm-задачи, в том числе и специфичные для плагинов;
|
||
- можно отображать экран с настройками конфигурации плагина. Например, [vue-cli-plugin-apollo](https://github.com/Akryum/vue-cli-plugin-apollo) предоставляет отдельный экран для конфигурации сервера Apollo:
|
||
|
||

|
||
- можно отображать [интерактивные подсказки](#интерактивные-подсказки) при создании проекта
|
||
- можно добавлять локализации плагина при необходимости поддержки нескольких языков
|
||
- можно сделать плагин обнаруживаемым при поиске в Vue UI
|
||
|
||
Вся логика, связанная с Vue UI, должна располагаться в файле `ui.js` в корневом каталоге или в `ui/index.js`. Файл должен экспортировать функцию, которая принимает аргументом объект api:
|
||
|
||
```js
|
||
module.exports = api => {
|
||
// Используем API здесь...
|
||
}
|
||
```
|
||
|
||
### Отображение задачи в UI
|
||
|
||
Плагин Vue CLI позволяет не только добавлять новые npm-задачи в проект с помощью [генератора](#расширение-пакета), но и создавать новые экраны для использования в Vue UI. Это полезно, если хочется запускать задачу сразу из пользовательского интерфейса и видеть результаты её выполнения.
|
||
|
||
Добавим отображение задачи `greet`, которую создавали с помощью [генератора](#расширение-пакета). Список задач определяется из поля `scripts` файла проекта `package.json`. Можно «дополнить» задачу дополнительной информацией и хуками с помощью метода `api.describeTask`:
|
||
|
||
```js
|
||
module.exports = api => {
|
||
api.describeTask({
|
||
match: /greet/,
|
||
description: 'Выводит приветствие в консоль',
|
||
link: 'https://cli.vuejs.org/ru/dev-guide/plugin-dev.html'
|
||
})
|
||
}
|
||
```
|
||
|
||
Теперь в обзоре проекта Vue UI можно увидеть, что задача появилась на странице `Tasks`. Можно увидеть её название, предоставленное описание, иконку ссылки, которая ведёт на указанный URL, а также экран для отображения результатов выполнения задачи:
|
||
|
||

|
||
|
||
### Отображение экрана конфигурации
|
||
|
||
Иногда в проекте могут быть пользовательские файлы конфигураций для различных функций или библиотек. С помощью плагина Vue CLI можно отображать конфигурацию в Vue UI, изменять её и сохранять (сохранение изменит соответствующий конфигурационный файл в проекте). По умолчанию в проекте Vue CLI имеется только главный экран конфигурации с настройками из `vue.config.js`. Если добавить ESLint в проект, то появится также экран конфигурации ESLint:
|
||
|
||

|
||
|
||
Давайте создадим экран конфигурации для плагина. Прежде всего, после добавления плагина в существующий проект, должен быть файл с пользовательской конфигурацией. Это означает, что требуется добавить этот файл в каталог `template` для шага [создания новых шаблонов](#создание-новых-шабnонов).
|
||
|
||
По умолчанию пользовательский интерфейс конфигурации может читать и записывать файлы следующих форматов: `json`, `yaml`, `js`, `package`. Назовём новый файл `myConfig.js` и поместим его в корне каталога `template`:
|
||
|
||
```
|
||
.
|
||
└── generator
|
||
├── index.js
|
||
└── template
|
||
├── myConfig.js
|
||
└── src
|
||
├── layouts
|
||
├── pages
|
||
└── router.js
|
||
```
|
||
|
||
Теперь необходимо добавить в этот файл какую-то актуальную конфигурацию:
|
||
|
||
```js
|
||
// myConfig.js
|
||
|
||
module.exports = {
|
||
color: 'black'
|
||
}
|
||
```
|
||
|
||
После вызова плагина файл `myConfig.js` будет сгенерирован в корневом каталоге проекта. Теперь добавим новый экран конфигурации с помощью метода `api.describeConfig` в файле `ui.js`:
|
||
|
||
Сначала нужно передать некоторую информацию:
|
||
|
||
```js
|
||
// ui.js
|
||
|
||
api.describeConfig({
|
||
// Уникальный ID для конфигурации
|
||
id: 'org.ktsn.vue-auto-routing.config',
|
||
// Отображаемое имя
|
||
name: 'Настройка приветствия',
|
||
// Описание, отображаемое под именем
|
||
description: 'Можно настроить цвет текста приветствия',
|
||
// Ссылка «More info»
|
||
link: 'https://github.com/ktsn/vue-cli-plugin-auto-routing#readme'
|
||
})
|
||
```
|
||
|
||
:::danger Предупреждение
|
||
Убедитесь в точности пространства имён для id, так как он должен быть уникальным для всех плагинов. Рекомендуем использовать [обратную нотацию записи доменного имени](https://en.wikipedia.org/wiki/Reverse_domain_name_notation)
|
||
:::
|
||
|
||
#### Логотип конфигурации
|
||
|
||
Можно выбрать значок для конфигурации. Это может быть код [значка Material](https://material.io/tools/icons/?style=baseline) или пользовательское изображение (см. [публичные статические файлы](ui-api.md#пубnичные-статические-файnы)).
|
||
|
||
```js
|
||
// ui.js
|
||
|
||
api.describeConfig({
|
||
/* ... */
|
||
// Значок конфигурации
|
||
icon: 'color_lens'
|
||
})
|
||
```
|
||
|
||
Если значок не указан, то будет использоваться логотип плагина, если таковой есть (см. [Логотип](#логотип)).
|
||
|
||
#### Файлы конфигурации
|
||
|
||
Теперь нужно предоставить файл конфигурации для UI: таким образом можно будет читать его содержимое и сохранять изменения обратно. Для этого указываем имя конфигурационного файла, его формат и указываем путь к нему:
|
||
|
||
```js
|
||
api.describeConfig({
|
||
// другие свойства конфигурации
|
||
files: {
|
||
myConfig: {
|
||
js: ['myConfig.js']
|
||
}
|
||
}
|
||
})
|
||
```
|
||
|
||
Можно указать больше одного файла. Например, если есть `myConfig.json`, можно определить его в свойстве `json: ['myConfig.json']`. Порядок здесь важен: первое имя файла в списке будет использоваться при создании файла конфигурации, если его не существует.
|
||
|
||
#### Отображение интерактивных подсказок конфигурации
|
||
|
||
Отобразим поле ввода для отображения свойства с цветом на экране конфигурации. Для этого используем хук `onRead`, который вернёт список интерактивных подсказок для отображения:
|
||
|
||
```js
|
||
api.describeConfig({
|
||
// другие свойства конфигурации
|
||
onRead: ({ data }) => ({
|
||
prompts: [
|
||
{
|
||
name: `color`,
|
||
type: 'input',
|
||
message: 'Цвет сообщения с приветствием',
|
||
value: 'white'
|
||
}
|
||
]
|
||
})
|
||
})
|
||
```
|
||
|
||
Этот пример добавляет интерактивную подсказку в виде поля с указанным значением `white`. Вот как будет выглядеть экран конфигурации со всеми приведёнными выше настройками:
|
||
|
||

|
||
|
||
Заменим теперь статическое значение `white` на свойство из конфигурационного файла. В хуке `onRead` объект `data` содержит JSON с результатом каждого файла конфигурации. В нашем случае содержание `myConfig.js` такое:
|
||
|
||
```js
|
||
// myConfig.js
|
||
|
||
module.exports = {
|
||
color: 'black'
|
||
}
|
||
```
|
||
|
||
Поэтому объект `data` будет таким:
|
||
|
||
```js
|
||
{
|
||
// Файл
|
||
myConfig: {
|
||
// Данные файла
|
||
color: 'black'
|
||
}
|
||
}
|
||
```
|
||
|
||
Легко увидеть, что необходимое нам свойство `data.myConfig.color`. Обновим хук `onRead`:
|
||
|
||
```js
|
||
// ui.js
|
||
|
||
onRead: ({ data }) => ({
|
||
prompts: [
|
||
{
|
||
name: `color`,
|
||
type: 'input',
|
||
message: 'Цвет сообщения с приветствием',
|
||
value: data.myConfig && data.myConfig.color
|
||
}
|
||
]
|
||
}),
|
||
```
|
||
|
||
::: tip Совет
|
||
Обратите внимание, что `myConfig` может быть неопределён, если конфигурационного файла не существует на момент загрузки экрана конфигурации.
|
||
:::
|
||
|
||
Как можно увидеть на экране конфигурации значение `white` заменится на `black`.
|
||
|
||
Также можно предоставить значение по умолчанию, если конфигурационный файл отсутствует:
|
||
|
||
```js
|
||
// ui.js
|
||
|
||
onRead: ({ data }) => ({
|
||
prompts: [
|
||
{
|
||
name: `color`,
|
||
type: 'input',
|
||
message: 'Цвет сообщения с приветствием',
|
||
value: data.myConfig && data.myConfig.color,
|
||
default: 'black',
|
||
}
|
||
]
|
||
}),
|
||
```
|
||
|
||
#### Сохранение конфигурации после изменений
|
||
|
||
Пока мы лишь считали содержимое `myConfig.js` и использовали его на экране конфигурации. Теперь попробуем сохранить все изменения в файл. Это можно сделать с помощью хука `onWrite`:
|
||
|
||
```js
|
||
// ui.js
|
||
|
||
api.describeConfig({
|
||
/* ... */
|
||
onWrite: ({ prompts, api }) => {
|
||
// ...
|
||
}
|
||
})
|
||
```
|
||
|
||
Хук `onWrite` принимает множество [аргументов](ui-api.html#сохранение-изменений-конфигурации), но нам нужны только два из них: `prompts` и `api`. В первом текущие объекты интерактивных подсказок — получим id интерактивной подсказки и ответ для этого id. Для получения ответа воспользуемся методом `async getAnswer()` из `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)
|
||
}
|
||
```
|
||
|
||
Теперь, если на экране конфигурации изменить значение цвета в поле ввода с `black` на `red` и нажать кнопку `Save the changes`, то содержимое файла `myConfig.js` также обновится:
|
||
|
||
```js
|
||
// myConfig.js
|
||
|
||
module.exports = {
|
||
color: 'red'
|
||
}
|
||
```
|
||
|
||
### Отображение интерактивных подсказок
|
||
|
||
При желании также можно отображать [интерактивные подсказки](#интерактивные-подсказки) в Vue UI. При установке плагина через UI интерактивные подсказки будут отображаться на шаге вызова плагина.
|
||
|
||
Объект подсказки можно расширять дополнительными свойствами. Они опциональны и используются только в UI:
|
||
|
||
```js
|
||
// prompts.js
|
||
|
||
module.exports = [
|
||
{
|
||
// основные свойства интерактивных подсказок
|
||
name: `addExampleRoutes`,
|
||
type: 'confirm',
|
||
message: 'Добавить примеры маршрутов?',
|
||
default: false,
|
||
// свойства интерактивных подсказок для UI
|
||
group: 'Настоятельно рекомендуется',
|
||
description: 'Добавить примеры страниц, шаблонов и конфигурацию маршрутизатора',
|
||
link: 'https://github.com/ktsn/vue-cli-plugin-auto-routing/#vue-cli-plugin-auto-routing'
|
||
}
|
||
]
|
||
```
|
||
|
||
В результате при вызове плагина появится такой экран:
|
||
|
||

|
||
|
||
### Логотип
|
||
|
||
Можно поместить файл `logo.png` в корне каталога, который будет публиковаться в npm. Тогда его можно будет увидеть в нескольких местах:
|
||
- При поиске плагина для установки
|
||
- В списке установленных плагинов
|
||
- В списке конфигураций (по умолчанию)
|
||
- В списке дополненных задач (по умолчанию)
|
||
|
||

|
||
|
||
Логотип должен быть квадратным изображением без прозрачности (в идеале 84x84).
|
||
|
||
## Публикация плагина в npm
|
||
|
||
Для публикации плагина необходимо быть зарегистрированным на [npmjs.com](npmjs.com) и глобально установить `npm`. Если публикуете ваш первый npm-модуль, то сначала запустите команду:
|
||
|
||
```bash
|
||
npm login
|
||
```
|
||
|
||
Введите имя пользователя и пароль. Это позволит сохранить учётные данные, чтобы не приходилось вводить их при каждой публикации.
|
||
|
||
:::tip Совет
|
||
Перед публикацией плагина убедитесь, что выбрали правильное имя для него! Соглашение по именованию `vue-cli-plugin-<name>`. Дополнительную информации см. в разделе [Именование и обнаруживаемость в поиске](#именование-и-обнаруживаемость-в-поиске).
|
||
:::
|
||
|
||
Для публикации плагина перейдите в корневой каталог и выполните команду в терминале:
|
||
|
||
```bash
|
||
npm publish
|
||
```
|
||
|
||
После успешной публикации можно будет добавить ваш плагин в проект, созданный с помощью Vue CLI командой `vue add <plugin-name>`.
|