CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vuex

State management pattern and library for Vue.js applications that serves as a centralized store with predictable state mutations

Pending
Overview
Eval results
Files

development-tools.mddocs/

Development Tools

Development and debugging features including logging plugin, DevTools integration, and state subscription mechanisms.

Capabilities

Logger Plugin

Development plugin for logging store mutations and actions to the console.

/**
 * Create a logger plugin for development debugging
 * @param options - Logger configuration options
 * @returns Plugin function for store
 */
function createLogger<S>(options?: LoggerOption<S>): Plugin<S>;

interface LoggerOption<S> {
  /** Whether to collapse log groups (default: true) */
  collapsed?: boolean;
  /** Filter function to determine which mutations to log */
  filter?: <P extends Payload>(mutation: P, stateBefore: S, stateAfter: S) => boolean;
  /** Transform state before logging */
  transformer?: (state: S) => any;
  /** Transform mutations before logging */
  mutationTransformer?: <P extends Payload>(mutation: P) => any;
  /** Filter function to determine which actions to log */
  actionFilter?: <P extends Payload>(action: P, state: S) => boolean;
  /** Transform actions before logging */
  actionTransformer?: <P extends Payload>(action: P) => any;
  /** Whether to log mutations (default: true) */
  logMutations?: boolean;
  /** Whether to log actions (default: true) */
  logActions?: boolean;
  /** Custom logger object (default: console) */
  logger?: Logger;
}

interface Logger extends Partial<Pick<Console, 'groupCollapsed' | 'group' | 'groupEnd'>> {
  log(message: string, color: string, payload: any): void;
  log(message: string): void;
}

interface Payload {
  type: string;
}

type Plugin<S> = (store: Store<S>) => any;

Usage Examples:

import { createStore, createLogger } from 'vuex';

// Basic logger setup
const store = createStore({
  state: { count: 0 },
  mutations: {
    increment(state) { state.count++; }
  },
  plugins: process.env.NODE_ENV !== 'production' 
    ? [createLogger()] 
    : []
});

// Advanced logger configuration
const loggerPlugin = createLogger({
  collapsed: false, // Don't collapse log groups
  
  // Only log mutations that change important state
  filter: (mutation, stateBefore, stateAfter) => {
    return mutation.type !== 'UPDATE_SCROLL_POSITION';
  },
  
  // Transform state to hide sensitive data
  transformer: (state) => ({
    ...state,
    user: state.user ? { ...state.user, password: '[HIDDEN]' } : null
  }),
  
  // Format mutation display
  mutationTransformer: (mutation) => ({
    type: mutation.type,
    payload: mutation.type.includes('PASSWORD') 
      ? '[HIDDEN]' 
      : mutation.payload
  }),
  
  // Only log specific actions
  actionFilter: (action, state) => {
    return !action.type.startsWith('analytics/');
  },
  
  // Custom action formatting
  actionTransformer: (action) => ({
    ...action,
    timestamp: Date.now()
  }),
  
  // Disable action logging in production
  logActions: process.env.NODE_ENV !== 'production',
  
  // Custom logger
  logger: {
    log: console.log,
    groupCollapsed: console.groupCollapsed,
    groupEnd: console.groupEnd
  }
});

const store = createStore({
  // ... store config
  plugins: [loggerPlugin]
});

State Subscription

Subscribe to mutations and actions for debugging and monitoring.

/**
 * Subscribe to store mutations
 * @param fn - Callback function called on each mutation
 * @param options - Subscription options
 * @returns Unsubscribe function
 */
subscribe<P extends MutationPayload>(
  fn: (mutation: P, state: S) => any, 
  options?: SubscribeOptions
): () => void;

/**
 * Subscribe to store actions
 * @param fn - Callback function or options object
 * @param options - Subscription options
 * @returns Unsubscribe function
 */
subscribeAction<P extends ActionPayload>(
  fn: SubscribeActionOptions<P, S>, 
  options?: SubscribeOptions
): () => void;

interface MutationPayload extends Payload {
  payload: any;
}

interface ActionPayload extends Payload {
  payload: any;
}

interface SubscribeOptions {
  /** Add subscriber to beginning of list */
  prepend?: boolean;
}

