CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue--runtime-core

Vue.js 3 runtime core library providing foundational APIs for building custom renderers and managing reactive component systems

Pending
Overview
Eval results
Files

error-handling.mddocs/

Error Handling

Vue's error handling system provides utilities for graceful error management, including error capture, handling, and reporting mechanisms for building robust applications.

Capabilities

Error Handling Functions

Handle errors with proper context and error information.

/**
 * Handles errors with Vue's error handling pipeline
 * @param err - Error to handle
 * @param instance - Component instance where error occurred
 * @param type - Error type for categorization
 */
function handleError(
  err: unknown,
  instance: ComponentInternalInstance | null,
  type: ErrorTypes
): void;

/**
 * Calls a function with error handling
 * @param fn - Function to call
 * @param instance - Component instance context
 * @param type - Error type
 * @param args - Arguments to pass to function
 * @returns Function result or undefined on error
 */
function callWithErrorHandling<T extends any[], R>(
  fn: (...args: T) => R,
  instance: ComponentInternalInstance | null,
  type: ErrorTypes,
  args?: T
): R | undefined;

/**
 * Calls async function(s) with error handling
 * @param fn - Function or array of functions to call
 * @param instance - Component instance context
 * @param type - Error type
 * @param args - Arguments to pass to function(s)
 * @returns Promise resolving to results
 */
function callWithAsyncErrorHandling<T extends any[], R>(
  fn: Function | Function[],
  instance: ComponentInternalInstance | null,
  type: ErrorTypes,
  args?: T
): Promise<R[]>;

Usage Examples:

import { 
  defineComponent, 
  handleError, 
  callWithErrorHandling, 
  callWithAsyncErrorHandling,
  ErrorCodes 
} from "@vue/runtime-core";

// Basic error handling
const SafeComponent = defineComponent({
  setup() {
    const riskyOperation = () => {
      try {
        // Some operation that might throw
        JSON.parse('invalid json');
      } catch (error) {
        handleError(error, getCurrentInstance(), ErrorCodes.SETUP_FUNCTION);
      }
    };
    
    // Safe function call with error handling
    const safeFunctionCall = (userFunction: Function) => {
      const result = callWithErrorHandling(
        userFunction,
        getCurrentInstance(),
        ErrorCodes.COMPONENT_EVENT_HANDLER
      );
      
      console.log('Function result:', result);
    };
    
    return {
      riskyOperation,
      safeFunctionCall
    };
  }
});

// Async error handling
const AsyncErrorComponent = defineComponent({
  setup() {
    const handleAsyncOperations = async () => {
      const asyncFunctions = [
        async () => { 
          await fetch('/api/data1'); 
          return 'data1';
        },
        async () => { 
          await fetch('/api/data2'); 
          return 'data2';
        },
        async () => {
          throw new Error('Intentional error');
        }
      ];
      
      const results = await callWithAsyncErrorHandling(
        asyncFunctions,
        getCurrentInstance(),
        ErrorCodes.COMPONENT_EVENT_HANDLER
      );
      
      console.log('Async results:', results);
    };
    
    return {
      handleAsyncOperations
    };
  }
});

// Error handling in lifecycle hooks
const LifecycleErrorComponent = defineComponent({
  setup() {
    onMounted(() => {
      const initializeThirdPartyLib = () => {
        // Third-party library initialization that might fail
        window.ThirdPartyLib?.init({
          apiKey: 'invalid-key'
        });
      };
      
      callWithErrorHandling(
        initializeThirdPartyLib,
        getCurrentInstance(),
        ErrorCodes.COMPONENT_EVENT_HANDLER
      );
    });
    
    return {};
  }
});

Error Codes and Types

Categorize errors for better handling and debugging.

/**
 * Enumeration of error codes for different error types
 */
enum ErrorCodes {
  SETUP_FUNCTION = 'setup function',
  RENDER_FUNCTION = 'render function',
  WATCH_GETTER = 'watcher getter',
  WATCH_CALLBACK = 'watcher callback',
  WATCH_CLEANUP = 'watcher cleanup function',
  NATIVE_EVENT_HANDLER = 'native event handler',
  COMPONENT_EVENT_HANDLER = 'component event handler',
  VNODE_HOOK = 'vnode hook',
  DIRECTIVE_HOOK = 'directive hook',
  TRANSITION_HOOK = 'transition hook',
  APP_ERROR_HANDLER = 'app errorHandler',
  APP_WARN_HANDLER = 'app warnHandler',
  FUNCTION_REF = 'ref function',
  ASYNC_COMPONENT_LOADER = 'async component loader',
  SCHEDULER = 'scheduler flush'
}

type ErrorTypes = ErrorCodes | string;

Usage Examples:

