Prerenderer

repository·dev·Indexed 42 days ago

https://github.com/tofandel/prerenderer

A framework-agnostic tool for prerendering Single Page Applications (SPAs) into static HTML files to improve SEO and performance. It provides plugins for Vite, Rollup, and Webpack 5, and supports multiple rendering engines including @prerenderer/renderer-puppeteer for high fidelity and @prerenderer/renderer-jsdom for high-volume sites.

Tokens
12.3K
Snippets
36
Records
51
Agent score
51%

What's inside Prerenderer

  1. What is Prerendering?

    dev

    Prerendering is a technique to gain the benefits of Server-Side Rendering (SSR) without the complexity. It works by launching a headless browser, loading your application's routes, and saving the resulting state as static HTML files. These files can then be served by any static file server.

    When to use Prerendering:

    • When you want fast, static delivery of SPA routes.
    • When you want to avoid the implementation overhead of full SSR.

    When to avoid Prerendering:

    • High route volume: If you have thousands of routes, the build process will be slow.
    • Highly dynamic content: If content is user-specific, ensure you use placeholder components that load on the client-side to avoid showing incorrect static data.
  2. Install @prerenderer/rollup-plugin

    dev

    Install the Rollup plugin along with a renderer. You can choose between puppeteer for a full browser environment or jsdom for a lighter, simulated DOM environment.

    Note: Yarn 1 is known to have issues resolving dependencies; it is recommended to use npm or an up-to-date version of yarn.

    # For Puppeteer renderer
    npm i -D @prerenderer/rollup-plugin @prerenderer/renderer-puppeteer puppeteer
    
    # For JSDOM renderer
    npm i -D @prerenderer/rollup-plugin @prerenderer/renderer-jsdom
  3. Install @prerenderer/webpack-plugin

    dev

    To use the webpack plugin, you must install it along with one of the supported renderers. This plugin requires webpack 5 and HtmlWebpackPlugin to be present in your project as it hooks into the latter.

    # For Puppeteer renderer
    npm i -D @prerenderer/webpack-plugin @prerenderer/renderer-puppeteer
    
    # OR for JSDOM renderer
    npm i -D @prerenderer/webpack-plugin @prerenderer/renderer-jsdom
  4. Install Prerenderer packages

    dev

    Prerenderer is a monorepo consisting of several packages. You must install the core package along with a renderer and a build system plugin (like Rollup or Webpack) to use it.

    For a setup using Rollup or Vite with the Puppeteer renderer, install the following:

    npm install --save-dev @prerenderer/rollup-plugin @prerenderer/renderer-puppeteer puppeteer

    Important: If your package manager does not automatically install peer dependencies, you must manually install puppeteer to ensure the necessary browser binaries are available:

    npm install --save-dev puppeteer
  5. Trigger custom render events in your application

    dev

    If you use the renderAfterDocumentEvent option in your prerenderer configuration, you must manually dispatch that event within your application code to signal that the page is ready to be prerendered. For example, in a Vue application, you might do this inside the onMounted lifecycle hook.

    document.dispatchEvent(new Event('custom-render-trigger'))
  6. Configure rendererOptions for Puppeteer/JSDOM

    dev

    The rendererOptions object allows fine-grained control over the rendering lifecycle and the browser environment. Key options include:

    • maxConcurrentRoutes: Limits the number of routes rendered in parallel (defaults to 0/no limit).
    • renderAfterDocumentEvent: Waits for a specific custom DOM event to be dispatched.
    • renderAfterElementExists: Waits until a specific element is detected via document.querySelector.
    • renderAfterTime: Waits for a specified number of milliseconds (not recommended).
    • timeout: Cancels the render if it takes longer than this many milliseconds.
    • inject: An object containing values to be attached to the window object.
    • injectProperty: The name of the property on window where inject data is stored (defaults to '__PRERENDER_INJECTED').
    • headless: (Puppeteer only) Boolean to show/hide the browser window.
    rendererOptions: {
      maxConcurrentRoutes: 4,
      renderAfterElementExists: 'my-app-element',
      renderAfterDocumentEvent: 'custom-render-trigger',
      timeout: 20000,
      inject: {
        foo: 'bar'
      },
      headless: false
    }
  7. Configure PrerendererWebpackPlugin options

    dev

    The PrerendererWebpackPlugin constructor accepts an options object to control the prerendering process.

    Core Options

    • routes (Required): An array of strings representing the routes to prerender.
    • indexPath (Optional): The location of your index.html file.
    • renderer (Optional): The string name of the renderer to use (e.g., '@prerenderer/renderer-puppeteer').
    • postProcess (Optional): A function to modify the rendered HTML or output path before it is written to disk. It receives a renderedRoute object.
    • server (Optional): Configuration for the local server used during prerendering. Includes port (defaults to autodetected).
    • rendererOptions (Optional): An object passed directly to the renderer class's constructor.
  8. Configure @prerenderer/webpack-plugin or @prerenderer/rollup-plugin

    dev

    Both the Webpack and Rollup plugins share the same API to facilitate easy migration.

    Note: The @prerenderer/webpack-plugin requires HtmlWebpackPlugin to be configured, as it hooks into it to serve your HTML.

    OptionTypeDefaultDescription
    routesArray<string>['/']List of routes to prerender.
    fallbackBooleanfalseIf true, existing output HTML files are re-emitted as {original_name}_fallback.html.
    rendererstring or instance'@prerenderer/renderer-puppeteer'The renderer instance or name to require.
    rendererOptionsObjectNoneOptions passed to the renderer.
    postProcess(renderedRoute: Route) => voidNoneCustomize HTML and output path before writing.
    urlModifier(url: string) => stringNoneHook to modify the URL used to retrieve compiled assets.
    entryPathStringindexPathThe entry HTML file to use.
    ...Inherits all Prerenderer Options.
  9. Configure Prerenderer Server options

    dev

    The server option allows you to configure the internal Express server used to host your application during the prerendering process.

    OptionTypeRequired?DefaultDescription
    portIntegerNoFirst free port after 8000The port for the app server to run on.
    proxyObjectNoNo proxyingProxy configuration (matches webpack-dev-server signature).
    hostStringNo127.0.0.1The host to send requests to. Use with caution; changing this may result in external URLs being rendered. Use postProcess to change URLs in the resulting HTML instead.
    listenHostStringNo127.0.0.1The IP address the server will listen to. (0.0.0.0 allows external access).
    beforeFunctionNoNo operationDeprecated: Use hookServer() instead to add custom middleware.
  10. Configure @prerenderer/renderer-puppeteer options

    dev

    The Puppeteer renderer uses a real browser. It defaults to rendering when DOMContentLoaded fires.

    OptionTypeDefaultDescription
    maxConcurrentRoutesNumber0 (No limit)Limits simultaneous renders.
    injectObjectNoneObject to inject into the global scope.
    injectPropertyString__PRERENDER_INJECTEDProperty name for inject on window.
    renderAfterDocumentEventStringDOMContentLoadedWait for a specific document event.
    renderAfterTimeInteger (ms)NoneWait for a specific duration.
    renderAfterElementExistsString (Selector)NoneWait for an element to appear via document.querySelector.
    elementVisibleBooleanNoneIf true, waits until renderAfterElementExists is visible.
    elementHiddenBooleanNoneIf true, waits until renderAfterElementExists is hidden.
    timeoutInteger (ms)30000Aborts rendering if this limit is reached.
    skipThirdPartyRequestsBooleanfalseBlocks third-party requests to speed up rendering.
    headlessBooleantrueWhether to run the browser in headless mode.
    consoleHandlerfunctionNoneCustom handler for console.* calls. Receives (route, message).
    viewportViewportNonePassed to puppeteer.launch().
    launchOptionsLaunchOptionsNonePassed to puppeteer.launch().
    navigationOptionsWaitForOptionsNonePassed to page.goto().
  11. Configure @prerenderer/renderer-jsdom options

    dev

    The JSDOM renderer is a lightweight option. By default, it renders on the DOMContentLoaded event.

    OptionTypeDefaultDescription
    maxConcurrentRoutesNumber0 (No limit)Limits simultaneous renders to manage load.
    injectObjectNoneObject to inject into the global scope (must be JSON stringifiable).
    injectPropertyString__PRERENDER_INJECTEDThe property name where inject is mounted on window.
    renderAfterDocumentEventStringDOMContentLoadedWait for a specific document event (e.g., document.dispatchEvent(new Event('custom-render-trigger'))).
    renderAfterElementExistsString (Selector)NoneWait for an element to appear via document.querySelector.
    renderAfterTimeInteger (ms)NoneWait for a specific duration.
    timeoutInteger (ms)30000Aborts rendering if this limit is reached while waiting.
    JSDOMOptionsBaseOptions{ runScripts: 'dangerously', resources: 'usable', pretendToBeVisual: true }Additional options for JSDOM.fromUrl.
  12. Configure Prerenderer options

    dev

    When initializing a Prerenderer instance, you can provide several configuration options. Note that if you are using a plugin (Webpack or Rollup), staticDir is automatically inferred from the bundler configuration.

    Core Options

    OptionTypeRequired?DefaultDescription
    staticDirStringYesNoneThe root path to serve your app from.
    indexPathStringNostaticDir/index.htmlThe index file to fall back on for SPAs.
    serverObjectNoNoneApp server configuration options.
    rendererIRenderer Instance, constructor or StringNonew PuppeteerRenderer()The renderer to use. Defaults to @prerenderer/renderer-puppeteer.
    rendererOptionsObjectNoNoneOptions passed to the renderer if it was not provided as an instance.
    postProcess(renderedRoute: Route, routes: Route[]) => voidNoNoneCustomize HTML and output path before writing to file. You can also add routes by pushing to the routes parameter.
    // Example conceptual configuration
    const prerenderer = new Prerenderer({
      staticDir: './dist',
      renderer: 'puppeteer',
      rendererOptions: {
        headless: true
      }
    });