or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

application.mdbase-classes.mdconfiguration.mdcontext.mdhttp-client.mdindex.mdloaders-errors.mdstartup.md
tile.json

loaders-errors.mddocs/

Loaders & Error Handling

Component loading system and error handling utilities for application bootstrapping, file loading, and exception management in Egg.js applications.

Capabilities

Application Loader Classes

Component loaders responsible for loading and initializing various application components during startup.

/**
 * Base application loader class
 */
class EggApplicationLoader {
  /** Load application components in correct order */
  load(): Promise<void>;
  
  /** Load configuration files */
  loadConfig(): Promise<void>;
  
  /** File loader utility */
  FileLoader: typeof FileLoader;
  
  /** All loaded plugins information */
  allPlugins: Record<string, any>;
  
  /** Application information */
  appInfo: EggAppInfo;
  
  /** Configuration metadata */
  configMeta: any;
  
  /** Plugin loading order */
  orderPlugins: string[];
}

/**
 * Application worker loader for loading app worker components
 */
class AppWorkerLoader extends EggApplicationLoader {
  /** Load controllers, services, middleware, etc. for app worker */
}

/**
 * Agent worker loader for loading agent worker components
 */
class AgentWorkerLoader extends EggApplicationLoader {
  /** Load components specific to agent worker */
}

Usage Examples:

// The loaders are used internally by Egg.js during application startup
// You typically don't use them directly, but can access their results

// In application ready callback
export default class AppBootHook {
  async didReady() {
    const { app } = this;
    
    // Access loader information
    console.log('Loaded plugins:', app.loader.orderPlugins);
    console.log('App info:', app.loader.appInfo);
    
    // Access loaded components through app
    console.log('Available controllers:', Object.keys(app.controller || {}));
    console.log('Available services:', Object.keys(app.service || {}));
  }
}

// Custom loader usage (advanced)
export default class CustomBootHook {
  async configWillLoad() {
    const { app } = this;
    
    // Access file loader for custom loading
    const customLoader = new app.loader.FileLoader({
      directory: path.join(app.baseDir, 'app/custom'),
      target: app.custom,
      inject: app
    });
    
    customLoader.load();
  }
}

Error Classes

Built-in error classes for handling specific error conditions in Egg.js applications.

/**
 * Error thrown when cookie size exceeds browser limits
 */
class CookieLimitExceedError extends Error {
  constructor(name: string, value: string);
  
  /** Cookie name that exceeded limit */
  name: string;
  
  /** Cookie value that caused the error */
  value: string;
}

/**
 * Error for unhandled promise rejections with additional context
 */
class MessageUnhandledRejectionError extends Error {
  constructor(message: string);
  
  /** Error message */
  message: string;
}

Usage Examples:

import { CookieLimitExceedError } from 'egg';

// Error handling in middleware
export default function errorHandler() {
  return async (ctx: Context, next: Next) => {
    try {
      await next();
    } catch (err) {
      if (err instanceof CookieLimitExceedError) {
        ctx.logger.warn('Cookie limit exceeded: %s = %s', err.name, err.value);
        ctx.status = 400;
        ctx.body = {
          error: 'Cookie too large',
          cookieName: err.name
        };
      } else {
        // Handle other errors
        ctx.status = err.status || 500;
        ctx.body = { error: err.message };
      }
    }
  };
}

// Listening for cookie limit events
export default class Application extends EggApplication {
  constructor(options) {
    super(options);
    
    // Built-in cookie limit handling
    this.on('cookieLimitExceed', ({ name, value, ctx }) => {
      const err = new CookieLimitExceedError(name, value);
      ctx.coreLogger.error(err);
      
      // Custom handling
      ctx.throw(400, 'Cookie size exceeds browser limits');
    });
  }
}

File Loading System

The underlying file loading system used by loaders to discover and load application components.

/**
 * File loader options for custom component loading
 */
interface FileLoaderOptions {
  /** Directory to load files from */
  directory: string | string[];
  
  /** Target object to assign loaded modules */
  target: any;
  
  /** Where to inject the target ('app' or 'ctx') */
  inject?: 'app' | 'ctx';
  
  /** File matching pattern */
  match?: string | string[] | RegExp;
  
  /** File ignore pattern */
  ignore?: string | string[];
  
  /** Loader function for processing files */
  initializer?: (obj: any, options: any) => any;
  
  /** Call loaded modules as functions */
  call?: boolean;
  
  /** Override existing properties */
  override?: boolean;
  
  /** Enable caseStyle conversion */
  caseStyle?: 'camel' | 'pascal' | 'lower' | 'upper';
  
  /** Custom loading filter */
  filter?: (obj: any) => boolean;
}

interface CustomLoaderConfig extends Omit<FileLoaderOptions, 'inject' | 'target'> {
  /** Injection target */
  inject?: 'ctx' | 'app';
  
  /** Load from plugins/framework */
  loadunit?: boolean;
}

Usage Examples:

// Custom loader configuration in config
config.customLoader = {
  // Load validators into app.validator
  validator: {
    directory: path.join(appInfo.baseDir, 'app/validator'),
    inject: 'app',
    caseStyle: 'camel',
    filter(validator) {
      return typeof validator === 'function';
    }
  },
  
  // Load utilities into ctx.util
  util: {
    directory: path.join(appInfo.baseDir, 'app/util'),
    inject: 'ctx',
    call: true // Call loaded modules as functions
  }
};

// Using custom loaded components
export default class UserController extends Controller {
  async create() {
    const { ctx, app } = this;
    const userData = ctx.request.body;
    
    // Use custom validator
    const errors = app.validator.user(userData);
    if (errors.length > 0) {
      ctx.throw(422, 'Validation failed', { errors });
    }
    
    // Use custom utility
    const hashedPassword = ctx.util.hashPassword(userData.password);
    
    const user = await ctx.service.user.create({
      ...userData,
      password: hashedPassword
    });
    
    ctx.body = { user };
  }
}

Loader Lifecycle

Understanding the component loading lifecycle and timing.

/**
 * Loader lifecycle hooks (used in app.js)
 */
interface LoaderLifecycle {
  /** Called before configuration loading */
  configWillLoad?(): void;
  
  /** Called after configuration loaded */
  configDidLoad?(): void;
  
  /** Called before all components ready */
  didLoad?(): void;
  
  /** Called when application is ready */
  willReady?(): void;
  
  /** Called after application ready */
  didReady?(): void;
  
  /** Called before server started */
  serverDidReady?(): void;
  
  /** Called before closing */
  beforeClose?(): void;
}

Usage Examples:

// app.js - Application lifecycle hooks
export default class AppBootHook {
  constructor(app) {
    this.app = app;
  }
  
  configWillLoad() {
    // Modify configuration before loading
    this.app.config.custom = { loaded: false };
  }
  
  async configDidLoad() {
    // Access final configuration
    console.log('Final config:', this.app.config.name);
  }
  
  async didLoad() {
    // All components loaded, can access services/controllers
    console.log('Available services:', Object.keys(this.app.service));
  }
  
  async willReady() {
    // Perform final setup before ready
    await this.app.redis.ping();
  }
  
  async didReady() {
    // Application is ready
    this.app.logger.info('Application started successfully');
  }
  
  async serverDidReady() {
    // HTTP server is ready
    const { server } = this.app;
    this.app.logger.info('Server listening on port %d', server.address().port);
  }
  
  async beforeClose() {
    // Cleanup before shutdown
    await this.app.mysql.end();
  }
}

Error Handling Patterns

Common error handling patterns and utilities.

/**
 * Application-level error handling
 */
interface EggApplicationCore {
  /** Emit error event */
  emit(event: 'error', err: Error, ctx?: Context): boolean;
  
  /** Add error event listener */
  on(event: 'error', listener: (err: Error, ctx?: Context) => void): this;
}

Usage Examples:

// Global error handler in app.js
export default class AppBootHook {
  constructor(app) {
    this.app = app;
    
    // Global error handling
    app.on('error', (err, ctx) => {
      // Log error with context
      if (ctx) {
        ctx.logger.error('Request error:', err);
        
        // Custom error reporting
        this.reportError(err, {
          url: ctx.url,
          method: ctx.method,
          userAgent: ctx.get('user-agent'),
          ip: ctx.ip
        });
      } else {
        app.logger.error('Application error:', err);
      }
    });
  }
  
  reportError(err, context) {
    // Send to error reporting service
    // Implementation depends on your error reporting solution
  }
}

// Error handling middleware
export default function onerror() {
  return async (ctx, next) => {
    try {
      await next();
    } catch (err) {
      // Set error properties
      err.status = err.status || 500;
      err.headers = err.headers || {};
      
      // Emit error event
      ctx.app.emit('error', err, ctx);
      
      // Response handling
      if (ctx.acceptJSON) {
        ctx.body = {
          error: err.message,
          status: err.status
        };
      } else {
        ctx.body = `<h1>${err.status} ${err.message}</h1>`;
      }
      
      ctx.status = err.status;
    }
  };
}

Types

interface EggAppInfo {
  /** Package.json content */
  pkg: any;
  
  /** Application name */
  name: string;
  
  /** Base directory */
  baseDir: string;
  
  /** Environment */
  env: EggEnvType;
  
  /** Scope name */
  scope: string;
  
  /** Home directory */
  HOME: string;
  
  /** Root directory */
  root: string;
}

interface FileLoader {
  /** Full file path symbol */
  FULLPATH: symbol;
  
  /** Load files from directory */
  load(): void;
}