Static Generation
The compiler's SSG backend emits string renderers. A project prerender script composes routes and layouts into HTML without a server-side DOM.
Configure the build
Use the default AFW plugin with mode: "ssg" and add a second build target:
{ "plugins": [ { "module": "@opentf/esdev-plugin-afw", "options": { "mode": "ssg" } }, { "module": "@opentf/afw-cli/ssg", "export": "siteOutputPlugin", "options": { "target": "web", "prerenderTarget": "prerender" } } ], "build": { "targets": { "web": { "entry": "index.html", "outdir": "dist", "assets": ["public"] }, "prerender": { "entry": "ssg.js", "out": ".ssg/ssg.js", "then": "run" } } } }
Provide ssg.js: it imports helpers from @opentf/afw-cli/ssg, locates the staged site, discovers pages/loaders, and calls runPrerender. This repo's website/ssg.js is a working example. Install @opentf/afw-cli as a development dependency and provide the browser entry from Production Build. Call writePrerenderReport(outDir, result) with the runPrerender result so the finish plugin receives resolved site metadata. The script is required; the compiler plugin does not generate it. The output plugin requires esdev 0.16 or newer.
esdev build --minify esdev preview
The prerender step writes HTML into release staging, alongside the compiled assets, before esdev publishes the completed output. In development this repo skips that step when no release staging directory exists.
Routes and data
Static routes render with their layout chains. Dynamic routes need getStaticPaths. Page loaders run at build time; their data is included in the HTML and emitted as <path>/__data.json. The prerender script resolves route metadata for each <head>.
Hydration
The client hydrate backend adopts supported server markup and attaches bindings. Unsupported compiler shapes can fall back to client rendering with diagnostics. See Hydration.
Search and other generated files
After every build target and prerender step completes, siteOutputPlugin indexes opted-in docs/blog HTML into _search/, then generates feeds and LLM context. It uses esdev's release-only finish hook and writes into staged output before publication. Indexing failures preserve the previous deployment.
The finish hook is release-only. esdev can still execute a target marked then: "run" during development, so the prerender script must check for release staging and skip rendering when it is absent. A selected browser-only build skips output generation when its configured prerender target is absent.