feat: add Cloudflare deployment adapter#192
Conversation
Add @marko/run-adapter-cloudflare for deploying Marko Run apps to Cloudflare Workers (default) or Cloudflare Pages. - Builds for the webworker SSR target with workerd export conditions - Workers mode emits a bundled `_worker.js` plus a generated wrangler.json (skipped when a project-level Wrangler config exists) - Pages mode emits an advanced-mode `_worker.js` and a `_routes.json` that excludes static assets from the function - Exposes env/ctx/cf to route handlers via CloudflarePlatformInfo - Previews via the Wrangler CLI (`wrangler dev` / `wrangler pages dev`)
Add dev test fixtures for both Cloudflare adapter modes, mirroring the existing Netlify adapter fixtures. Preview is skipped because it requires the Wrangler CLI (unavailable in CI), matching the Netlify edge fixture. Verified the build output for each mode: - workers: dist/_worker.js (default fetch export with ASSETS fallback) and a generated dist/wrangler.json pointing at the worker and public assets - pages: dist/public/_worker.js plus dist/public/_routes.json excluding the static assets dir
🦋 Changeset detectedLatest commit: 153dc22 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
WalkthroughThis PR adds a new 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
packages/adapters/cloudflare/scripts/build.ts (1)
40-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
splitting: truediverges from the sibling build script's convention.The analogous esm build in
packages/run/scripts/build.tsusessplitting: !true(i.e.false). Here it's set totruefor the single-entry esm build (src/index.ts), which has no practical effect today but is an unexplained deviation, and could silently start emitting chunk files if dynamic imports are ever introduced intosrc/index.ts, changing the publisheddistlayout.♻️ Suggested fix to align with the established pattern
build({ ...opts, format: "esm", - splitting: true, + splitting: false, }),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/adapters/cloudflare/scripts/build.ts` around lines 40 - 44, The single-entry ESM build in build() is using splitting: true, which deviates from the sibling script’s convention and could change the emitted dist layout if dynamic imports appear later. Update the cloudflare build configuration to match the existing pattern used in the analogous build script by disabling splitting for the src/index.ts ESM output, keeping the build behavior aligned and stable.packages/run/src/__tests__/fixtures/cloudflare-adapter-pages/.gitignore (1)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider ignoring
.wrangler/local cache too.
wrangler dev/wrangler pages devwrite a local.wranglercache directory; worth adding alongsidedistto avoid accidental commits during local preview testing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/run/src/__tests__/fixtures/cloudflare-adapter-pages/.gitignore` at line 1, The fixture .gitignore currently ignores only dist, but wrangler dev and wrangler pages dev also create a local .wrangler cache directory that should be excluded. Update the .gitignore content in this fixture to ignore .wrangler alongside dist so local preview artifacts are not accidentally committed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/adapters/cloudflare/package.json`:
- Around line 16-22: The package metadata still points `exports["."]` and
`types` at `src/index.ts`, but only `dist/` is published, so update the
Cloudflare adapter package entrypoints to the built outputs instead. Adjust the
`exports` and `types` fields in the package configuration to reference the
generated JS and declaration files under `dist/`, keeping the existing `files`
list aligned with what consumers can actually import.
In `@packages/adapters/cloudflare/src/index.ts`:
- Around line 74-83: The Workers preview path in startPreview() is pointing at a
dist-local wrangler.json that buildEnd() may not create when a root Wrangler
config already exists. Update the preview flow in startPreview() and the config
emission logic in buildEnd() so they stay in sync: either always write the
dist-scoped wrangler.json, or have the preview command reference the root config
when that is the intended source. Use the existing startPreview and buildEnd
symbols to locate the related branches and keep the pages/dev and worker/dev
modes consistent.
- Around line 68-90: The startPreview flow in the Cloudflare adapter is dropping
env-file support because it spawns Wrangler with only process.env. Update the
startPreview implementation in the Cloudflare adapter so it merges
previewOptions.options.envFile into the environment passed to spawn, matching
the base adapter’s env-file handling. Use the existing startPreview,
previewOptions, and spawn setup to locate the change and ensure Wrangler preview
receives the loaded env values.
---
Nitpick comments:
In `@packages/adapters/cloudflare/scripts/build.ts`:
- Around line 40-44: The single-entry ESM build in build() is using splitting:
true, which deviates from the sibling script’s convention and could change the
emitted dist layout if dynamic imports appear later. Update the cloudflare build
configuration to match the existing pattern used in the analogous build script
by disabling splitting for the src/index.ts ESM output, keeping the build
behavior aligned and stable.
In `@packages/run/src/__tests__/fixtures/cloudflare-adapter-pages/.gitignore`:
- Line 1: The fixture .gitignore currently ignores only dist, but wrangler dev
and wrangler pages dev also create a local .wrangler cache directory that should
be excluded. Update the .gitignore content in this fixture to ignore .wrangler
alongside dist so local preview artifacts are not accidentally committed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a0821cb7-cb32-48f5-83ad-6704392ddba9
⛔ Files ignored due to path filters (3)
package-lock.jsonis excluded by!**/package-lock.jsonand included by**packages/run/src/__tests__/fixtures/cloudflare-adapter-pages/__snapshots__/dev.expected.mdis excluded by!**/__snapshots__/**and included by**packages/run/src/__tests__/fixtures/cloudflare-adapter-workers/__snapshots__/dev.expected.mdis excluded by!**/__snapshots__/**and included by**
📒 Files selected for processing (26)
.changeset/cloudflare-adapter.mdcspell.jsonpackages/adapters/cloudflare/README.mdpackages/adapters/cloudflare/package.jsonpackages/adapters/cloudflare/scripts/build.tspackages/adapters/cloudflare/scripts/importMetaURL.jspackages/adapters/cloudflare/src/default-entry.tspackages/adapters/cloudflare/src/index.tspackages/adapters/cloudflare/src/types.tspackages/adapters/cloudflare/tsconfig.jsonpackages/run/src/__tests__/fixtures/cloudflare-adapter-pages/.gitignorepackages/run/src/__tests__/fixtures/cloudflare-adapter-pages/.marko-run/routes.d.tspackages/run/src/__tests__/fixtures/cloudflare-adapter-pages/package.jsonpackages/run/src/__tests__/fixtures/cloudflare-adapter-pages/src/components/counter.markopackages/run/src/__tests__/fixtures/cloudflare-adapter-pages/src/routes/+page.markopackages/run/src/__tests__/fixtures/cloudflare-adapter-pages/test.config.tspackages/run/src/__tests__/fixtures/cloudflare-adapter-pages/tsconfig.jsonpackages/run/src/__tests__/fixtures/cloudflare-adapter-pages/vite.config.tspackages/run/src/__tests__/fixtures/cloudflare-adapter-workers/.gitignorepackages/run/src/__tests__/fixtures/cloudflare-adapter-workers/.marko-run/routes.d.tspackages/run/src/__tests__/fixtures/cloudflare-adapter-workers/package.jsonpackages/run/src/__tests__/fixtures/cloudflare-adapter-workers/src/components/counter.markopackages/run/src/__tests__/fixtures/cloudflare-adapter-workers/src/routes/+page.markopackages/run/src/__tests__/fixtures/cloudflare-adapter-workers/test.config.tspackages/run/src/__tests__/fixtures/cloudflare-adapter-workers/tsconfig.jsonpackages/run/src/__tests__/fixtures/cloudflare-adapter-workers/vite.config.ts
- Add package.toggle.json so publish points exports/types at dist/ - Make the injected import.meta.url shim a string (.href) for the CJS build - Fix the README platform example to read from context.platform - Workers preview: only pass --config when the generated wrangler.json exists (it is skipped when the project has its own Wrangler config), otherwise let Wrangler discover the project config - Load the --env-file into the Wrangler preview environment - Throw instead of exiting the process when the Wrangler CLI is missing
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/adapters/cloudflare/src/index.ts (1)
83-100: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winDrop
shell: truefrom the Wrangler spawn.
spawn(..., { shell: true })concatenates args instead of escaping them, sopublicDir,generatedConfig, and forwarded preview args can be split or interpreted by the shell. Useshell: false(or a cross-platform wrapper if you need shim support).♻️ Proposed change
const proc = spawn("wrangler", args, { cwd, env: process.env, - shell: true, + shell: false, });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/adapters/cloudflare/src/index.ts` around lines 83 - 100, The Wrangler launch in spawn currently uses shell: true, which can let publicDir, generatedConfig, and args from parseWranglerArgs be reinterpreted by the shell. Update the spawn call in the Cloudflare adapter’s index logic to run without a shell (or use a cross-platform wrapper if shim support is required) so the args array is passed through safely and verbatim.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/adapters/cloudflare/src/index.ts`:
- Around line 83-100: The Wrangler launch in spawn currently uses shell: true,
which can let publicDir, generatedConfig, and args from parseWranglerArgs be
reinterpreted by the shell. Update the spawn call in the Cloudflare adapter’s
index logic to run without a shell (or use a cross-platform wrapper if shim
support is required) so the args array is passed through safely and verbatim.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8e25ac50-08e8-43cc-bbd2-cbc594375514
📒 Files selected for processing (4)
packages/adapters/cloudflare/README.mdpackages/adapters/cloudflare/package.toggle.jsonpackages/adapters/cloudflare/scripts/importMetaURL.jspackages/adapters/cloudflare/src/index.ts
✅ Files skipped from review due to trivial changes (2)
- packages/adapters/cloudflare/package.toggle.json
- packages/adapters/cloudflare/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/adapters/cloudflare/scripts/importMetaURL.js
Use `shell: true` only on Windows (where `wrangler` is a `.cmd` shim that requires it). On POSIX the CLI is spawned directly, so `close()` kills Wrangler itself instead of an orphaned shell wrapper and argument values are no longer re-parsed by the shell. Also handle the child's error event so a failed launch doesn't crash the parent.
…lare) Clarify that Marko Run automatically uses an installed adapter with no Vite config, and add a Deploying section right after installation showing `npm run build` + `npx wrangler deploy -c dist/wrangler.json`.
Description
Adds a new adapter package,
@marko/run-adapter-cloudflare, for previewing and deploying Marko Run apps to Cloudflare. It supports both Cloudflare targets via amodeoption:mode: "workers"(default) — builds a bundled_worker.js(export default { fetch }) for Cloudflare Workers with a static assets binding, and generates a starterwrangler.jsonpointing at the worker and thepublic/assets. An existing project-level Wrangler config (wrangler.toml/.json/.jsonc) is left untouched so user-defined bindings/secrets/name are preserved.mode: "pages"— builds a Cloudflare Pages "advanced mode"_worker.jsalongside the static assets and emits a_routes.jsonthat excludes the static asset directory from invoking the function.Implementation mirrors the existing Netlify edge adapter:
webworkerwithworkerd/workerexport conditions andnoExternal: true(single self-contained bundle).default-entrythat calls@marko/run's router and falls back toenv.ASSETS.fetchwhen no route matches.{ env, ctx, cf }via the exportedCloudflarePlatformInfotype.wrangler devfor Workers,wrangler pages devfor Pages).Also adds two test fixtures to the
@marko/runpackage (cloudflare-adapter-workersandcloudflare-adapter-pages) mirroring the Netlify fixtures, and a changeset for the new package.Motivation and Context
Cloudflare is one of the most-requested deployment targets and the canonical edge platform, but Marko Run shipped no adapter for it — users had to wire up Workers/Pages by hand. Because the runtime is built on web standards, a Cloudflare adapter is a natural fit and fills the largest gap in deployment coverage alongside the existing Node, static, and Netlify adapters.
Screenshots (if appropriate):
Checklist:
Generated by Claude Code