Skip to content

Guide 36 of 36

Verniz Sites production guide

Build, inspect, test and deploy complete static, hybrid and server products with TypeScript, packages, content and auditable graphs.

On this page

Verniz Sites turns one typed Zolo application into a portable static site, a hybrid product, or a standalone server. HTML is the default product. JavaScript is added only for islands, client entries, mounts, progressive navigation, offline support, or another capability the project explicitly enables.

The normal build does not require Node. TypeScript checking and emit use the embedded typescript-rs engine; bundling, splitting and minification use Rolldown/Oxc; npm and JSR packages are resolved by Aube behind Zolo's sealed package adapter.

Start a complete project

[project]
entry = "src/main.zolo"

[web]
output = "static"             # static | hybrid | server
out_dir = "dist"
public_dir = "public"
base = "/"
trailing_slash = "always"
minify = true
source_maps = "external"

[client]
target = "es2022"
typecheck = "strict"
split = true

Run the development server, build the production artifact, inspect why it was built, and preview exactly what will be deployed:

zolo dev
zolo build --web=static
zolo explain web /
zolo preview

Expected result: zolo dev keeps the last good program and updates the open page after a valid save; the build reports routes, HTML/CSS/JS/assets, budgets, rendered versus reused routes and total duration; dist/_zolo/web-manifest.json seals every published byte; preview validates that manifest before listening. A byte-identical second build reports an unchanged product and does not replace dist/.

Client JavaScript and TypeScript

External entries are relative to the .zolo file when they start with ./ or ../, and relative to the project root otherwise:

{client.entry("./client/about.ts")}
{client.entry("src/client/admin.ts")}

Small progressive enhancements can stay beside their markup:

<button id="count">Add</button>
<script client lang="ts">
  const button = document.querySelector<HTMLButtonElement>("#count")!
  button.onclick = () => button.dataset.clicked = "true"
</script>

Production always uses canonical TypeScript emit before the Rust bundler. Development keeps a fast incremental Program and bundle per entry, watches type imports too, and retains the previous client product after an error. Source maps and editor diagnostics point to authored .ts or the exact inline body in the .zolo file, never to a temporary projection.

The editor supports completion and auto-import, hover, definition, references, rename, diagnostics and formatting for external files and inline virtual documents. Oxlint and Oxfmt are separate opt-ins through zolo lint --client and zolo fmt --client; they are not hidden build steps.

npm and JSR without an authored node_modules

zolo add npm:[email protected]
zolo add jsr:@luca/[email protected]
zolo install
zolo audit packages --deny warnings
zolo explain packages

Expected result: zolo.toml records exact direct declarations and zolo.lock records exports, conditions, transitives, peers, integrity, license and provenance. A subsequent build reconstructs the sealed VFS offline and frozen; it neither installs nor runs lifecycle scripts. Lifecycle remains denied unless an exact package coordinate is approved. Audit and explain read the sealed graph without network access.

The TypeScript service consumes the same editor descriptor as the build, so package imports receive real types, public-subpath completion, hover and definition without creating node_modules in the project. Missing declaration, stale lock, private subpath and unavailable VFS produce different diagnostics; quick fixes prepare a command but never install implicitly.

Typed client/server boundary

verniz:routes, verniz:actions, verniz:env, verniz:assets and verniz:client are generated typed modules. client.mount receives Wire-safe props, an abort signal and deterministic cleanup. Actions expose typed codecs, cancellation, revalidation and separate domain, HTTP, offline and protocol errors. Any, closures, handles, filesystem resources and secret data cannot cross this boundary silently.

Content, assets and cost

Typed Markdown/JSON/TOML/YAML collections can generate route entries, safe HTML, feeds, sitemap and SEO metadata. Route-local provenance makes an edit to one document rebuild its page and only the shared indexes that depend on it. The scale gate covers 2,048 content pages.

public/ preserves stable authored URLs. assets.file emits content-addressed assets; images can receive verified dimensions, responsive AVIF/WebP candidates and zero-JavaScript placeholders; assets.font can produce an audited WOFF2 subset or fall back safely. CSS chunks, preload, SRI and route budgets are all derived from real graph edges.

Optional product layers

  • [web.navigation] adds link-graph-derived prefetch, a byte-limited cache and optional View Transitions. Every failure falls back to native navigation.
  • [web.pwa] adds install metadata without JavaScript. [web.pwa.offline] is a separate network-first cache with explicit routes and a mandatory byte budget.
  • [web.edge] emits a provider-neutral, import-free Wasm adapter for the sealed static response graph. Dynamic edge execution is not claimed.
  • [tasks.<name>] and [workspace.dependencies] define a deterministic task DAG. Web builds delegate incremental work to WebGraph; generic cached tasks require exact inputs and outputs. Vite, Vitest and tsdown remain explicit external escape hatches.

