Классы обслуживания, использующие плагины в Nuxt.js

Поначалу создание приложений Nuxt может показаться простым - у вас есть компоненты, страницы и, возможно, несколько плагинов. Однако по мере роста вашего приложения и усложнения бизнес-логики размер и структура вашего приложения также увеличиваются. Сначала это может быть неочевидно, но по мере того, как в кодовую базу попадает все больше вызовов API или других интеграций, вы быстро поймете, насколько быстро эти проблемы могут стать неуправляемыми, будь то из-за повторяющегося кода, плохо спроектированной структуры или ее отсутствия. .

Возьмем, к примеру, вызовы API. Каждое приложение, от простого todo-приложения до крупномасштабной платформы электронной коммерции, требует HTTP-запросов к внешнему API, будь то тот, который вы создали сами или сторонний. В некоторых ситуациях вам может потребоваться дважды вызвать одну и ту же конечную точку API.

Продолжая работу с платформой электронной коммерции, рассмотрите возможность, при которой вам нужно отображать рекомендации для пользователя на основе его истории покупок или просмотров. Вместо того, чтобы отображать его только в одном месте, вы можете отобразить рекомендации как на главной странице для максимальной видимости, так и в их корзине для покупок, чтобы побудить их покупать больше продуктов. Это две совершенно разные страницы, но каждая из них должна загружать одно и то же содержимое с одной и той же конечной точки API.

Вы можете просто написать полный вызов API в каждом компоненте страницы и вернуть данные с помощью функции Nuxt asyncData.

Конечно, это работает, но это касается только страницы рекомендаций. А как насчет домашней страницы? Вы собираетесь скопировать и вставить туда и этот код? Что произойдет, если изменится конечная точка API для получения рекомендаций? Собираетесь ли вы найти все экземпляры этого URL-адреса и заменить их новым?

Вместо этого давайте позаботимся о том, чтобы код был СУХИМ (он же не повторяйся), что является одним из важнейших принципов разработки программного обеспечения для написания чистого кода. Вместо того, чтобы копировать и вставлять повсюду похожие строки кода, мы можем использовать концепцию, называемую служебные классы, которая позволит нам абстрагироваться от общей логики, делая ее чистой и пригодной для повторного использования.

Внедрение плагина

Хотя ни Vue, ни Nuxt не построены с учетом архитектуры внедрения зависимостей, такой как Angular или другие фреймворки, все же остается простой способ сделать классы обслуживания, подобные этим, доступными повсюду в вашем приложении, как для рендеринга на стороне сервера, так и для клиент. В Nuxt это понятие называется плагины. Они часто используются в сторонних модулях, но могут быть столь же полезны для структурирования логики вашего собственного приложения. В частности, мы хотим глубже изучить внедрение свойств как в экземпляр Vue, так и в контекст приложения Nuxt, задокументированные далее на странице.

Внедрение свойств позволяет нам делать функции или другие значения доступными в обоих компонентах Vue, включая хуки жизненного цикла, шаблоны и методы, а также в контексте Nuxt, к которому можно получить доступ из других мест, таких как хук asyncData на страницах или в дополнительных плагины.

Давайте кратко рассмотрим пример внедрения в документации, чтобы увидеть возможности, которые он может предоставить.

Супер просто! Метод внедряется везде, где он может вам понадобиться, включая экземпляр Vue и контекст Nuxt. Nuxt также автоматически добавит к внедренному методу префикс $, чтобы отличить его от методов первой стороны. В документации также напоминается, что вам необходимо зарегистрировать плагин в plugins разделах вашего nuxt.config.js файла.

Теперь, когда плагин зарегистрирован и $hello внедрен, давайте посмотрим, как его можно использовать.

Метод $hello доступен повсюду, обеспечивая те же функции без повторения кода. Конечно, $hello буквально «Hello World!» функция и не была бы такой уж полезной, но возможности, которые она предоставляет, безграничны.

Одна из наиболее полезных функций injection состоит в том, что внедренные свойства также доступны в хранилище VueX, что позволяет использовать их в отправленных действиях.

Опять же - не очень полезно без дополнительной логики, но рассмотрите функциональные возможности, которые он может предоставить, такие как выборка и сохранение данных из API, отправка уведомлений пользовательского интерфейса или обработка проверки формы.

Классы обслуживания

Забудьте об одном методе. Инъекция Nuxt поддерживает любой тип свойства, не только функции или статические значения, но и целые классы.

Хотя наш $hello метод был не так уж и полезен, вся служба ведения журнала могла быть полезнее.

Хотя он по-прежнему прост, он дает представление о функциональных возможностях, которые могут предоставить классы обслуживания.

Прежде чем мы сможем использовать методы класса, нам нужно будет создать экземпляр LoggingService и внедрить его, как мы это делали с предыдущей функцией $hello.

Достаточно просто. После того, как вы зарегистрируете свой плагин в своем nuxt.config.js, LoggingService будет доступен под свойством $logging, как и $hello, но на этот раз предоставляя несколько функций, все инкапсулированные внутри класса.

Давайте приступим к работе.

Как и раньше, LoggingService методы доступны во всем компоненте - в шаблоне, хуках жизненного цикла или даже в методах. Больше не нужно копировать и вставлять console.log('[My App] .....') в свое приложение.

Классы обслуживания и зависимости

Возможно, простая логика, такая как ведение журнала, может быть импортирована как отдельные функции из вашего типичного модуля, и это не обязательно неправильно. Однако такая структура становится значительно более полезной, когда ваши классы полагаются на другие зависимости для своей функциональности.

Вернемся к предыдущему примеру электронной коммерции, где на странице рекомендаций нужно было отображать список рекомендуемых продуктов из внешнего API. В этом примере мы использовали собственный модуль @nuxt/axios, который упростил наши HTTP-запросы.

Так же, как мы внедрили $hello и $logging в контекст приложения, Axios также внедрила собственное свойство $axios, предоставив предварительно настроенный экземпляр клиента Axios для использования в компонентах, плагинах и VueX. Учитывая, что this$axios доступен в контексте, мы так же легко можем внедрить его в класс службы через его конструктор, сделав его доступным для всех методов нашего класса.

Предположим, что когда RecommendationsService создан (до того, как мы его внедрим), он получит экземпляр клиента Axios в качестве единственного аргумента. Для примера предположим, что getRecommendations() возвращает данные в формате, подобном следующему:

/api/recommendations
{
  // array of recommendations 
  data: [
    { ... }, 
  ]
}

Как обычно, прежде чем мы сможем вызвать нашу службу, нам нужно будет внедрить ее, на этот раз передав экземпляр $axios из контекста приложения плагина.

После просмотра предыдущих модификаций этого плагина и понимания контекста приложения внедрение RecommendationsService должно быть довольно простым. Экземпляр $axios просто извлекается из контекста и передается конструктору до внедрения экземпляра класса.

Прежде чем закончить, давайте кратко рассмотрим, как эта служба используется, что определенно более интересно, чем регистрация нескольких сообщений с помощью нашей предыдущей службы.

Просто загружая список рекомендаций и отображая их для пользователя, этот компонент предлагает два метода доступа к RecommendationsService - либо через ловушку asyncData, требующую, чтобы данные были загружены перед отрисовкой страницы, либо через наш метод reloadRecommendations, который можно вызвать нажав кнопку в шаблоне. Хотя каждый метод обращается к сервису немного по-разному, оба они работают одинаково.

Хотите, чтобы ваши рекомендации отображались на другой странице? Нет необходимости переписывать вызов API Axios, если можно просто вернуться к классу обслуживания.

И последнее, что нужно отметить о нашей зависимости Axios в классе RecommendationsService! Вы можете просто импортировать Axios непосредственно из его модуля, но имейте в виду, что при этом будет создан новый клиент с конфигурацией по умолчанию - без учета каких-либо модификаций (например, базового URL-адреса), которые плагин @nuxt/axios уже настроил, которые доступны только через экземпляр, введенный в контекст приложения.

Так же, как мы внедрили Axios - можно внедрить любую другую зависимость, включая VueX $store или даже HTTP-клиент $http, предоставленный модулем @nuxt/http.

Заключение

По мере того, как вы продолжаете создавать свои приложения Nuxt, потребность в разделении логики и создании своего рода шаблона обслуживания быстро станет очевидной.

Существуют различные способы структурировать такую ​​архитектуру, но одна из замечательных (но иногда не очень!) Особенностей Nuxt заключается в том, что она не очень самоуверенна, что позволяет вам разрабатывать свое приложение так, как лучше всего подходит для ваших вариантов использования.

Вы можете создать новую папку для своих служб или даже обернуть все свои службы API в один объект, например, сделав службы рекомендаций и ведения журналов доступными по адресам app.$api.recommendations и app.$api.logging соответственно, чтобы предотвратить чрезмерное загрязнение контекста.

Ознакомьтесь с примерами кода здесь и следите за будущими статьями, посвященными улучшенным сервисным классам API, а также интеграции TypeScript.