Waku
Source:
src/Cloudflare/Website/Waku.ts
A Cloudflare Worker deployed from a Waku project.
Waku builds the project programmatically — no waku.config.ts edits,
no Wrangler configuration, and no build command required. The RSC server
bundle deploys as the Worker script and the client output (including
SSG-prerendered pages) deploys as static assets.
Requires the @distilled.cloud/waku package to be installed in your
project (alongside waku itself). Input files are content-hashed
(respecting .gitignore by default) so unchanged projects skip the
build and deploy entirely.
Waku’s server runtime uses AsyncLocalStorage, so the nodejs_als
compatibility flag is enabled automatically when your compatibility
flags include neither nodejs_als nor nodejs_compat. SSG pages are
served at their extensionless URLs (/about) via the default
drop-trailing-slash asset handling.
Deploying a Waku Site
Section titled “Deploying a Waku Site”A single call builds the project and deploys the RSC server bundle plus the client assets — no configuration required.
Waku site
const site = yield* Cloudflare.Website.Waku("Site");Waku project in a subdirectory
const site = yield* Cloudflare.Website.Waku("Site", { rootDir: "apps/web",});Bindings
Section titled “Bindings”Pass resources through env like any other Worker. Server components
and API routes read them from the cloudflare:workers env at request
time. Prefer a guarded dynamic import in page modules — Waku’s SSG step
renders static pages in Node, where a top-level
import { env } from "cloudflare:workers" cannot resolve.
const bucket = yield* Cloudflare.R2.Bucket("Uploads");
const site = yield* Cloudflare.Website.Waku("Site", { env: { UPLOADS: bucket, },});Custom Worker Entry
Section titled “Custom Worker Entry”By default the deployed Worker entry is Waku’s own RSC server entry.
When the Worker must export more than Waku’s fetch handler — Durable
Object classes, additional handlers — point main at your own module
that wraps Waku’s handler (imported from virtual:waku/server-entry)
and re-exports the extras.
// import wakuHandler from "virtual:waku/server-entry";// export class Counter extends DurableObject { ... }// export default { fetch: (req, env, ctx) => wakuHandler.fetch(req, env, ctx) };
const site = yield* Cloudflare.Website.Waku("Site", { main: "src/worker-entry.ts", env: { COUNTER: Cloudflare.DurableObject("Counter", { className: "Counter", }), },});Custom Rebuild Scope
Section titled “Custom Rebuild Scope”By default, every non-gitignored file is hashed to decide whether a
rebuild is needed. Use memo to narrow the scope when your project has
large directories that don’t affect the build output.
const site = yield* Cloudflare.Website.Waku("Site", { memo: { include: ["src/**", "public/**", "package.json"], },});Class Form
Section titled “Class Form”Calling Waku with no arguments returns a constructor you can extend
to declare the Worker as a named class. The class is both an Effect
you can yield* to deploy and a type you can reference elsewhere —
useful when other resources need to bind to this Worker.
class Site extends Cloudflare.Website.Waku<Site>()("Site") {}
const site = yield* Site;