Removing any opt-in removes its runtime and artifacts on the next atomic build.

The release candidate is measured as a complete command, not a compiler microbenchmark. The current same-host comparison, its variance and the historic P10b optimization checkpoint are recorded in the Verniz release benchmark.

Runnable verification matrix

Run commands from the repository root unless a row says otherwise.

Capability Example and command Expected proof
Island SSR contract zolo run examples/features/36-web/04-island-counter.zolo --no-cache, then build it with --emit native and --emit llvm Two independent island states, compiled handlers and reactive regions; VM, Cranelift and LLVM output is byte-equivalent.
Partial form target zolo check examples/features/36-web/05-island-form.zolo Current bind:value and @action surfaces typecheck together; the file explicitly labels reactive-list reconciliation and refinement types as future language work.
Zero-JS static zolo build --web=static examples/features/36-web/19-static-site-build.zolo twice Two pages + 404 + manifest; second build unchanged/reused; JavaScript is 0 B.
Dynamic entries zolo build --web=static examples/features/36-web/20-static-dynamic-routes.zolo One concrete page per enumerated slug; invalid or duplicate params fail before publish.
Asset graph zolo dev examples/features/36-web/21-authored-assets.zolo, then static build Asset update reaches the browser in dev; production URL is hashed, dimensioned and manifest-owned.
Mounts/actions/Wire zolo build --web=static examples/features/36-web/22-client-mount-actions.zolo Typed mount chunk and action bridge are retained only by the owning route.
Content/SEO from examples/features/36-web/23-content-site, run zolo build --web=static twice Pages, feed and sitemap are deterministic; second build reuses every route.
Hybrid runtime from examples/features/36-web/24-hybrid-product, run zolo build --web=hybrid then zolo preview Static page plus sealed standalone runtime for server route/action/form.
Navigation from examples/features/36-web/25-navigation-site, run static build and preview Normal links remain valid; opt-in runtime and targets are visible in explain.
Inline TypeScript from examples/features/36-web/26-inline-typescript, run static build twice and zolo dev Canonical TS chunk/maps, incremental reuse and HMR from .zolo or imported .ts.
PWA/offline/edge from examples/features/36-web/27-pwa-edge, run static build, explain and preview Manifest, budgeted cache and import-free edge adapter validate; repeated build is byte-identical.
Workspace tasks from examples/features/36-web/28-task-workspace, run zolo task build --all --graph, then twice normally Four nodes/three edges; web routes are reused; repeated generator reports a cache hit.

Final product QA

A production build is not complete merely because rendering succeeds. For the canonical documentation dogfood, run the authored product auditor from apps/zolo-lang-verniz:

npm run test:qa
node tools/check-seo-product.mjs
pwsh -File tools/check-search-product.ps1

The first command walks every generated HTML document and the fallback. It checks internal links, heading and skip-target structure, accessible dialog names, inherited locale declarations, localized Portuguese surfaces and likely UTF-8 mojibake. The SEO and search commands independently cross-check the Route Graph, sitemap, alternates, redirects and localized index.

Complete the gate in a real browser at desktop and 390 px: keyboard-open and close the command palette, exercise the mobile menu, run both Playground and a Tutorial lesson, visit a long document and the 404 fallback, and confirm there is no horizontal overflow or console error. Record Lighthouse and a performance trace as evidence. The 2026-08-24 baseline is 100/100/100/100 for accessibility, best practices, SEO and agentic browsing on desktop and mobile, with 87 ms LCP, 1 ms TTFB and 0.00 CLS on the local static preview.

Honest limits

  • Static export rejects request-dependent routes unless they are explicitly placed in a hybrid/server product. There is no silent static-to-server fallback.
  • Author-authored package ranges/tags are intentionally unavailable; direct dependencies use exact versions. Microsoft tsgo still lacks the upstream static package-mapping API, so the native TypeScript path is typescript-rs.
  • Offline HTML is returned only after a network failure, never for an HTTP error or a query-bearing navigation. Dynamic code does not yet execute in the edge Wasm adapter.
  • Reactive list reconciliation and refinement-type forms remain separate language work. The Wire boundary, leak checks, mounts and actions themselves are implemented.

The normative architecture and phase-by-phase evidence are in specs/verniz-sites.html.

DOCS / FEEDBACK

Did this page leave a question?

Tell us where the explanation lost you. Documentation is part of the language experience.

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

enpt-br