Skip to main content

Puppeteer Plugin

The Puppeteer plugin is the default rendering engine for Scully. It uses Puppeteer to launch a headless Chrome browser, navigate to your Angular application routes, and capture the rendered HTML for static generation.

Overview

Puppeteer is a Node library that provides a high-level API to control Chrome or Chromium browsers. Scully uses Puppeteer to:
  1. Launch a headless browser instance
  2. Navigate to each route in your Angular application
  3. Wait for the application to fully render
  4. Extract the HTML content
  5. Save it as a static file

Installation

The Puppeteer plugin comes bundled with Scully, but you need to install Puppeteer as a peer dependency:
npm install puppeteer
Or use the Scully plugin package directly:
npm install @scullyio/scully-plugin-puppeteer puppeteer

Configuration

The Puppeteer renderer is the default renderer in Scully. If you’ve installed it separately, import it in your Scully configuration:
// scully.<project-name>.config.ts
import '@scullyio/scully-plugin-puppeteer';
import { ScullyConfig } from '@scullyio/scully';

export const config: ScullyConfig = {
  projectRoot: './src',
  projectName: 'my-app',
  outDir: './dist/static',
  routes: {}
};

Usage

Once configured, use Scully normally:
# Build your Angular application
npx ng build

# Run Scully
npx scully

Features

Automatic Route Discovery

Puppeteer automatically handles Angular routing and renders each discovered route:
export const config: ScullyConfig = {
  routes: {
    '/': { type: 'default' },
    '/about': { type: 'default' },
    '/blog/:slug': {
      type: 'contentFolder',
      slug: {
        folder: './blog'
      }
    }
  }
};

Manual Idle Check

For complex pages with dynamic content, you can manually control when Scully considers the page ready:
export const config: ScullyConfig = {
  routes: {
    '/dashboard': {
      type: 'default',
      manualIdleCheck: true
    }
  }
};
In your Angular component:
import { isScullyRunning } from '@scullyio/ng-lib';

export class DashboardComponent {
  ngAfterViewInit() {
    // Perform async operations
    this.loadData().then(() => {
      if (isScullyRunning()) {
        window['pageRenderReady']();
      }
    });
  }
}

Request Interception

Filter resources during rendering to improve performance:
export const config: ScullyConfig = {
  ignoreResourceTypes: ['image', 'stylesheet', 'font'],
  routes: {}
};
This prevents Puppeteer from loading specified resource types, speeding up the rendering process.

Bare Project Mode

For non-Angular projects or special cases:
export const config: ScullyConfig = {
  bareProject: true,
  routes: {
    '/': {
      type: 'default',
      manualIdleCheck: true
    }
  }
};
In bare project mode, Scully monitors network requests and waits for them to complete before considering the page ready.

Screenshot/Thumbnail Generation

Generate screenshots of your pages:
export const config: ScullyConfig = {
  thumbnails: true,
  outDir: './dist/static',
  routes: {}
};
Screenshots are saved as thumbnail.jpg in each route’s output directory.

Host URL Configuration

Specify a custom host URL for rendering:
export const config: ScullyConfig = {
  hostUrl: 'http://localhost:4200',
  // or
  hostName: 'localhost',
  appPort: 4200,
  routes: {}
};

SSL Support

Render pages over HTTPS:
npx scully --ssl

Advanced Features

Expose Data to Pages

Pass data from Scully to your Angular application:
export const config: ScullyConfig = {
  routes: {
    '/blog/:slug': {
      type: 'contentFolder',
      slug: { folder: './blog' },
      exposeToPage: {
        buildTime: new Date().toISOString()
      }
    }
  }
};
Access in Angular:
const exposedData = window['ScullyIO-exposed'];
console.log(exposedData.buildTime);

Inject Data into Pages

Inject data into the static HTML:
export const config: ScullyConfig = {
  inlineStateOnly: true,
  routes: {
    '/': {
      type: 'default',
      injectToPage: {
        version: '1.0.0'
      }
    }
  }
};
The injected data is available in window['ScullyIO-injected'].

Show Browser for Debugging

Debug rendering issues by viewing the browser:
npx scully --showBrowser
This launches a visible browser window and keeps pages open for 120 seconds after rendering.

Troubleshooting

Rendering Errors

If a page fails to render, Scully retries up to 3 times. Common issues:
  1. Timeout: Page takes too long to render
    • Solution: Use manualIdleCheck or increase timeout
  2. 404 Routes: Angular doesn’t provide the route
    • Solution: Verify the route exists in your Angular app
  3. Browser Crashes: Puppeteer instance dies
    • Solution: Check system resources, update Puppeteer

Empty Content

If rendered pages are empty:
  1. Ensure your Angular app emits the AngularReady event
  2. Check that @scullyio/ng-lib is installed and configured
  3. Verify routes are correctly defined

Performance Issues

To improve rendering performance:
  1. Use ignoreResourceTypes to skip unnecessary resources
  2. Disable images, fonts, and stylesheets if not needed for rendering
  3. Use bareProject mode for simpler applications

Interface

The render plugin interface:
(route: HandledRoute) => Promise<string>
The plugin is called for every route and returns the rendered HTML string. If it throws an error, Scully retries up to 3 times before skipping the route.

Repository

  • Package: @scullyio/scully-plugin-puppeteer
  • Repository: GitHub
  • Puppeteer Version: ^13.4.1+

See Also

Build docs developers (and LLMs) love