// Custom error handling by type
const createErrorHandler = () => {
  const errorCounts = reactive<Record<string, number>>({});
  
  const customHandleError = (
    err: unknown, 
    instance: ComponentInternalInstance | null, 
    type: ErrorTypes
  ) => {
    // Track error frequency
    if (typeof type === 'string') {
      errorCounts[type] = (errorCounts[type] || 0) + 1;
    }
    
    // Different handling based on error type
    switch (type) {
      case ErrorCodes.RENDER_FUNCTION:
        console.error('Render error - component may be broken:', err);
        break;
        
      case ErrorCodes.ASYNC_COMPONENT_LOADER:
        console.warn('Async component failed to load:', err);
        break;
        
      case ErrorCodes.NATIVE_EVENT_HANDLER:
        console.error('Native event handler error:', err);
        break;
        
      default:
        console.error(`Error in ${type}:`, err);
    }
    
    // Use Vue's default error handling
    handleError(err, instance, type);
  };
  
  return {
    customHandleError,
    errorCounts: readonly(errorCounts)
  };
};

// Error boundary component
const ErrorBoundary = defineComponent({
  setup(_, { slots }) {
    const hasError = ref(false);
    const error = ref<Error | null>(null);
    
    onErrorCaptured((err, instance, info) => {
      hasError.value = true;
      error.value = err instanceof Error ? err : new Error(String(err));
      
      // Log error with context
      handleError(err, instance, `error boundary: ${info}`);
      
      // Prevent error from propagating
      return false;
    });
    
    const retry = () => {
      hasError.value = false;
      error.value = null;
    };
    
    return () => {
      if (hasError.value) {
        return h('div', { class: 'error-boundary' }, [
          h('h3', 'Something went wrong'),
          h('p', error.value?.message || 'Unknown error'),
          h('button', { onClick: retry }, 'Retry')
        ]);
      }
      
      return slots.default?.();
    };
  }
});

Development Tools Integration

Warning and development utilities for debugging.

/**
 * Development warning utility (only in development mode)
 * @param msg - Warning message
 * @param args - Additional arguments to log
 */
declare const warn: (msg: string, ...args: any[]) => void;

/**
 * Assert that a value is a number (development only)
 * @param val - Value to check
 * @param type - Context type for error message
 */
function assertNumber(val: unknown, type: string): void;

Usage Examples:

import { warn, assertNumber } from "@vue/runtime-core";

const ValidationComponent = defineComponent({
  props: {
    count: [Number, String],
    timeout: Number
  },
  
  setup(props) {
    // Development warnings
    if (__DEV__) {
      if (typeof props.count === 'string') {
        warn('count prop should be a number, received string:', props.count);
      }
      
      // Assert number type
      if (props.timeout !== undefined) {
        assertNumber(props.timeout, 'timeout prop');
      }
    }
    
    const processCount = () => {
      const numericCount = typeof props.count === 'string' 
        ? parseInt(props.count, 10) 
        : props.count || 0;
        
      if (__DEV__ && isNaN(numericCount)) {
        warn('Invalid count value, defaulting to 0');
      }
      
      return isNaN(numericCount) ? 0 : numericCount;
    };
    
    return {
      processCount
    };
  }
});

// Custom validation with warnings
const useValidation = () => {
  const validateProps = (props: Record<string, any>, schema: Record<string, any>) => {
    for (const [key, validator] of Object.entries(schema)) {
      const value = props[key];
      
      if (validator.required && (value === undefined || value === null)) {
        if (__DEV__) {
          warn(`Required prop "${key}" is missing`);
        }
        continue;
      }
      
      if (value !== undefined && validator.type && typeof value !== validator.type) {
        if (__DEV__) {
          warn(`Prop "${key}" expected ${validator.type}, got ${typeof value}`);
        }
      }
      
      if (validator.validator && !validator.validator(value)) {
        if (__DEV__) {
          warn(`Prop "${key}" failed custom validation`);
        }
      }
    }
  };
  
  return { validateProps };
};

Advanced Error Handling Patterns

// Global error handler setup
const setupGlobalErrorHandling = (app: App) => {
  app.config.errorHandler = (err, instance, info) => {
    // Custom global error handling
    console.error('Global error:', err);
    console.log('Component:', instance);
    console.log('Error info:', info);
    
    // Send to error reporting service
    sendErrorToService(err, {
      component: instance?.type?.name || 'Unknown',
      info,
      stack: err instanceof Error ? err.stack : undefined
    });
    
    // Use Vue's error handling
    handleError(err, instance, `global handler: ${info}`);
  };
  
  app.config.warnHandler = (msg, instance, trace) => {
    console.warn('Vue warning:', msg);
    if (instance) {
      console.log('Component:', instance.type?.name);
    }
    console.log('Trace:', trace);
  };
};