type ActionSubscriber<P, S> = (action: P, state: S) => any;
type ActionErrorSubscriber<P, S> = (action: P, state: S, error: Error) => any;

interface ActionSubscribersObject<P, S> {
  before?: ActionSubscriber<P, S>;
  after?: ActionSubscriber<P, S>;
  error?: ActionErrorSubscriber<P, S>;
}

type SubscribeActionOptions<P, S> = ActionSubscriber<P, S> | ActionSubscribersObject<P, S>;

Usage Examples:

import { createStore } from 'vuex';

const store = createStore({
  state: { count: 0, logs: [] },
  mutations: {
    increment(state) { state.count++; },
    addLog(state, message) { state.logs.push(message); }
  },
  actions: {
    async fetchData({ commit }) {
      const data = await api.getData();
      commit('setData', data);
    }
  }
});

// Subscribe to mutations
const unsubscribeMutations = store.subscribe((mutation, state) => {
  console.log('Mutation:', mutation.type);
  console.log('Payload:', mutation.payload);
  console.log('New state:', state);
  
  // Log mutations to server
  analytics.track('store_mutation', {
    type: mutation.type,
    payload: mutation.payload
  });
});

// Subscribe to actions with lifecycle hooks
const unsubscribeActions = store.subscribeAction({
  before: (action, state) => {
    console.log(`Before action ${action.type}`, action.payload);
    // Start performance timing
    performance.mark(`action-${action.type}-start`);
  },
  
  after: (action, state) => {
    console.log(`After action ${action.type}`, state);
    // End performance timing
    performance.mark(`action-${action.type}-end`);
    performance.measure(
      `action-${action.type}`, 
      `action-${action.type}-start`, 
      `action-${action.type}-end`
    );
  },
  
  error: (action, state, error) => {
    console.error(`Action ${action.type} failed:`, error);
    // Log errors to monitoring service
    errorReporting.captureException(error, {
      action: action.type,
      payload: action.payload,
      state
    });
  }
});

// Subscribe with prepend option
const debugSubscriber = store.subscribe((mutation, state) => {
  // This will be called first due to prepend: true
  console.log('Debug:', mutation);
}, { prepend: true });

// Cleanup subscriptions
const cleanup = () => {
  unsubscribeMutations();
  unsubscribeActions();
  debugSubscriber();
};

// Auto-cleanup on app unmount
window.addEventListener('beforeunload', cleanup);

State Watching

Watch specific parts of the store state for changes.

/**
 * Watch a computed value derived from store state
 * @param getter - Function that returns the value to watch
 * @param cb - Callback function called when value changes
 * @param options - Watch options (Vue WatchOptions)
 * @returns Unwatch function
 */
watch<T>(
  getter: (state: S, getters: any) => T, 
  cb: (value: T, oldValue: T) => void, 
  options?: WatchOptions
): () => void;

// Note: WatchOptions is imported from Vue and includes:
// { deep?: boolean; immediate?: boolean; flush?: 'pre' | 'post' | 'sync' }

Usage Examples:

import { createStore } from 'vuex';

const store = createStore({
  state: {
    user: null,
    cart: { items: [] },
    ui: { theme: 'light' }
  },
  getters: {
    cartTotal: state => state.cart.items.reduce((sum, item) => 
      sum + item.price * item.quantity, 0),
    itemCount: state => state.cart.items.length
  }
});

// Watch specific state property
const unwatchUser = store.watch(
  (state) => state.user,
  (newUser, oldUser) => {
    console.log('User changed:', { newUser, oldUser });
    
    if (newUser && !oldUser) {
      // User logged in
      analytics.track('user_login', { userId: newUser.id });
    } else if (!newUser && oldUser) {
      // User logged out
      analytics.track('user_logout', { userId: oldUser.id });
    }
  },
  { deep: true } // Watch object properties
);

// Watch computed getter
const unwatchCartTotal = store.watch(
  (state, getters) => getters.cartTotal,
  (newTotal, oldTotal) => {
    console.log(`Cart total changed: ${oldTotal} -> ${newTotal}`);
    
    // Update localStorage
    localStorage.setItem('cartTotal', newTotal.toString());
    
    // Show notification for significant changes
    if (newTotal - oldTotal > 100) {
      showNotification('Large price change detected!');
    }
  }
);

