--- 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-` или `@scope/vue-cli-plugin-`. Такой подход позволяет вашему плагину быть: - Обнаруживаемым `@vue/cli-service`; - Обнаруживаемым другими разработчиками при поиске; - Устанавливаемым с помощью команд `vue add ` или `vue invoke `. :::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" } ``` ![Plugin search item](/plugin-search-item.png) ## Генератор Генератор — это часть плагина 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`: ![Структура файлов генератора](/generator-template.png) После создания необходимо добавить вызов `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 / ``` Также есть возможность заменять сразу несколько мест в файле одновременно, для этого потребуется обернуть заменяющие строки в блоки `<%# REPLACE %>` и `<%# END_REPLACE %>`: ```ejs --- extend: '@vue/cli-service/generator/template/src/App.vue' replace: - !!js/regexp /Добро пожаловать в приложение Vue\.js/ - !!js/regexp / <%# 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 } ] ``` При вызове плагина пользователю будет предложено ответить на вопрос о добавлении примеров маршрутов с ответом по умолчанию «Нет». ![Пример интерактивных подсказок](/prompts-example.png) Если необходимо использовать результат выбора пользователя в генераторе, ответ будет доступен по имени интерактивной подсказки. Теперь можно модифицировать `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 ``` Вызов этих команд необходимо повторять каждый раз при внесении изменений в плагин. Другой способ добавления плагина — воспользоваться возможностями Vue UI. Выполните команду: ```bash vue ui ``` Пользовательский интерфейс откроется в браузере по адресу `localhost:8000`. Перейдите на вкладку `Vue Project Manager`: ![Менеджер проекта Vue](/ui-project-manager.png) И найдите в списке название тестового проекта: ![Список плагинов в UI](/ui-select-plugin.png) Нажмите на название приложения, перейдите на вкладку плагинов (значок пазла) и затем нажмите кнопку `Add new plugin` (Добавить новый плагин) в правом верхнем углу. На новой странице будет отображён список плагинов Vue CLI, доступных через npm. В нижней части страницы будет кнопка `Browse local plugin` (Выбор локального плагина): ![Выбор локальный плагин](/ui-browse-local-plugin.png) В окне выбора находим тестируемый плагин и добавляем в проект. После этого он станет виден в списке плагинов, а применить изменения к плагину можно просто нажав на иконку обновления: ![Refresh plugin](/ui-plugin-refresh.png) ## Интеграция с UI Vue CLI имеет отличный UI с помощью которого пользователь может разворачивать и управлять проектом в удобном графическом интерфейсе. Плагины Vue CLI могут интегрироваться в этот интерфейс. Также UI предоставляет дополнительные возможности для плагинов CLI: - можно напрямую из UI запускать npm-задачи, в том числе и специфичные для плагинов; - можно отображать экран с настройками конфигурации плагина. Например, [vue-cli-plugin-apollo](https://github.com/Akryum/vue-cli-plugin-apollo) предоставляет отдельный экран для конфигурации сервера Apollo: ![Экран конфигурации в UI](/ui-configuration.png) - можно отображать [интерактивные подсказки](#интерактивные-подсказки) при создании проекта - можно добавлять локализации плагина при необходимости поддержки нескольких языков - можно сделать плагин обнаруживаемым при поиске в 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, а также экран для отображения результатов выполнения задачи: ![Задача Greet в UI](/ui-greet-task.png) ### Отображение экрана конфигурации Иногда в проекте могут быть пользовательские файлы конфигураций для различных функций или библиотек. С помощью плагина Vue CLI можно отображать конфигурацию в Vue UI, изменять её и сохранять (сохранение изменит соответствующий конфигурационный файл в проекте). По умолчанию в проекте Vue CLI имеется только главный экран конфигурации с настройками из `vue.config.js`. Если добавить ESLint в проект, то появится также экран конфигурации ESLint: ![Экран конфигурации в UI](/ui-configuration-default.png) Давайте создадим экран конфигурации для плагина. Прежде всего, после добавления плагина в существующий проект, должен быть файл с пользовательской конфигурацией. Это означает, что требуется добавить этот файл в каталог `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`. Вот как будет выглядеть экран конфигурации со всеми приведёнными выше настройками: ![Начало конфигурации UI](/ui-config-start.png) Заменим теперь статическое значение `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' } ] ``` В результате при вызове плагина появится такой экран: ![Интерактивные подсказки в UI](/ui-prompts.png) ### Логотип Можно поместить файл `logo.png` в корне каталога, который будет публиковаться в npm. Тогда его можно будет увидеть в нескольких местах: - При поиске плагина для установки - В списке установленных плагинов - В списке конфигураций (по умолчанию) - В списке дополненных задач (по умолчанию) ![Плагины](/plugins.png) Логотип должен быть квадратным изображением без прозрачности (в идеале 84x84). ## Публикация плагина в npm Для публикации плагина необходимо быть зарегистрированным на [npmjs.com](npmjs.com) и глобально установить `npm`. Если публикуете ваш первый npm-модуль, то сначала запустите команду: ```bash npm login ``` Введите имя пользователя и пароль. Это позволит сохранить учётные данные, чтобы не приходилось вводить их при каждой публикации. :::tip Совет Перед публикацией плагина убедитесь, что выбрали правильное имя для него! Соглашение по именованию `vue-cli-plugin-`. Дополнительную информации см. в разделе [Именование и обнаруживаемость в поиске](#именование-и-обнаруживаемость-в-поиске). ::: Для публикации плагина перейдите в корневой каталог и выполните команду в терминале: ```bash npm publish ``` После успешной публикации можно будет добавить ваш плагин в проект, созданный с помощью Vue CLI командой `vue add `.