feat(cloudflare): Support @cloudflare/opennextjs / wrangler with full parity#142
Open
czxtm wants to merge 4 commits into
Open
feat(cloudflare): Support @cloudflare/opennextjs / wrangler with full parity#142czxtm wants to merge 4 commits into
@cloudflare/opennextjs / wrangler with full parity#142czxtm wants to merge 4 commits into
Conversation
…r-byte When deploying a Worker whose `main` already points at a complete, runtime-ready ESM bundle produced by an external tool (OpenNext, wrangler, custom build pipelines, etc.), alchemy still runs that artifact through `cloudflareRolldown`. `isExternal: true` already disables alchemy's Effect-wrapping virtual entry, but `prepareBundle` still calls `Bundle.build(...)` with `cloudflareRolldown` on the way through. There is currently no way to opt out of that re-bundle. This adds a new `WorkerProps.bundle?: boolean` (default `true`). When set to `false`, `prepareBundle` reads `props.main` directly and returns a synthetic single-file `Bundle.BundleOutput` whose `content` is the file's bytes verbatim and whose `hash` is sha256(bytes). The downstream upload path is unchanged. The accompanying integration test works as follows: 1. Deploy a hand-written ESM bundle that contains a SENTINEL comment 2. Verify the resulting `worker.hash?.bundle` equals `sha256(sourceBytes)` (which is impossible to satisfy if rolldown ran on the file) 3. Round-trip a request through the deployed Worker to confirm the literal sentinel string survives.
Minimal Next.js + OpenNext app deployed via `Cloudflare.Worker` with `bundle: false`, demonstrating the new opt-out for alchemy's rolldown step on pre-built worker bundles. Condensed from the upstream repro (czxtm/repro-alchemy-bundle-false) — 11 files instead of ~36, no Fumadocs/MDX/AI/Tailwind scaffolding.
Adds two prototype resources for deploying Next.js apps via OpenNext to Cloudflare Workers, both bypassing alchemy's rolldown bundler: - `Cloudflare.OpenNext` — bundles `.open-next/worker.js` in-process via esbuild + `@cloudflare/unenv-preset` + a vendored copy of wrangler's `nodejsHybridPlugin`. No subprocess; backed by a new `Cloudflare.OpenNextBundle` resource so esbuild runs during the apply phase where `Output`s materialize. - `Cloudflare.OpenNextWranglerSubprocess` — shells out to `wrangler deploy --dry-run --outdir=...` to delegate bundling to wrangler's exact pipeline. Tracks wrangler precisely with no plugin drift risk. Both compose `Build.Command` (next + opennext build) → bundler → `Cloudflare.Worker` with `bundle: false`, and pass assets via `AssetsWithHash` so `Worker` doesn't read `.open-next/assets` during plan before the build has run. Verified end-to-end (HTTP 200 + correct title) on clean deploy and update re-deploy for both variants via the cloudflare-nextjs example.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
After more testing I discovered that wrangler includes not just the main file, but any other file in the same directory. It also has a few other special-cased behaviors that are required.
This PR should allow any wrangler-deployed app to be deployed by Alchemy, as it actually uses wrangler under-the-hood (or uses esbuild equivalently) and therefore produces the exact same bundle. There are 2 approaches that could be taken - I included both so you can simply delete one of them after deciding which path to take.
OpenNextWranglerSubprocessspawns a subprocess and runswrangler --dry-runwhich is the officially recommended way to produce the exact bundle that wrangler would upload.OpenNextdoes not use a subprocess but instead imports it from wrangler to do the same thing programatically by calling esbuild the same way wrangler does. The obvious risk here is that if that ever changes, then there would be drift. It's also not part of the public API so there's also maintenance risk. The other downside is it introduces a couple dependencies.Both of them produce the exact same thing and successfully deploy the example.