Production Build
The AFW plugin compiles components and discovers routes. esdev processes the HTML entry, bundles JavaScript, compiles CSS and writes the configured output.
For a browser app, install the runtime and build plugin if they are not already listed in your project dependencies:
pnpm add @opentf/afw pnpm add -D @opentf/esdev-plugin-afw
{ "plugins": [{ "module": "@opentf/esdev-plugin-afw", "options": { "mode": "spa" } }], "build": { "targets": { "web": { "entry": "index.html", "outdir": "dist", "assets": ["public"] } } } }
Your index.html includes the app root and its module entry:
<div id="app"></div> <script type="module" src="./entry.js"></script>
import { mountApp } from "@opentf/afw"; import { pages, guard } from "@afw/routes"; mountApp({ pages, guard, target: document.getElementById("app") });
esdev build --minify esdev preview --spa
Output
dist/ contains the processed HTML, JavaScript assets, compiled stylesheets and configured public files. The route map uses dynamic imports; esdev owns chunking and final asset names. See the official project build configuration.
esdev preview serves the output as a static host does: a missing path is a 404, with dist/404.html when present. A single-page app passes --spa so route-like paths get index.html; configure your host the same way so client routes resolve. See Preview.
Static rendering and docs output
Static generation requires a project prerender script; it is not a build flag. See Static Generation. That script reads site.url from afw.config.js for canonical URLs, sitemap and feeds.
For search, feeds and LLM files, configure the release output plugin as described in Static Generation.