Архитектурные задачи при росте экосистемы
С момента первого релиза «Азбуки вкуса» команда столкнулась с типичными проблемами крупного фронтенд‑проекта: рост количества сервисов, дублирование бизнес‑логики и усложнение структуры модулей. При переходе на Vue 3, Nuxt 4 и TypeScript появилась возможность переосмыслить архитектуру и построить более гибкую, поддерживаемую и расширяемую систему.
Ключевые вызовы, которые стали драйверами изменений:
- Увеличение количества микросервисов – каждый сервис имел собственный набор UI‑компонентов, API‑клиентов и вспомогательных утилит.
- Повторное использование кода – одинаковые паттерны запросов, валидации форм и стилизации оказывались разбросаны по репозиториям.
- Модульность Nuxt – стандартные модули Nuxt (plugins, composables, middleware) начали конфликтовать, когда их количество превысило несколько десятков.
Выбор стека и его влияние
Vue 3 и Composition API
Переход на Vue 3 дал доступ к Composition API, который стал фундаментом для организации бизнес‑логики. Вместо разрозненных опций data, methods и computed был введён единый подход: каждый функциональный блок оформляется как отдельный composable. Это позволило:
- Явно объявлять зависимости и типы через TypeScript.
- Делить сложные компоненты на небольшие, переиспользуемые куски кода.
- Уменьшить количество повторяющихся методов, вынеся их в общие composables (например,
useApi,useFormValidation).
Nuxt 4 и сервер‑сайд рендеринг
Nuxt 4, построенный на Vite, обеспечил быстрый HMR и упрощённую настройку. Основные шаги по оптимизации проекта:
- Автоматическое импортирование composables и компонентов через
autoImports. Это избавило от необходимости явно прописывать каждый импорт в файлах, ускорив разработку. - Модульность через Nuxt modules – вместо монолитных
pluginsсозданы отдельные модули для аутентификации, аналитики и кэширования. Каждый модуль имеет собственныйruntimeиconfig, что упрощает подключение в разных сервисах. - Route‑based code splitting – динамические импорты страниц и компонентов, позволяющие загружать только необходимый JavaScript при переходе между разделами «Азбуки вкуса».
TypeScript как единый источник правды
Весь код проекта теперь строго типизирован. Выделены типы для:
- API‑ответов (генерируются из Swagger‑спецификаций).
- Параметров запросов (универсальный тип
RequestParams<T>). - Состояния Vuex (или Pinia) – каждый store имеет отдельный интерфейс состояния и методов.
Это позволило интегрировать eslint‑plugin‑typescript и prettier, поддерживая единый стиль кода и предотвращая типовые ошибки на этапе компиляции.
Структурирование репозитория
Для борьбы с дублированием был введён монорепозиторий на основе pnpm workspaces. Основные пакеты:
@azbuka/ui– библиотека UI‑компонентов, экспортирующая атомарные элементы (Button, Input) и готовые шаблоны (Card, Modal).@azbuka/api– слой доступа к бекенду, включающий типизированные клиенты для всех микросервисов.@azbuka/utils– набор утилит (форматирование дат, работа с локалью, хелперы для работы с массивами).@azbuka/config– общие конфигурационные файлы (eslint, tsconfig, vite config), импортируемые в каждом сервисе.
Каждый сервис (например, catalog, checkout, profile) подключает эти пакеты как зависимости, получая единый набор компонентов и API‑клиентов без копирования кода. При необходимости добавить новую функцию достаточно обновить один из пакетов и выпустить новую версию.
Управление состоянием и кешированием
Для глобального состояния выбран Pinia вместо Vuex, благодаря лучшей интеграции с Composition API и более простому синтаксису. Ключевые подходы:
- Modular stores – каждый микросервис имеет свой store (e.g.,
useCatalogStore,useCartStore). - Persisted state – с помощью
pinia-plugin-persistedstateсохраняются важные данные (корзина, токен) вlocalStorage. - Server‑side prefetch – при SSR Nuxt предзагружает данные через
useAsyncData, передавая их в Pinia, что уменьшает количество запросов после гидратации.
Кеширование запросов реализовано в @azbuka/api через axios‑interceptor, который проверяет наличие свежих данных в sessionStorage и возвращает их без обращения к серверу. При изменении данных (например, добавление товара в корзину) происходит инвалидация соответствующего кеша.
Тестирование и CI/CD
Для обеспечения стабильности кода введён набор автоматических проверок:
- Unit‑тесты на Jest для composables и утилит.
- E2E‑тесты на Cypress, покрывающие основные пользовательские сценарии (поиск продукта, оформление заказа).
- Static analysis –
npm run lintиnpm run typecheckзапускаются в каждом pull‑request.
CI построен на GitHub Actions: сборка, проверка типов, запуск тестов и публикация пакетов в приватный npm‑реестр. При мёрже в main автоматически деплоятся новые версии сервисов в Kubernetes‑кластеры.
Итоги внедрения
Переписывание «Азбуки вкуса» под Vue 3, Nuxt 4 и TypeScript привело к:
- Сокращению дублирования кода на 40 % благодаря общим пакетам и composables.
- Ускорению сборки проекта с 30 сек до 8 сек благодаря Vite и оптимальному code‑splitting.
- Повышению надёжности за счёт строгой типизации и автоматических проверок.
- Упрощению масштабирования: новые микросервисы подключаются к единой экосистеме без необходимости копировать базовые компоненты.
Эти изменения создали фундамент для дальнейшего развития продукта, позволяя команде быстро внедрять новые функции, поддерживать высокий уровень качества кода и эффективно управлять растущей архитектурой.