// Error recovery utilities
const useErrorRecovery = () => {
  const retryCount = ref(0);
  const maxRetries = 3;
  
  const withRetry = async <T>(
    operation: () => Promise<T>,
    errorType: ErrorTypes = ErrorCodes.COMPONENT_EVENT_HANDLER
  ): Promise<T | null> => {
    try {
      const result = await callWithAsyncErrorHandling(
        [operation],
        getCurrentInstance(),
        errorType
      );
      
      retryCount.value = 0; // Reset on success
      return result[0];
      
    } catch (error) {
      retryCount.value++;
      
      if (retryCount.value < maxRetries) {
        console.log(`Retrying operation (${retryCount.value}/${maxRetries})`);
        return withRetry(operation, errorType);
      }
      
      console.error('Max retries exceeded');
      return null;
    }
  };
  
  return {
    withRetry,
    retryCount: readonly(retryCount)
  };
};

// Circuit breaker pattern
class CircuitBreaker {
  private failures = 0;
  private lastFailureTime = 0;
  private state: 'closed' | 'open' | 'half-open' = 'closed';
  
  constructor(
    private failureThreshold = 5,
    private recoveryTimeout = 30000
  ) {}
  
  async execute<T>(
    operation: () => Promise<T>,
    fallback?: () => T
  ): Promise<T> {
    if (this.state === 'open') {
      if (Date.now() - this.lastFailureTime > this.recoveryTimeout) {
        this.state = 'half-open';
      } else {
        if (fallback) return fallback();
        throw new Error('Circuit breaker is open');
      }
    }
    
    try {
      const result = await callWithAsyncErrorHandling(
        [operation],
        null,
        ErrorCodes.COMPONENT_EVENT_HANDLER
      );
      
      // Success - reset circuit breaker
      if (this.state === 'half-open') {
        this.state = 'closed';
        this.failures = 0;
      }
      
      return result[0];
      
    } catch (error) {
      this.failures++;
      this.lastFailureTime = Date.now();
      
      if (this.failures >= this.failureThreshold) {
        this.state = 'open';
      }
      
      if (fallback) return fallback();
      throw error;
    }
  }
}

Types

enum ErrorCodes {
  SETUP_FUNCTION = 'setup function',
  RENDER_FUNCTION = 'render function',
  WATCH_GETTER = 'watcher getter',
  WATCH_CALLBACK = 'watcher callback',
  WATCH_CLEANUP = 'watcher cleanup function',
  NATIVE_EVENT_HANDLER = 'native event handler',
  COMPONENT_EVENT_HANDLER = 'component event handler',
  VNODE_HOOK = 'vnode hook',
  DIRECTIVE_HOOK = 'directive hook',
  TRANSITION_HOOK = 'transition hook',
  APP_ERROR_HANDLER = 'app errorHandler',
  APP_WARN_HANDLER = 'app warnHandler',
  FUNCTION_REF = 'ref function',
  ASYNC_COMPONENT_LOADER = 'async component loader',
  SCHEDULER = 'scheduler flush'
}

type ErrorTypes = ErrorCodes | string;

interface ErrorHandler {
  (err: unknown, instance: ComponentInternalInstance | null, info: string): void;
}

interface WarnHandler {
  (msg: string, instance: ComponentInternalInstance | null, trace: string): void;
}

Best Practices

Error Handling Strategy

  1. Graceful Degradation: Always provide fallbacks for failed operations
  2. Error Boundaries: Use onErrorCaptured to contain errors within components
  3. Contextual Logging: Include component and operation context in error reports
  4. User-Friendly Messages: Don't expose technical errors directly to users

Development vs Production

// Development-only error handling
if (__DEV__) {
  warn('This is a development warning');
  assertNumber(value, 'prop name');
}

// Production error handling
const handleProductionError = (error: unknown) => {
  // Log to service, show user-friendly message
  console.error('An error occurred');
  // Don't expose internal details
};

Error Recovery Patterns

  1. Retry Logic: Implement retry mechanisms for transient failures
  2. Circuit Breakers: Prevent cascading failures in distributed systems
  3. Fallback Content: Always have backup content for failed async operations
  4. Error Boundaries: Isolate errors to prevent full application crashes

Install with Tessl CLI

npx tessl i tessl/npm-vue--runtime-core

docs

asset-resolution.md

builtin-components.md

components.md

composition-helpers.md

dependency-injection.md

error-handling.md

hydration.md

index.md

internal-render-helpers.md

lifecycle.md

reactivity.md

scheduler-timing.md

ssr-context.md

vdom-rendering.md

watch-effects.md

tile.json