Waku
Archil.Website.Waku deploys a Waku app to an Archil
sandbox, (React Server Components) on Node, with SSG pages served extensionless. The site is the
program of its own sandbox, on port 3000, at a public
https://3000-…archil.app URL. A stopped sandbox starts again on the next
request.
Install
Section titled “Install”The build integration is not bundled with alchemy. Install
@alchemy.run/frontend-frameworks; the resource loads its /waku
and /waku/node exports from your project at deploy time. It is only
used at build time, so a dev dependency is enough:
pnpm add -D https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:d8eb8a5bun add -d https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:d8eb8a5npm install -D https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:d8eb8a5yarn add -D https://pkg.alchemy.run/@alchemy.run/frontend-frameworks/pr:2930:d8eb8a5Configure Waku
Section titled “Configure Waku”No framework config is required — a fresh Waku project deploys
as-is. If your project has a waku.config.ts, Alchemy loads it
natively (exactly as Waku’s own CLI does) and uses it as the base
config — including Vite plugins under its vite field:
import tailwindcss from "@tailwindcss/vite";import { defineConfig } from "waku/config";
export default defineConfig({ basePath: "/", vite: { plugins: [tailwindcss()], },});Options set on the resource (srcDir, distDir, basePath) merge
over the file, per key. The one key Alchemy owns is
unstable_adapter — the Node deploy target sets it. Setting it
fails the build with an actionable error.
Declare the Website
Section titled “Declare the Website”Declare the site as a module-level const:
import * as Archil from "@alchemy.run/archil";
export const Website = Archil.Website.Waku("Website");sandbox sizes the site’s sandbox and sets its image, timeouts, disks and network policy:
export const Website = Archil.Website.Waku("Website", { sandbox: { vcpuCount: 2, memSizeMiB: 4096, idleTtlSeconds: 600 },});Add it to the Stack
Section titled “Add it to the Stack”Yield the site from your Stack and return its URL:
import * as Archil from "@alchemy.run/archil";import * as Alchemy from "alchemy";import * as Effect from "effect/Effect";
export const Website = Archil.Website.Waku("Website");
export default Alchemy.Stack( "MyWakuSite", { providers: Archil.providers(), state: Alchemy.localState(), }, Effect.gen(function* () { const site = yield* Website; return { url: site.url }; }),);Run alchemy deploy. url is the site’s https://3000-…archil.app URL.
site.sandbox is the sandbox behind it, and undefined under
alchemy dev.
See examples/archil-website-waku for the checked-in example.
Add environment variables
Section titled “Add environment variables”Process environment is a top-level env map — plain strings, or
Redacted values:
export const Website = Archil.Website.Waku("Website", { env: { GREETING: "Hello from alchemy", API_BASE: "https://api.example.com", },});The values are copied onto process.env before the build and the
dev server, and onto the program at deploy time, so server
code reads the same keys in both modes. Client inlining is whatever
Vite does (VITE_ prefixes).
Read the environment in server code
Section titled “Read the environment in server code”The RSC server is a plain Node process. Server components and API
routes read process.env (Waku’s getEnv reads the same values):
export default async function HomePage() { const greeting = process.env.GREETING ?? "hello"; return <h1>{greeting}</h1>;}
export const getConfig = async () => ({ render: "dynamic" }) as const;Local dev
Section titled “Local dev”bun alchemy devalchemy dev runs Waku’s own dev server (native HMR) instead of
deploying; site.url is the local address and no Archil resources
are created. Wrap the site in Alchemy.remote() to deploy the live sandbox even during dev:
export const Website = Archil.Website.Waku("Website").pipe( Alchemy.remote(),);Where next
Section titled “Where next”Archil.Website.Wakureference- Websites — every framework Archil hosts
- Programs and Sandboxes — what the site runs on