|
| 1 | +# What this is |
| 2 | + |
| 3 | +`@opennextjs/cloudflare` is an adapter that takes a Next.js `standalone` build and runs it on Cloudflare Workers via the Node.js compatibility layer. It sits on top of `@opennextjs/aws`, which provides the generic OpenNext build/runtime core; this package plugs Cloudflare-specific bindings (KV, R2, D1, Durable Objects, Assets, Images) into the override points that `@opennextjs/aws` exposes, and also contains the esbuild plugins and AST grep patches needed to rewrite Next's emitted code to run on Workers. |
| 4 | + |
| 5 | +# Layout |
| 6 | + |
| 7 | +``` |
| 8 | +packages/cloudflare/ # the adapter |
| 9 | + src/api/ # runtime surface users import (small) |
| 10 | + src/cli/ # the `opennextjs-cloudflare` build CLI |
| 11 | + commands/ # build, deploy, preview, etc. commands live here |
| 12 | + build/patches/ # esbuild plugins + ast-grep patches applied to Next's output |
| 13 | + templates/ # starter configs copied by `migrate` command |
| 14 | +examples/ # sample Next apps used for manual + e2e testing |
| 15 | +create-cloudflare/ # templates for the `create-cloudflare` CLI |
| 16 | +benchmarking/ # perf harness |
| 17 | +``` |
| 18 | + |
| 19 | +Two things to keep separate in your head: **`src/api`** is the tiny surface users import at runtime; **`src/cli`** is the much larger build tool. Changes to `src/api` are user-visible; changes in `src/cli/build/patches` are user-invisible but the riskiest code in the repo. |
| 20 | + |
| 21 | +# Commands |
| 22 | + |
| 23 | +Use pnpm. Run from the repo root. |
| 24 | + |
| 25 | +| Command | What it does | |
| 26 | +| -------------------------------------- | -------------------------------------------------------------------------------------------------------- | |
| 27 | +| `pnpm install` | also triggers a `postinstall` build of the adapter. | |
| 28 | +| `pnpm build` | build `packages/cloudflare`. | |
| 29 | +| `pnpm --filter cloudflare build:watch` | rebuild on change. | |
| 30 | +| `pnpm test` | builds, then runs all vitest suites. | |
| 31 | +| `pnpm code:checks` | prettier + eslint + tsc. | |
| 32 | +| `pnpm fix` | auto-fix prettier + eslint. | |
| 33 | +| `pnpm --filter <example> preview` | build + preview an example app end-to-end. Add `SKIP_NEXT_APP_BUILD=true` when only the adapter changed. | |
| 34 | +| `pnpm e2e` / `pnpm e2e:dev` | Playwright suites against the example apps. | |
| 35 | +| `pnpm --filter <example> e2e` | Run a specific example's Playwright suite. | |
| 36 | +| `pnpm changeset` | create a changeset for changes. | |
| 37 | + |
| 38 | +# Conventions |
| 39 | + |
| 40 | +- **Strict TypeScript**. Don't loosen; reach for generics or narrowing. |
| 41 | +- **ESM only**. Internal imports use the `.js` extension (`./foo.js`) even though the source is `.ts` - this is required for bundling, not a mistake. |
| 42 | +- **Unit tests are `*.spec.ts` colocated with source**, run with Vitest. Use `mock-fs` for filesystem-heavy tests. E2E coverage lives in `examples/` and runs under Playwright. |
| 43 | +- **Formatting is prettier**. Don't fight it; `pnpm fix`. |
| 44 | +- **Imports are sorted by `simple-import-sort`.** Let eslint reorder them. |
| 45 | +- **Dependency versions live in `pnpm-workspace.yaml` under `catalog:`.** When adding a shared dep, add it to the catalog and reference it as `"catalog:"` in the package.json. Don't pin versions inline when a catalog entry already exists. |
| 46 | +- **`packages/cloudflare` ships to users**. Be deliberate about adding runtime `dependencies`. Prefer `devDependencies`, inlining small helpers, or moving logic into code that only runs in the CLI. |
| 47 | +- **`CloudflareEnv` is augmented globally** in `src/api/cloudflare-context.ts`. New bindings that users configure should be declared there with a comment explaining what they're for. |
| 48 | +- **User-facing logs** go through `@opennextjs/aws`'s logger, not `console.*`. Warn (don't throw) when experimental features are used. |
| 49 | + |
| 50 | +## Where things tend to go wrong |
| 51 | + |
| 52 | +- **`src/cli/build/patches/`** contains esbuild plugins and `@ast-grep/napi` transforms that rewrite Next's emitted code to run on Workers. Every patch needs a spec, and ideally a minimal fixture of the input it's matching. Upstream Next changes break these; when a patch stops matching, fix the matcher, don't widen it blindly. |
| 53 | +- **Overrides in `src/api/overrides/`** implement contracts defined in `@opennextjs/aws`. Check the upstream type before changing a signature. `@opennextjs/aws` is pinned in `package.json`, so bumping it is a deliberate change with its own changeset. |
| 54 | + |
| 55 | +# Pre-PR checklist |
| 56 | + |
| 57 | +1. `pnpm code:checks` is clean. |
| 58 | +2. `pnpm test` passes. |
| 59 | +3. Changeset included if necessary. |
| 60 | + |
| 61 | +## Changesets |
| 62 | + |
| 63 | +Any behavioural change to `packages/cloudflare` needs one. Skip for internal refactors, test-only changes, example/doc tweaks. |
| 64 | + |
| 65 | +```sh |
| 66 | +pnpm changeset |
| 67 | +``` |
| 68 | + |
| 69 | +Format: |
| 70 | + |
| 71 | +``` |
| 72 | +<type>: <imperative title> |
| 73 | +
|
| 74 | +<body explaining the why> |
| 75 | +``` |
| 76 | + |
| 77 | +- `type` is one of `feature | fix | refactor | docs | chore`. |
| 78 | +- Bugfixes and experimental work -> `patch`. |
| 79 | +- New feature -> `minor`. |
| 80 | +- Breaking changes -> `major`. |
| 81 | + |
| 82 | +Full rules in [CONTRIBUTING.md](CONTRIBUTING.md). |
0 commit comments