Skip to content

[migrate] Migrated site 404s on every route in bun run dev — no wrangler.jsonc scaffolded (@cloudflare/vite-plugin mounts no worker) #346

Description

@JonasJesus42

Summary

A freshly migrated site cannot run bun run dev on the first try: every route returns a silent 404 with an empty body — including the framework's own admin routes (/live/_meta, /.decofile) and the CMS home (/). The root cause is that the migrator intentionally does not scaffold a wrangler.jsonc, but the vite.config.ts it generates uses @cloudflare/vite-plugin, which needs a wrangler config to mount the worker in dev. With no worker mounted, Vite falls through to its default 404 for all paths — and, crucially, no error is logged, so it looks like routing is broken rather than config being absent.

This reproduces on essentially every first migration (confirmed on portal-davinci; no migrated site in the workspaces has a wrangler.jsonc).

Root cause

  • packages/blocks-cli/scripts/migrate/phase-scaffold.ts:53-56 deliberately skips wrangler.jsonc:

    // Root config files. wrangler.jsonc is intentionally NOT generated by the migration script -- it's per-site... wired by hand on first deploy (D6.3 interim state...)

  • But phase-scaffold.ts generates a vite.config.ts whose plugin list includes cloudflare({ viteEnvironment: { name: "ssr" } }) (@cloudflare/vite-plugin). That plugin resolves the worker from wrangler.jsonc's main. With the file missing, it mounts no worker, and the deco worker entry (src/worker-entry.tscreateDecoWorkerEntry, which handles /live/_meta, /.decofile, /deco/render, and wraps the TanStack router) never runs.
  • Net symptom: curl /HTTP 404, content-length: 0; curl /live/_meta404; curl /foo404; dev server logs nothing.

The D6.3 decision (wrangler.jsonc is per-site, wired by hand on first deploy) may be fine for deploy, but it makes local dev impossible out of the box — the two are coupled through @cloudflare/vite-plugin.

Repro

  1. Migrate any Fresh/Deno site (e.g. deco-sites/portal-davinci) with the local migrator.
  2. bun install (+ link local packages if testing unpublished framework changes).
  3. bun run generate && bun run dev.
  4. curl -s -o /dev/null -w "%{http_code}\n" http://localhost:<port>/404 (empty body). Same for /live/_meta, /.decofile.

Confirmation

Adding a minimal wrangler.jsonc fixes the primary symptom — the worker boots and routes are handled:

{
  "name": "portal-davinci",
  "main": "src/worker-entry.ts",
  "compatibility_date": "2025-05-01",
  "compatibility_flags": ["nodejs_compat", "no_handle_cross_request_promise_resolution"],
  "kv_namespaces": [{ "binding": "SITES_KV", "id": "dev-sites-kv" }]
}

After this, / renders HTTP 200 with real content (<title>Portal da Vinci | Cirurgia Robótica</title>, ~15 KB body) and /live/_meta is handled (returns 503, i.e. reached the handler, no longer 404).

Secondary first-migration blocker (surfaced only after the wrangler fix)

Once the worker boots, it fails to load with:

Failed to load url ../../.deco/loaders.gen (resolved id: ../../.deco/loaders.gen)
in src/setup/commerce-loaders.ts. Does the file exist?

src/setup/commerce-loaders.ts imports ../../.deco/loaders.gen unconditionally, but the unified bun run generate orchestrator did not emit .deco/loaders.gen.ts (it wrote blocks.gen, sections.gen, meta.gen but not loaders.gen). Running the loaders generator directly (tsx node_modules/@decocms/blocks-cli/scripts/generate-loaders.ts --site <name>) writes the file (even with 0 entries) and unblocks the boot. So the orchestrator skips emitting loaders.gen on first run while a scaffolded file imports it — a second, independent first-run gap.

Impact

Every first migration produces a site that cannot be run locally without two undocumented manual steps (create wrangler.jsonc, generate loaders.gen). The 404-on-everything symptom is especially costly because nothing is logged — it reads as a routing bug, not missing config, and sends people debugging the wrong layer.

Proposed fix

  1. Scaffold a minimal dev wrangler.jsonc in phase-scaffold.ts (main → src/worker-entry.ts, compatibility_date, nodejs_compat + no_handle_cross_request_promise_resolution, a dev SITES_KV binding). If keeping D6.3's "no committed wrangler for deploy" stance, generate it as a dev-only file and/or clearly document it as the required first step in MIGRATION_REPORT.md (currently it's only mentioned tangentially, re: observability).
  2. Ensure the unified generate always emits .deco/loaders.gen.ts (even with 0 entries) so the scaffolded commerce-loaders.ts import resolves — or make that import tolerate an absent file.
  3. Optionally, have the migrator's Verify phase check for wrangler.jsonc + .deco/loaders.gen.ts and fail loudly with the remediation, instead of the silent dev 404.

Found while validating the #305 ctx fix end-to-end on portal-davinci; the ctx fix itself works (page renders, no ctx-undefined errors) once the site can boot.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions