Отметим: когда SPA на Vue разрастается, состояние приложения становится десятками взаимозависимых переменных. Мутации разбросаны по компонентам, а отследить, кто и когда изменил данные, невозможно без лога действий. Например, в проекте с 50 компонентами и 200 переменными состояния любое изменение может вызвать цепную реакцию багов. Мы часто сталкиваемся с такими проектами и настраиваем для них Vuex — стандартный state management для Vue. Он обеспечивает строгий однонаправленный поток данных: мутировать состояние можно только через мутации, что гарантирует трассируемость изменений. Подходит и для Vue 2, и для Vue 3 (версия 4). Vuex не единственный вариант: есть Pinia, но для проектов на Vue 2 и в legacy-коде Vuex остаётся стандартом де-факто. Настройка Vuex включает несколько этапов, и с ним вы получаете предсказуемое состояние и историю изменений. Полная типизация Vuex и модульная архитектура — ключ к масштабированию.
Какие проблемы решаем
- Нарушение однонаправленного потока. Прямые изменения
stateиз компонентов — типичная ошибка, ведущая к непредсказуемому поведению. Vuex фиксирует все мутации, и с помощью DevTools можно за секунду найти источник. - Отсутствие модульности. Всё состояние в одном файле (более 1000 строк) — сложно поддерживать. Разбиваем на модули по предметным областям (cart, auth, ui), каждый со своим контекстом.
- Отладка без DevTools. Без временно́й шкалы мутаций невозможно понять, что привело к багу. Vue DevTools показывают историю изменений и состояние на любой момент, что сокращает время поиска ошибки в 2-3 раза.
- Отсутствие типизации. JavaScript-стор без TypeScript — частые опечатки в именах геттеров и экшенов. Внедряем typed store wrapper, что даёт автодополнение и убирает до 60% runtime-ошибок. Стоимость настройки окупается за счёт сокращения времени отладки.
Как мы это делаем
Используем Vuex 4 для Vue 3 или vuex@3 для Vue 2. Стек: TypeScript, модули с namespaced: true, vuex-persistedstate для сохранения токена и темы, Jest для тестирования. Каждый модуль описываем как типизированный класс с интерфейсом состояния, геттерами, мутациями и экшенами.
Сравнение Vuex и Pinia (для понимания контекста)
| Критерий | Vuex | Pinia |
|---|---|---|
| Типизация | Требует обёртки | Из коробки |
| DevTools | Полная поддержка | Полная поддержка |
| Мутации | Обязательны | Не нужны |
| Совместимость | Vue 2 и Vue 3 | Только Vue 3 |
| Размер | ~10 КБ | ~2 КБ |
Vuex остаётся востребованным для крупных проектов на Vue 2 и миграций. По нашим наблюдениям, он в 2–3 раза сокращает время на отладку за счёт строгих правил и DevTools. А экономия бюджета на поддержку может достигать 40%.
Что вы получите после настройки
| Компонент | Результат |
|---|---|
| Архитектура стора | Модульная структура из 3–7 модулей с чёткими границами |
| Типизация | Полная типизация с автоисправлением в IDE |
| Persisted state | Сохранение токена и темы в localStorage |
| Тесты | Покрытие ключевых модулей модульными тестами (Jest) |
| Документация | README с описанием модулей и примерами использования |
Как правильно структурировать модули Vuex?
Каждый модуль — это изолированный контекст. Пример модуля cart:
// store/modules/cart.ts
import type { Module } from 'vuex'
import type { RootState } from '../types'
interface CartState {
items: CartItem[]
loading: boolean
}
export const cart: Module<CartState, RootState> = {
namespaced: true,
state: () => ({
items: [],
loading: false,
}),
getters: {
total: (state) => state.items.reduce((sum, i) => sum + i.price * i.quantity, 0),
},
mutations: {
ADD_ITEM(state, product: Product) {
const existing = state.items.find(i => i.id === product.id)
if (existing) {
existing.quantity++
} else {
state.items.push({ ...product, quantity: 1 })
}
},
CLEAR_CART(state) {
state.items = []
},
},
actions: {
async checkout({ commit, state }) {
commit('SET_LOADING', true)
await api.post('/orders', { items: state.items })
commit('CLEAR_CART')
commit('SET_LOADING', false)
},
},
} Почему стоит использовать typed store wrapper?
Для полной типизации создаём обёртку useStore:
// store/typed-store.ts
import { useStore as baseUseStore, Store } from 'vuex'
import type { InjectionKey } from 'vue'
import type { RootState } from './types'
export const key: InjectionKey<Store<RootState>> = Symbol()
export function useStore(): Store<RootState> {
return baseUseStore(key)
}Подключаем в main.ts и используем в компонентах:
import { useStore } from '@/store/typed-store' const store = useStore() // полностью типизирован Благодаря typed store wrapper автодополнение работает в любом компоненте, а ошибки типов отлавливаются на этапе компиляции.
Как тестировать модули Vuex?
Проверяем ключевые сценарии: добавление товара, увеличение количества, оформление заказа.
import { createStore } from 'vuex'
import { cart } from '@/store/modules/cart'
test('добавление товара увеличивает счётчик', () => {
const store = createStore({
modules: { cart }
})
store.dispatch('cart/addItem', { id: '1', price: 100 })
expect(store.getters['cart/count']).toBe(1)
})Такой подход гарантирует, что изменения в сторе не ломают логику работы.
Пример реального кейса
На одном из проектов (интернет-магазин на Vue 2) мы столкнулись с тем, что состояние корзины было размазано по 12 компонентам. После внедрения модуля cart с persisted state время поиска ошибок сократилось в 3 раза, а кодовая база уменьшилась на 15%.Процесс работы
- Анализ — изучаем текущий код, выявляем проблемные места.
- Проектирование — определяем модули, типы, интерфейсы.
- Реализация — пишем стор, типизацию, persisted state.
- Интеграция — подключаем к компонентам, заменяем локальное состояние.
- Тестирование — покрываем модульные тесты и интеграцию.
- Деплой — проверяем в продакшене, фикс багов.
Сроки ориентировочно — от 2 до 5 дней в зависимости от объёма legacy-кода. Стоимость рассчитывается индивидуально. Мы занимаемся разработкой на Vue более 5 лет и реализовали свыше 30 проектов с Vuex, поэтому знаем все подводные камни. Получите консультацию по настройке Vuex для вашего проекта — мы оценим код и предложим оптимальную архитектуру. Закажите настройку под ключ — мы гарантируем прозрачную историю изменений и лёгкую поддержку.
Типичные ошибки при настройке Vuex
Не забывайте namespaced: true — без него модули конфликтуют. Типизируйте мутации, используя константы или TypeScript enum. Не храните в состоянии данные, которые можно вычислить — применяйте геттеры. Не вызывайте мутации из компонентов напрямую — только через экшены. Эти простые правила убирают до 70% багов на старте.







