Static Site Generation

Static Site Generation (SSG) renders application pages as static HTML files during the build. The files can be served without running JavaScript for the initial response.

Retend provides the retendSSG Vite plugin for this process.

Setup

The plugin is imported and added to the Vite configuration:

// vite.config.ts
import { defineConfig } from 'vite';
import { retend } from 'retend-web/plugins/vite';
import { retendSSG } from 'retend-server/plugin';

export default defineConfig({
  plugins: [
    retend(),
    retendSSG({
      pages: ['/', '/about', '/contact'],
      routerModulePath: './source/router.ts',
    }),
  ],
});

Configuration Options

OptionRequiredDefaultDescription
pagesYes—An array of URLs to generate static HTML for.
routerModulePathYes—Path to the module that exports createRouter.
rootSelectorNo'#app'CSS selector for the root element.

The Router Module

The module at routerModulePath exports a createRouter function that returns a Router instance:

// source/router.ts
import { Router, defineRoutes } from 'retend';
import { Home } from './pages/home';
import { About } from './pages/about';

const routes = defineRoutes(() => [
  { path: '/', component: Home },
  { path: '/about', component: About },
]);

export function createRouter() {
  return new Router({ routes });
}

Handling Dynamic Routes

The pages array lists every specific URL to generate. For dynamic routes like /users/:userId, each URL is enumerated:

retendSSG({
  pages: ['/', '/users/1', '/users/2', '/users/3'],
  routerModulePath: './source/router.ts',
});

If URLs come from a database or API, the array can be built dynamically in the Vite config:

const userIds = await fetchAllUserIds();

export default defineConfig({
  plugins: [
    retend(),
    retendSSG({
      pages: ['/', ...userIds.map((id) => `/users/${id}`)],
      routerModulePath: './source/router.ts',
    }),
  ],
});

How It Works

During vite build, the plugin:

  1. Reads the index.html shell.
  2. For each page in the pages array, creates a virtual browser environment.
  3. Renders the app by navigating the router to that page.
  4. Waits for all async data (via <Await> boundaries) to resolve.
  5. Serializes the rendered output into a static HTML file.
  6. Handles any redirects defined in the routes automatically.

The generated HTML files can be served by a static file host.

Redirects

If a route in the configuration has a redirect property, the plugin automatically generates:

  • An HTML file with a <meta http-equiv="refresh"> redirect.
  • A _redirects file entry (compatible with Netlify, Cloudflare Pages, etc.).