Askr
Guides

Generate a Static Site

Use generate a static site with the current published Askr packages.

  • @askrjs/askr0.0.59

How to use generate a static site

Keep static routes in the shared registry and make the document, assets, and output directory explicit in ssg.config.ts.

  1. Import the published @askrjs/askr entrypoint.
  2. Keep generate a static site configuration next to the component, route, or server composition root that owns it.
  3. Handle pending, unavailable, cancellation, and failure states, then verify the production path.
export const staticConfig = {
  registry,
  outputDir: 'dist',
  document: renderDocument,
  assets: [{ from: resolve('public'), to: '.' }],
};

// package.json: "build": "askr ssg --config ./ssg.config.ts --output ./dist"

Goal and architecture

`createStaticGen({ routes, outputDir })` from `@askrjs/askr/ssg` walks your route table (or a `registry` built with `createRouteRegistry`) and writes fully rendered HTML per route, plus a `metadata.json` describing the run. Routes carrying real request-auth requirements are excluded from prerendering by default, since there's no request to authenticate against at build time — those stay runtime-only unless you explicitly override that.

Implementation

For parameterized paths like `/posts/{slug}`, supply an `entries()` function that returns one param map per page you want generated — `createStaticGen` expands the path template against each entry to produce concrete URLs. `dataOverrides` lets you feed deterministic seed data to resources during generation instead of hitting a live backend, and `assets` copies static files or directories alongside the generated HTML. `askr ssg --config <path> --output <dir> [--incremental]` runs the same generator from the CLI, with incremental mode using `invalidationKeys` and `changedRoutes` to skip unchanged pages.

Failure states

Check `result.failed` and each route's `RouteRenderResult.error` after `generate()` — a single route throwing during render doesn't stop the whole run, but it does mean that route's HTML wasn't written, and a naive script that only checks a zero exit code will miss it. Routes with `policies` (advanced runtime access checks) are excluded from prerendering by default for the same reason auth-gated routes are — don't fight this by forcing them in unless you're certain the policy is safe to evaluate without a real request.

Verification

Confirm `result.successful` matches `result.totalRoutes` and inspect `result.routes[].reason` — `unchanged`/`cache-hit` routes on an incremental run should genuinely be unchanged, not silently stale because an invalidation key wasn't wired up. Open a generated file directly (not through a dev server) and confirm it's real standalone HTML with no unresolved markers. If you're shipping incrementally, re-run with a deliberately changed key and confirm exactly the expected routes rebuild, not the entire set.