כאשר אפליקציית Vue SPA גדלה, מצב האפליקציה הופך לעשרות משתנים תלויים זה בזה. מוטציות מפוזרות בין רכיבים, ומעקב אחר מי שינה מה בלתי אפשרי ללא לוג. לדוגמה, בפרויקט עם 50 רכיבים ו-200 משתני מצב, כל שינוי יכול לגרום למפל של באגים. אנו מגדירים Vuex — ניהול המצב הסטנדרטי עבור Vue — כדי לאכוף זרימת נתונים חד-כיוונית קפדנית, מה שהופך כל מוטציה לניתנת למעקב. זה עובד גם עבור Vue 2 וגם עבור Vue 3 (גרסה 4). בעוד שקיימות חלופות כמו Pinia, Vuex נשאר התקן דה-פקטו עבור Vue 2 וקוד מורשת. ההתקנה כוללת מספר שלבים, ומקבלים מצב צפוי עם היסטוריית שינויים מלאה. טיפוס מלא וארכיטקטורה מודולרית הם המפתח לסקייל.
בעיות שאנו פותרים
- זרימה חד-כיוונית שבורה. מוטציות ישירות למצב מרכיבים הן טעות נפוצה שמובילה להתנהגות בלתי צפויה. Vuex מתעד כל מוטציה, ועם DevTools ניתן למצוא את המקור באופן מיידי.
- חוסר מודולריות. כל המצב בקובץ אחד (מעל 1000 שורות) קשה לתחזוקה. אנו מפצלים למודולים לפי תחום עסקי (עגלה, אימות, ממשק משתמש), כל אחד עם הקונטקסט שלו.
- ניפוי באגים ללא DevTools. ללא ציר זמן של מוטציות, אי אפשר להבין מה גרם לבאג. Vue DevTools מציגים היסטוריית מוטציות ומצב בכל נקודת זמן, ומפחיתים את זמן חיפוש השגיאות פי 2–3.
- חוסר TypeScript. חנויות מבוססות JavaScript בלבד נוטות לשגיאות הקלדה בשמות getters ופעולות. אנו מיישמים מעטפת חנות מטופלת, המעניקה השלמה אוטומטית ומבטלת עד 60% משגיאות הריצה. עלות ההתקנה משתלמת דרך הפחתת זמן הניפוי.
איך אנחנו עושים את זה
אנו משתמשים ב-Vuex 4 עבור Vue 3 או vuex@3 עבור Vue 2. מחסנית: TypeScript, מודולים עם state, namespaced: true עבור אחסון טוקן ונושא, Jest לבדיקות. כל מודול הוא מחלקה מטופלת עם ממשק מצב, getters, מוטציות ופעולות.
Vuex לעומת Pinia (להקשר)
| קריטריון | Vuex | Pinia |
|---|---|---|
| טיפוס | נדרשת מעטפת | מובנה |
| DevTools | תמיכה מלאה | תמיכה מלאה |
| מוטציות | נדרשות | לא נדרשות |
| תאימות | Vue 2 ו-Vue 3 | Vue 3 בלבד |
| גודל | ~10 KB | ~2 KB |
Vuex נשאר רלוונטי עבור פרויקטי Vue 2 גדולים והגירות. לפי הניסיון שלנו, הוא מפחית את זמן הניפוי פי 2–3 בזכות חוקים קפדניים ו-DevTools. חיסכון בתקציב התמיכה יכול להגיע ל-40%.
מה מקבלים לאחר ההתקנה
| רכיב | תוצאה |
|---|---|
| ארכיטקטורת חנות | מבנה מודולרי עם 3–7 מודולים מופרדים בבירור |
| טיפוס | TypeScript מלא עם השלמה אוטומטית ב-IDE |
| מצב מתמשך | טוקן ונושא נשמרים ב-localStorage |
| בדיקות | מודולים מרכזיים מכוסים בבדיקות יחידה עם Jest |
| תיעוד | README עם תיאורי מודולים ודוגמאות שימוש |
איך לבנות מודולי Vuex נכון
כל מודול הוא קונטקסט מבודד. דוגמה למודול vuex-persistedstate:
// 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)
},
},
} למה להשתמש במעטפת חנות מטופלת?
לטיפוס מלא, אנו יוצרים מעטפת cart:
// 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)
}רושמים אותה ב-// 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) }, }, } ומשתמשים ברכיבים:
import { useStore } from '@/store/typed-store' const store = useStore() // полностью типизирован עם מעטפת חנות מטופלת, ההשלמה האוטומטית עובדת בכל רכיב, ושגיאות טיפוס נתפסות בזמן הקומפילציה.
איך לבדוק מודולי 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 רכיבים. לאחר יישום מודול עגלה עם מצב מתמשך, זמן הניפוי ירד פי 3, והקוד הצטמצם ב-15%.תהליך העבודה
- ניתוח — סקירת קוד קיים, זיהוי נקודות כאב.
- עיצוב — הגדרת מודולים, טיפוסים, ממשקים.
- יישום — כתיבת חנות, טיפוסים, מצב מתמשך.
- אינטגרציה — חיבור לרכיבים, החלפת מצב מקומי.
- בדיקות — בדיקות יחידה למודולים מרכזיים ואינטגרציה.
- פריסה — אימות בייצור, תיקון באגים.
ציר זמן: בדרך כלל 2–5 ימים תלוי בנפח קוד המורשת. העלות מחושבת באופן אישי. אנו עוסקים בפיתוח Vue למעלה מ-5 שנים והשלמנו 30+ פרויקטי Vuex, כך שאנו מכירים את כל המלכודות. קבלו ייעוץ על התקנת Vuex לפרויקט שלכם — נבדוק את הקוד שלכם ונציע ארכיטקטורה אופטימלית. הזמינו התקנה סוהר — אנו מבטיחים היסטוריית שינויים שקופה ותחזוקה קלה.
טעויות נפוצות בהתקנת Vuex
- לא מגדירים
useStore— מודולים יתנגשו. - לא מטיפוס מוטציות — השתמשו בקבועים או ב-TypeScript enums.
- אחסון נתונים מחושבים במצב — השתמשו ב-getters במקום.
- קריאה ישירה למוטציות מרכיבים — תמיד עברו דרך פעולות.
החוקים הפשוטים האלה מבטלים עד 70% מהבאגים מההתחלה.