// Watch multiple values
const unwatchMultiple = store.watch(
  (state, getters) => ({
    user: state.user,
    itemCount: getters.itemCount,
    theme: state.ui.theme
  }),
  (newValues, oldValues) => {
    // React to changes in any watched value
    console.log('Multiple values changed:', { newValues, oldValues });
  },
  { deep: true }
);

// Watch with immediate option
const unwatchImmediate = store.watch(
  (state) => state.ui.theme,
  (theme) => {
    document.body.className = `theme-${theme}`;
  },
  { immediate: true } // Call immediately with current value
);

// Conditional watching
let themeWatcher = null;

const startThemeWatching = () => {
  if (!themeWatcher) {
    themeWatcher = store.watch(
      (state) => state.ui.theme,
      (theme) => applyTheme(theme)
    );
  }
};

const stopThemeWatching = () => {
  if (themeWatcher) {
    themeWatcher();
    themeWatcher = null;
  }
};

// Cleanup all watchers
const cleanup = () => {
  unwatchUser();
  unwatchCartTotal();
  unwatchMultiple();
  unwatchImmediate();
  stopThemeWatching();
};

DevTools Integration

Integration with Vue DevTools browser extension for debugging.

Usage Examples:

import { createApp } from 'vue';
import { createStore } from 'vuex';

// DevTools is automatically enabled in development
const store = createStore({
  state: { count: 0 },
  mutations: {
    increment(state) { state.count++; }
  },
  // DevTools enabled by default in development
  devtools: process.env.NODE_ENV !== 'production'
});

// Explicit DevTools control
const store = createStore({
  state: { count: 0 },
  mutations: {
    increment(state) { state.count++; }
  },
  devtools: true // Force enable even in production
});

// Custom DevTools configuration
const app = createApp(App);
const store = createStore({
  // ... store config
  devtools: true
});

app.use(store);

// DevTools will show:
// - State tree with current values
// - Mutation history with time-travel debugging
// - Action dispatch logging
// - Module hierarchy
// - Getter values and dependencies

// Time-travel debugging features:
// 1. Click on any mutation in the timeline to see state at that point
// 2. Use "Commit All" to apply all mutations up to a point
// 3. Use "Revert" to undo mutations
// 4. Export/import state snapshots
// 5. Filter mutations and actions by type or module

Custom Development Plugins

Create custom plugins for development workflow enhancement.

Usage Examples:

// Performance monitoring plugin
const performancePlugin = (store) => {
  const actionTimes = new Map();
  
  store.subscribeAction({
    before: (action) => {
      actionTimes.set(action.type, performance.now());
    },
    after: (action) => {
      const startTime = actionTimes.get(action.type);
      const duration = performance.now() - startTime;
      
      if (duration > 100) {
        console.warn(`Slow action detected: ${action.type} took ${duration}ms`);
      }
      
      actionTimes.delete(action.type);
    }
  });
};

// State persistence plugin
const persistPlugin = (store) => {
  // Load state from localStorage on store creation
  const saved = localStorage.getItem('vuex-state');
  if (saved) {
    store.replaceState(JSON.parse(saved));
  }
  
  // Save state on every mutation
  store.subscribe((mutation, state) => {
    localStorage.setItem('vuex-state', JSON.stringify(state));
  });
};

// Error tracking plugin
const errorTrackingPlugin = (store) => {
  store.subscribeAction({
    error: (action, state, error) => {
      // Send to error tracking service
      errorTracker.captureException(error, {
        extra: {
          action: action.type,
          payload: action.payload,
          state: JSON.stringify(state)
        }
      });
    }
  });
};

// Usage
const store = createStore({
  // ... store config
  plugins: process.env.NODE_ENV !== 'production' 
    ? [createLogger(), performancePlugin, errorTrackingPlugin]
    : [persistPlugin]
});

Install with Tessl CLI

npx tessl i tessl/npm-vuex

docs

component-helpers.md

composition-api.md

development-tools.md

index.md

module-system.md

store-management.md

tile.json