Vite Prerender Plugin

0.5.13 · active · verified Tue Apr 21

vite-prerender-plugin is a Vite plugin designed to perform server-side rendering (prerendering) of web applications to static HTML during the build process. This is particularly useful for improving initial page load performance and SEO for sites that don't require full server-side rendering on every request. The current stable version is `0.5.13`, with minor updates released somewhat regularly to address bug fixes and ensure compatibility with newer Vite versions, currently supporting Vite 5.x through 8.x. A key differentiator of this plugin is its highly flexible approach, being an extraction of the prerendering functionality from the Preact ecosystem's `@preact/preset-vite` and WMR. It delegates the actual rendering logic to the user, who must provide an exported `prerender()` function within a specified script. This function can be synchronous or asynchronous, allowing for data fetching and file system access, and is expected to return an object containing an `html` property with the rendered string. The plugin then injects this HTML into the main document at a configurable `renderTarget` selector, and can automatically discover and prerender additional routes.

Common errors

Warnings

Install

Imports

Quickstart

Shows how to configure `vite-prerender-plugin` in `vite.config.ts`, define a `prerender.ts` script for generating HTML, and prerender basic and dynamically added routes. Includes a minimal `index.html` and client-side `main.ts` for context.

/* === 1. Install dependencies === */
// npm install vite vite-prerender-plugin

/* === 2. vite.config.ts === */
import { defineConfig } from 'vite';
import { vitePrerenderPlugin } from 'vite-prerender-plugin';
import { resolve } from 'path';

export default defineConfig({
  plugins: [
    vitePrerenderPlugin({
      renderTarget: '#app', // Query selector for where to insert prerender result
      prerenderScript: resolve(__dirname, './prerender.ts'), // Absolute path to your prerender script
      additionalPrerenderRoutes: ['/about', '/contact', '/404'], // Routes not automatically discovered
    }),
  ],
  build: {
    // Ensure build output is suitable for static hosting
    // For this example, no special SSR options are needed beyond the plugin.
  }
});

/* === 3. prerender.ts === */
// This script runs in a Node.js-like environment during the build process.
// You would typically use your framework's renderToString method here.

interface PrerenderResult { html: string; }

export async function prerender(url: string): Promise<PrerenderResult> {
  let content = '';
  switch (url) {
    case '/':
      content = '<h1>Home Page</h1><p>Welcome to the prerendered app!</p><a href="/about">About</a>';
      break;
    case '/about':
      content = '<h1>About Us</h1><p>Learn more about our mission.</p><a href="/">Home</a>';
      break;
    case '/contact':
      content = '<h1>Contact Us</h1><p>Get in touch with us.</p>';
      break;
    case '/404':
      content = '<h1>404 - Page Not Found</h1><p>The page you requested does not exist.</p>';
      break;
    default:
      content = '<h1>Dynamic Route</h1><p>This content was prerendered for: ' + url + '</p>';
      break;
  }
  // Simulate an app mounting into a div with id 'app'
  return { html: `<div id="app">${content}</div>` };
}

/* === 4. index.html === */
<!-- In your public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite Prerender Example</title>
</head>
<body>
    <div id="app"><!-- Prerendered content will be injected here --></div>
    <script type="module" src="/src/main.ts"></script>
</body>
</html>

/* === 5. src/main.ts (client-side entrypoint) === */
// import './style.css'; // Optional: Basic styling

const app = document.querySelector<HTMLDivElement>('#app');

// Only hydrate or render if the content is not already prerendered
if (app && !app.innerHTML) {
  app.innerHTML = `
    <h1>Client-side Hydration</h1>
    <p>This content is loaded dynamically if prerendering fails or for SPAs.</p>
    <button id="counter">count is 0</button>
  `;
  let count = 0;
  document.getElementById('counter')?.addEventListener('click', () => {
    count++;
    document.getElementById('counter')!.textContent = `count is ${count}`;
  });
}

view raw JSON →