3.2 KiB
@fixtures/vocs
E2E fixture for vocs (the minimal React documentation framework) on Cloudflare Workers.
Vocs 2.x is built on waku: its vocs() vite plugin (public export
vocs/vite) composes waku's own waku/vite-plugins (environments,
adapter-alias, static-build, ...) with vocs's mdx/config/patch plugins, and it
peer-depends on waku ^1.0.0-beta.6. It is not a fully static site: page
bodies are prerendered RSC elements, but the document shell is SSR'd per
request and there are dynamic API routes (/api/search, /api/og,
/api/mcp, /api/feedback) — so it runs as a worker.
Vocs does not use waku's unstable_combinedPlugins, so the
@alchemy.run/frontend-frameworks/waku Framework layer can't drive it directly. Instead,
@alchemy.run/frontend-frameworks/vocs provides a first-class Vocs framework
integration and target contract. Its Cloudflare target composes the established
Waku adapter and RSC environment primitives while owning Vocs-specific target
selection, runtime requirements, config bridging, and public exports.
There is no vite.config.ts and no wrangler.jsonc: e2e.config.ts carries
the entire worker configuration in memory; vocs.config.ts is vocs's own
(platform-agnostic) docs config.
What it exercises
- Worker SSR — the docs shell (sidebar, layout) is rendered by the worker at request time in both dev (workerd module-runner) and preview (miniflare).
- MDX pages —
src/pages/*.mdxwith sidebar navigation. - Client interactivity —
src/components/Counter.tsxis a"use client"component embedded in MDX, hydrated in the browser. - Static assets —
public/hello.txtrides along indist/public, next to vocs's build-time artifacts (llms.txt,llms-full.txt).
Workerd bridges (and why vocs is pinned exactly)
Upstream vocs only ships node/vercel/netlify adapters — nothing targets a
no-fs runtime. Runtime config resolution needs a small bridge, implemented as
the workerdConfigBridge Vite plugin in the public Vocs integration:
- Runtime config resolution — vocs's server code calls
Config.resolve({ server: true })per request; in production that branch dynamically imports an on-diskdist/server/vocs.config.jsviaimport.meta.dirname(Node server layout), which crashes in workerd. The bridge rewrites that branch to import a virtual module which re-exports the project's originalvocs.config.*. Vite therefore loads and bundles the config itself, preserving its imports and functions; Alchemy does not separately resolve or serialize it.
The transform hard-fails with a descriptive error if the installed vocs no
longer matches the expected internals — which is why vocs is pinned to an
exact version. On a bump, re-check the guarded patterns in
packages/frontend-frameworks/src/vocs/Vocs.ts.
nodejs_compat (not just nodejs_als) is required: vocs's server bundle
imports node:fs and friends (guarded with try/catch at runtime).
Commands
bun run dev # vocs dev over workerd (port 3105)
bun run build # programmatic vocs build -> dist/ + dist/build.json
bun run preview # miniflare over dist/build.json
bun run test # playwright: live (built worker) + dev