Ingest Ingest Composable Server/less IO Framework
GitHub

Reference Layer

ImportRouter

ImportRouter routes to dynamic import functions. It supports lazy loading, but it is also useful when build or deployment tooling needs explicit route import boundaries.

Class ReferenceMethods, Properties, Examples

On This Page

Structural Map

  1. 1. Properties
  2. 2. HTTP Method Routing
  3. 3. Event-Based Routing
  4. 4. Creating Actions from Imports
  5. 5. Using Other ImportRouters
  6. 6. Dynamic Import Functions
  7. 6.1. Basic Import Function
  8. 6.2. Conditional Import Function
  9. 6.3. Environment-Based Import Function
  10. 6.4. Feature Flag Import Function
  11. 6.5. Async Import Function
  12. 7. Tooling and Lazy Loading
  13. 7.1. Route Import Boundaries
  14. 7.2. Why use it
  15. 7.3. Build-Time Analysis
  16. 8. Error Handling
  17. 8.1. Import Failure Handling
  18. 8.2. Module Validation
  19. 8.3. Graceful Degradation
  20. 9. Integration with ActionRouter
  21. 9.1. Initialization
  22. 9.2. Mixed Routing Approaches
  23. 10. Best Practices
  24. 10.1. Strategic Import Boundaries
  25. 10.2. Performance Optimization
  26. 10.3. Error Resilience
  27. 10.4. Development vs Production
  28. 10.5. Type Safety
  29. 10.6. Bundle Analysis

ImportRouter routes to dynamic import functions. It supports lazy loading, but it is also useful when build or deployment tooling needs explicit route import boundaries. It solves both on-demand loading and tooling visibility for route modules in larger applications.

TypeScript
import ImportRouter from '@stackpress/ingest/plugin/ImportRouter';

const router = new ImportRouter(actionRouter, listen);

// Route to dynamic imports
router.get('/users/:id', () => import('./routes/user.js'));
router.post('/users', () => import('./routes/create-user.js'));

// Conditional imports
router.get('/admin/*', () => {
  if (isProduction) {
    return import('./routes/admin-prod.js');
  }
  return import('./routes/admin-dev.js');
});
  1. Properties
  2. HTTP Method Routing
  3. Event-Based Routing
  4. Creating Actions from Imports
  5. Using Other ImportRouters
  6. Dynamic Import Functions
  7. Code Splitting Benefits
  8. Error Handling
  9. Integration with ActionRouter
  10. Best Practices

1. Properties

The following properties are available when instantiating an ImportRouter.

PropertyTypeDescription
importsMap<string, Set<ImportRouterTaskItem<R, S, X>>>Map of event names to import function configurations (readonly)

2. HTTP Method Routing

The following examples show how to define import-based routes for different HTTP methods.

TypeScript
// GET routes with dynamic imports
router.get('/users', () => import('./routes/users/list.js'));
router.get('/users/:id', () => import('./routes/users/get.js'));

// POST routes
router.post('/users', () => import('./routes/users/create.js'));

// PUT routes
router.put('/users/:id', () => import('./routes/users/update.js'));

// DELETE routes
router.delete('/users/:id', () => import('./routes/users/delete.js'));

// PATCH routes
router.patch('/users/:id', () => import('./routes/users/patch.js'));

// OPTIONS routes
router.options('/users', () => import('./routes/users/options.js'));

// HEAD routes
router.head('/users', () => import('./routes/users/head.js'));

// CONNECT and TRACE are also available
router.connect('/proxy', () => import('./routes/proxy/connect.js'));
router.trace('/users', () => import('./routes/users/trace.js'));

// Handle any method
router.all('/health', () => import('./routes/health.js'));

Parameters

ParameterTypeDescription
pathstringRoute path with optional parameters (:id)
actionImportRouterAction<R, S, X>Function that returns a dynamic import
prioritynumberPriority level (default: 0). Can be negative. Higher numbers run first, then ties follow definition order.

Returns

The ImportRouter instance to allow method chaining.

3. Event-Based Routing

The following example shows how to route events to dynamic imports.

TypeScript
// Route custom events to imports
router.on('user-login', () => import('./handlers/user-login.js'));
router.on('data-updated', () => import('./handlers/data-updated.js'));

// Route with regex patterns
router.on(/^email-.+$/, () => import('./handlers/email-handler.js'));

Parameters

ParameterTypeDescription
event`string\RegExp`Event name or pattern
entryImportRouterAction<R, S, X>Function that returns a dynamic import
prioritynumberPriority level (default: 0). Can be negative. Higher numbers run first, then ties follow definition order.

Returns

The ImportRouter instance to allow method chaining.

4. Creating Actions from Imports

The following example shows how import functions are converted to executable actions.

TypeScript
// Internal method - creates action from import function
const action = router.action(
  'GET /users', 
  () => import('./routes/users.js'), 
  0
);

// The action executes the import and calls the default export
await action(request, response, context);

Parameters

ParameterTypeDescription
eventstringEvent name for tracking
actionImportRouterAction<R, S, X>Function that returns a dynamic import
prioritynumberPriority level (default: 0). Can be negative. Higher numbers run first, then ties follow definition order.

Returns

An async function that executes the import and calls the default export.

5. Using Other ImportRouters

The following example shows how to merge imports from another router.

TypeScript
const apiRouter = new ImportRouter(actionRouter, listen);
apiRouter.get('/api/users', () => import('./api/users.js'));

const mainRouter = new ImportRouter(actionRouter, listen);
mainRouter.use(apiRouter); // Merges import configurations

Parameters

ParameterTypeDescription
routerImportRouter<R, S, X>Another ImportRouter to merge imports from

Returns

The ImportRouter instance to allow method chaining.

6. Dynamic Import Functions

Import functions provide flexible module loading with conditional logic.

6.1. Basic Import Function

The following example shows a basic dynamic import function.

TypeScript
router.get('/users', () => import('./routes/users.js'));

// The imported module should export a default function
// ./routes/users.js
export default async function UsersIndex({ res }) {
  const users = await getUsers();
  res.setResults(users);
}

6.2. Conditional Import Function

The following example shows how to implement conditional imports based on runtime conditions.

TypeScript
router.get('/dashboard', () => {
  const userRole = getCurrentUserRole();
  
  if (userRole === 'admin') {
    return import('./routes/admin-dashboard.js');
  } else if (userRole === 'user') {
    return import('./routes/user-dashboard.js');
  } else {
    return import('./routes/guest-dashboard.js');
  }
});

6.3. Environment-Based Import Function

The following example shows how to use different imports based on environment.

TypeScript
router.get('/debug', () => {
  if (process.env.NODE_ENV === 'development') {
    return import('./routes/debug/full.js');
  } else {
    return import('./routes/debug/minimal.js');
  }
});

6.4. Feature Flag Import Function

The following example shows how to use feature flags to control imports.

TypeScript
router.get('/new-feature', () => {
  if (isFeatureEnabled('new-ui')) {
    return import('./routes/new-feature-v2.js');
  } else {
    return import('./routes/new-feature-v1.js');
  }
});

6.5. Async Import Function

The following example shows how to perform async operations before importing.

TypeScript
router.get('/dynamic', async () => {
  // Can perform async operations before importing
  const config = await loadConfiguration();
  
  if (config.useNewHandler) {
    return import('./routes/new-handler.js');
  } else {
    return import('./routes/old-handler.js');
  }
});

7. Tooling and Lazy Loading

ImportRouter enables lazy loading while also exposing import boundaries through router.imports.

7.1. Route Import Boundaries

The following examples show how ImportRouter makes route imports visible to builders and deployment scripts.

TypeScript
// Large admin panel is only loaded when needed
router.get('/admin/*', () => import('./routes/admin/index.js'));

// Heavy data processing is split into separate chunks
router.post('/process-data', () => import('./routes/data-processor.js'));

// Third-party integrations are loaded on demand
router.get('/integrations/:service', () => {
  const service = getServiceFromPath();
  return import(`./integrations/${service}.js`);
});

7.2. Why use it

ImportRouter is useful when you want:

  • lazy loading
  • route-aware build scripts
  • deployment packaging based on route modules
  • explicit import metadata through router.imports
  • On-Demand Loading: Route handlers are loaded only when accessed
  • Better Caching: Individual route chunks can be cached separately
  • Progressive Loading: Users only download code for features they use

7.3. Build-Time Analysis

The following example shows how bundlers can analyze import patterns for optimization.

TypeScript
// Bundlers can analyze import patterns for optimization
console.log(router.imports);
// Map {
//   'GET /users' => Set([{ 
//     import: () => import('./routes/users.js'), 
//     priority: 0 
//   }]),
//   'POST /users' => Set([{ 
//     import: () => import('./routes/create.js'), 
//     priority: 0 
//   }])
// }

8. Error Handling

ImportRouter provides robust error handling for dynamic imports.

8.1. Import Failure Handling

The following example shows how to handle import failures with fallback strategies.

TypeScript
router.get('/fallback-example', async () => {
  try {
    return await import('./routes/primary.js');
  } catch (error) {
    console.warn('Primary route failed, using fallback');
    return await import('./routes/fallback.js');
  }
});

8.2. Module Validation

The following example shows how to validate imported modules.

TypeScript
router.get('/validated', async () => {
  const module = await import('./routes/example.js');
  
  if (!module.default || typeof module.default !== 'function') {
    throw new Error('Invalid route module: missing default export');
  }
  
  return module;
});

8.3. Graceful Degradation

The following example shows how to implement graceful degradation when imports fail.

TypeScript
router.get('/optional-feature', () => {
  return import('./routes/optional.js').catch(() => {
    // Return a minimal handler if the feature module fails
    return {
      default: async (req, res, ctx) => {
        res.setError('Feature not available', {}, [], 503);
        return false;
      }
    };
  });
});

9. Integration with ActionRouter

ImportRouter works as an extension of ActionRouter, sharing the same event system and routing capabilities.

9.1. Initialization

The following example shows how ImportRouter integrates with ActionRouter.

TypeScript
import ActionRouter from '@stackpress/ingest/plugin/ActionRouter';

const actionRouter = new ActionRouter(context);

// ImportRouter is automatically available
actionRouter.import.get('/users', () => import('./routes/users.js'));

// Or create standalone
const importRouter = new ImportRouter(actionRouter, listen);

9.2. Mixed Routing Approaches

The following example shows how to combine different routing approaches.

TypeScript
// Combine different routing approaches
actionRouter.get('/immediate', immediateHandler);
actionRouter.entry.get('/file-based', './routes/file.js');
actionRouter.import.get('/lazy', () => import('./routes/lazy.js'));
actionRouter.view.get('/template', './views/template.hbs');

// All routes work together in the same system

10. Best Practices

The following guidelines help ensure effective use of ImportRouter in production applications.

10.1. Strategic Import Boundaries

The following examples show route boundaries that are useful for lazy loading, packaging, and deployment tooling.

TypeScript
// Split by feature boundaries
router.get('/auth/*', () => import('./features/auth/routes.js'));
router.get('/billing/*', () => import('./features/billing/routes.js'));
router.get('/analytics/*', () => import('./features/analytics/routes.js'));

// Split heavy dependencies
router.get('/pdf-export', () => import('./routes/pdf-export.js')); // Heavy PDF library
router.get('/image-process', () => import('./routes/image-process.js')); // Heavy image library

10.2. Performance Optimization

The following example shows how to preload critical routes for better performance.

TypeScript
// Preload critical routes
const criticalRoutes = [
  () => import('./routes/home.js'),
  () => import('./routes/login.js'),
  () => import('./routes/dashboard.js')
];

// Preload during idle time
if ('requestIdleCallback' in window) {
  requestIdleCallback(() => {
    criticalRoutes.forEach(importFn => importFn());
  });
}

10.3. Error Resilience

The following example shows how to implement retry logic for unstable imports.

TypeScript
// Implement retry logic
router.get('/retry-example', async () => {
  let attempts = 0;
  const maxAttempts = 3;
  
  while (attempts < maxAttempts) {
    try {
      return await import('./routes/unstable.js');
    } catch (error) {
      attempts++;
      if (attempts >= maxAttempts) {
        throw error;
      }
      // Wait before retry
      await new Promise(resolve => setTimeout(resolve, 1000 * attempts));
    }
  }
});

10.4. Development vs Production

The following example shows different strategies for different environments.

TypeScript
// Different strategies for different environments
const isDev = process.env.NODE_ENV === 'development';

router.get('/dev-tools', () => {
  if (isDev) {
    return import('./routes/dev-tools.js');
  } else {
    return Promise.resolve({
      default: (req, res, ctx) => {
        res.setError('Not available in production', {}, [], 404);
        return false;
      }
    });
  }
});

10.5. Type Safety

The following example shows how to implement type safety with ImportRouter.

TypeScript
// Type-safe import functions
interface RouteModule {
  default: (req: Request, res: Response, ctx: Context) => Promise<boolean>;
}

router.get('/typed', (): Promise<RouteModule> => {
  return import('./routes/typed.js');
});

10.6. Bundle Analysis

The following example shows how to track import patterns for optimization.

TypeScript
// Track import patterns for optimization
const importStats = new Map();

router.get('/tracked', () => {
  const route = './routes/tracked.js';
  importStats.set(route, (importStats.get(route) || 0) + 1);
  return import(route);
});

// Log popular routes for optimization
setInterval(() => {
  console.log('Import statistics:', importStats);
}, 60000);