Skip to main content

RouteConfig

The RouteConfig interface defines how Scully processes routes with dynamic parameters. Each route in your Angular application that contains dynamic segments needs a configuration to tell Scully how to generate all possible route variants.

Interface Definition

interface RouteConfig {
  [route: string]: RoutesTypes;
}

type RoutesTypes = 
  | RouteTypeJson 
  | RouteTypeContentFolder 
  | RouterTypeDefault 
  | RouteTypeUnknown;

Route Types

Scully supports several route types, each designed for different use cases.

RouteTypes Enum

enum RouteTypes {
  json = 'json',
  contentFolder = 'contentFolder',
  default = 'default'
}

Default Route Type

For routes without dynamic parameters or with custom handling.

Interface

interface RouterTypeDefault {
  type: RouteTypes.default;
  postRenderers?: (string | symbol)[];
}

Example

{
  routes: {
    '/about': {
      type: 'default'
    },
    '/contact': {
      type: 'default',
      postRenderers: ['customRenderer']
    }
  }
}

JSON Route Type

For routes that get their dynamic data from an API endpoint.

Interface

type RouteTypeJson = {
  type: RouteTypes.json;
  postRenderers?: (string | symbol)[];
} & {
  [paramName: string]: {
    url: string;
    property: string;
    headers?: HeadersObject;
    resultsHandler?: (raw: any) => any[];
    agent?: any;
  };
};

interface HeadersObject {
  expectedContentType?: string;
  [headerName: string]: string;
}

Properties

  • url: API endpoint URL to fetch data from. Can use template variables like ${userId}
  • property: Property name in the response that contains the parameter value
  • headers: Optional HTTP headers for the request
  • resultsHandler: Optional function to transform the API response
  • agent: Optional custom HTTP agent

Example: Single Parameter

{
  routes: {
    '/user/:userId': {
      type: 'json',
      userId: {
        url: 'https://api.example.com/users',
        property: 'id'
      }
    }
  }
}

Example: Multiple Parameters

{
  routes: {
    '/user/:userId/post/:postId': {
      type: 'json',
      userId: {
        url: 'https://api.example.com/users',
        property: 'id',
        resultsHandler: (raw) => raw.filter(user => user.active)
      },
      postId: {
        url: 'https://api.example.com/posts?userId=${userId}',
        property: 'id'
      }
    }
  }
}

Example: With Custom Headers

{
  routes: {
    '/product/:id': {
      type: 'json',
      id: {
        url: 'https://api.example.com/products',
        property: 'id',
        headers: {
          'Authorization': 'Bearer token123',
          'expectedContentType': 'application/json'
        }
      }
    }
  }
}

Content Folder Route Type

For routes that generate pages from markdown or other content files.

Interface

type RouteTypeContentFolder = {
  postRenderers?: (string | symbol)[];
  type: RouteTypes.contentFolder;
} & {
  [paramName: string]: {
    folder: string;
  };
};

Properties

  • folder: Path to the folder containing content files

Example: Blog Posts

{
  routes: {
    '/blog/:slug': {
      type: 'contentFolder',
      slug: {
        folder: './blog'
      }
    }
  }
}

Example: Multiple Content Folders

{
  routes: {
    '/docs/:category/:page': {
      type: 'contentFolder',
      page: {
        folder: './docs'
      }
    }
  }
}

Example: With Post Renderers

{
  routes: {
    '/blog/:slug': {
      type: 'contentFolder',
      postRenderers: ['toc', 'highlightCode'],
      slug: {
        folder: './blog'
      }
    }
  }
}

Unknown Route Type

For custom route plugins.

Interface

type RouteTypeUnknown = {
  postRenderers?: (string | symbol)[];
  type: string;
} & {
  [paramName: string]: any;
};

Example

{
  routes: {
    '/custom/:id': {
      type: 'myCustomPlugin',
      postRenderers: ['seoOptimizer'],
      customOption: 'value'
    }
  }
}

Post Renderers

All route types support post renderers, which are plugins that process the HTML after it has been rendered.
{
  routes: {
    '/blog/:slug': {
      type: 'contentFolder',
      postRenderers: [
        'seoHrefOptimise',
        'tocPlugin',
        'addMetaTags'
      ],
      slug: {
        folder: './blog'
      }
    }
  }
}

Complete Example

import { ScullyConfig, RouteTypes } from '@scullyio/scully';

export const config: ScullyConfig = {
  projectName: 'my-site',
  routes: {
    // Static route
    '/home': {
      type: RouteTypes.default
    },
    
    // Blog from content folder
    '/blog/:slug': {
      type: RouteTypes.contentFolder,
      postRenderers: ['toc', 'highlightCode'],
      slug: {
        folder: './content/blog'
      }
    },
    
    // User profiles from API
    '/user/:id': {
      type: RouteTypes.json,
      id: {
        url: 'https://api.example.com/users',
        property: 'id',
        resultsHandler: (users) => users.filter(u => u.published),
        headers: {
          'Authorization': 'Bearer token123'
        }
      }
    },
    
    // Nested dynamic routes
    '/category/:category/product/:productId': {
      type: RouteTypes.json,
      category: {
        url: 'https://api.example.com/categories',
        property: 'slug'
      },
      productId: {
        url: 'https://api.example.com/products?category=${category}',
        property: 'id'
      }
    }
  }
};

Important Notes

Routes with dynamic parameters that have no configuration will be logged and skipped during processing. This means no static files will be generated for unconfigured dynamic routes.
When using multiple parameters in a route, parameters can reference each other using template syntax: ${paramName}

Unhandled vs Handled Routes

Scully categorizes routes into two types:
  1. Unhandled Routes: Routes without dynamic parameters or routes that don’t need special processing
  2. Handled Routes: Routes with dynamic parameters that require a route configuration
All handled routes must have a corresponding configuration in the routes object, otherwise they will not be rendered.

Build docs developers (and LLMs) love