The Static Adapter
The preview on the right is this app running live on marko-run’s dev
server — two pages and a layout, clickable right now. But a dev server
isn’t a deployment. Static site generation turns the app into plain
.html files at build time, so you can host it on any static server or
CDN with nothing running behind it.
That switch is the job of an adapter. marko-run’s Vite plugin builds
the same routes for different targets depending on which adapter is
installed, and @marko/run-adapter-static is the one that renders to
files. This project’s vite.config.ts already has it wired in:
import staticAdapter from "@marko/run-adapter-static";
export default defineConfig({ plugins: [marko({ adapter: staticAdapter() })],});At build time the adapter renders every route it can reach — each route
with no :params, plus any page it finds by following relative <a href>
links in the HTML it just rendered. That’s why the layout links Home
and Counter: the crawler follows those links to discover the pages.
Build it — in the terminal. The preview on the right is a running dev
server, and you never build over a running server’s files, so send the
build to a folder of its own with --output:
pnpm run build --output dist-staticYou get a per-route size table. Both routes read 0 kB — this site is pure HTML so far, and pure HTML ships no JavaScript. See what landed on disk:
ls dist-static/publicindex.html (home) and counter.html (counter), ready to deploy. Open
one:
cat dist-static/public/index.htmlPlain HTML — no <script>, nothing to hydrate. This page is done the
moment the browser receives it.
Now make the counter actually count. Right now counter/+page.marko
prints a hard-coded 0. Give it real state — a <let> and a button that
increments it, the same reactivity you built in Part 2:
<let/count=0><button onClick() { count++ }> Clicked ${count} times</button>The preview updates instantly — the counter clicks now. Then rebuild:
pnpm run build --output dist-staticWatch the table. / still reads 0 kB — the home page didn’t change,
so it still ships nothing. But /counter now shows a couple of kB: the
moment a page needs to do something in the browser, marko-run bundles
that page’s code — and only that page’s — and ships it. Confirm it in the
HTML:
cat dist-static/public/counter.htmlThere’s a <script> now, pulling a file out of dist-static/public/assets/:
the counter’s code. The home page’s HTML is untouched.
That is a complete static site: two pages, one interactive, built to files you can host anywhere with no server — where the interactive page costs only its own counter and the static page costs nothing at all.
- Installing dependencies
- Starting dev server