Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion apps/docs/alchemy.run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,44 @@ const program = Effect.gen(function* () {
// The build is expected to have already run (`bun run build:worker`); this
// resource only handles upload + binding wiring.
const website = yield* Cloudflare.Worker("Docs", {
main: ".open-next/worker.js",
// `.open-next/worker.js` is OpenNext's tiny ~2KB entrypoint — it expects to
// be passed through a wrangler-style bundler that resolves the relative
// `./cloudflare/*.js` imports and inlines them. Two viable bundlers:
//
// 1. wrangler (esbuild under the hood) — bundles statics, *preserves*
// runtime `import()` paths. This is what `opennextjs-cloudflare deploy`
// uses internally and what OpenNext is designed against.
// 2. alchemy's built-in cloudflareRolldown — also bundles statics, but
// mangles OpenNext's dynamic `import("./server-functions/default/
// handler.mjs")` so its `resolveWrapper(...)` returns `undefined` at
// request time. The deployed Worker then throws
// `TypeError: Cannot destructure property 'name' of '(intermediate
// value)'`
// inside `createGenericHandler` and every dynamic Next route
// (`/docs/*`, …) returns 500. Static routes (`/`, `/api/search`)
// survive because they're served by the ASSETS binding without
// entering the broken handler.
//
// We pre-bundle with wrangler in `bun run build:worker`
// (`wrangler deploy --dry-run --outdir=.open-next/dist`) and point
// `main:` at the resulting self-contained file, then tell alchemy to skip
// its own bundling pass with `bundle: false` so the byte-for-byte upload
// is the wrangler artifact.
main: ".open-next/dist/worker.js",
// OpenNext emits a plain Workers default export `{ fetch }` — the alchemy
// bootstrap that wraps `main` in `Layer.effect(tag, entry)` mis-handles
// that shape and the deployed worker throws CF 1101 on first request.
// `isExternal: true` skips the wrapper so the bundle keeps OpenNext's own
// entrypoint.
isExternal: true,
// The `bundle: false` opt-out is added by patches/alchemy@2.0.0-beta.20.patch
// (a backport of the proposed upstream change at
// https://github.com/alchemy-run/alchemy-effect — the
// `feat(cloudflare/Worker): add bundle: false …` commit). It short-
// circuits `prepareBundle` to upload `props.main` byte-for-byte. Drop the
// patch + this prop once cloudflareRolldown's dynamic-import handling is
// fixed upstream and we can bundle through alchemy directly.
bundle: false,
// Mirror apps/docs/wrangler.jsonc — OpenNext serves its own routing so the
// worker must run for missed asset paths, and we want the SPA-style
// trailing-slash handling for static MDX routes.
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"private": true,
"scripts": {
"build": "next build",
"build:worker": "opennextjs-cloudflare build",
"build:worker": "opennextjs-cloudflare build && wrangler deploy --dry-run --outdir=.open-next/dist --minify",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts",
"deploy": "bun run build:worker && bunx alchemy deploy",
"deploy:dev": "APP_ENV=dev bun run build:worker && bunx alchemy deploy --stage dev",
Expand Down
25 changes: 12 additions & 13 deletions apps/docs/src/mdx-components.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import defaultMdxComponents from "fumadocs-ui/mdx";
import type { MDXComponents } from "mdx/types";
import {
createGenerator,
createFileSystemGeneratorCache,
} from "fumadocs-typescript";
import { AutoTypeTable } from "fumadocs-typescript/ui";
import { Files, File, Folder } from "@/components/files";
import type { ReactNode } from "react";

// Note on `<AutoTypeTable>`: the MDX tag is *expanded at build time* by
// `remarkAutoTypeTable` in source.config.ts, so the rendered docs never
// contain a live `<AutoTypeTable>` element. Registering the runtime
// component here used to pull `fumadocs-typescript` → `ts-morph` into
// the Cloudflare Worker bundle, which (a) bloats it past the 64 MiB
// uncompressed Workers limit and (b) crashes at request time with
// `[unenv] fs.mkdir is not implemented yet!` from `ts-morph`'s
// `createFileSystemGeneratorCache`. Don't reintroduce a runtime
// `AutoTypeTable` registration unless you're prepared to (1) swap to a
// non-FS cache and (2) verify ts-morph still bundles cleanly under
// `nodejs_compat`.

// NixOption renders stale generated MDX files that still reference <NixOption>.
// It reconstructs the original markdown-table layout from the JSX props so the
// options reference pages look correct until docs are regenerated.
Expand Down Expand Up @@ -132,17 +139,9 @@ function NixOptionMeta() {
return null;
}

const generator = createGenerator({
// recommended: choose a directory for cache
cache: createFileSystemGeneratorCache(".next/fumadocs-typescript"),
});

export function getMDXComponents(components?: MDXComponents): MDXComponents {
return {
...defaultMdxComponents,
AutoTypeTable: (props) => (
<AutoTypeTable {...props} generator={generator} />
),
Files,
File,
Folder,
Expand Down
7 changes: 3 additions & 4 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading