Skip to content

fix(router): buildEnv "auto" reads the wrangler config of the Vite root - #1045

Merged
ivogt merged 1 commit into
mainfrom
fix/1037-build-env-auto-root
Oct 4, 2026
Merged

ivogt merged 1 commit into
mainfrom
fix/1037-build-env-auto-root

Conversation

@ivogt

@ivogt ivogt commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator

Closes #1037.

Problem

With rango({ preset: "cloudflare", buildEnv: "auto" }), building from a directory other than the app's (vite build tests/cloudflare-basic from the repo root) gave build-time Prerender/Static handlers an env without the app's bindings. The /build-env prerender failed with Cannot read properties of undefined (reading 'put'); building from inside the app passed. getPlatformProxy() was called with no options, so wrangler searched for its config from process.cwd(), and also resolved its default persist path against process.cwd().

Before / after

// before: router-discovery.ts, resolveBuildEnv
const proxy = await getPlatformProxy();

// after
const proxy = await getPlatformProxy(wranglerProxyOptions(factoryCtx.root));

Consumer side: nothing to change. The same config now works from any working directory.

// vite.config.ts, unchanged
export default defineConfig({
  plugins: [rango({ preset: "cloudflare", buildEnv: "auto" })],
});
$ vite build apps/web        # from the monorepo root
before: FAIL /build-env - Cannot read properties of undefined (reading 'put')
after:  OK   /build-env

Semantics

Case Call
Config (wrangler.json, wrangler.jsonc, wrangler.toml, in that order) found in the Vite root or an ancestor getPlatformProxy({ configPath, persist: { path: <Vite root>/.wrangler/state/v3 } })
No config found upward from the root getPlatformProxy(), as before
Redirected config (.wrangler/deploy/config.json) not followed; an explicit configPath is used. Unchanged for apps without a redirect, left as is
Non-cloudflare presets, factory, plain object unchanged

Wrangler facts (installed wrangler-dist/cli.js): findWranglerConfig at line 3172 checks wrangler.json, wrangler.jsonc, wrangler.toml with a find-up from the reference path (default process.cwd()). getPlatformProxy passes options.configPath to readConfig at line 370330. Its persist root is the literal ".wrangler/state/v3" (getMiniflarePersistRoot, line 370381) with no config-relative resolution, so it lands under process.cwd(); hence persist is passed explicitly. It is anchored to the Vite root, not to the config's directory: @cloudflare/vite-plugin reads local state from <Vite root>/.wrangler/state/v3 in dev and preview (getPersistenceRoot(root, persistState), dist/index.mjs:64251), so build-time writes land where dev and preview read them also when the config sits above the root. When the working directory is the root, the path is the one wrangler used before.

Code change

packages/rangojs-router/src/vite/router-discovery.ts: new wranglerProxyOptions(root) (find-up with wrangler's names and order) and one changed call; resolveBuildEnv is now exported so the test can drive it. No public option; the Cloudflare Vite plugin's own configPath is not read.

Test plan

  • New unit test src/vite/__tests__/build-env-auto-root.test.ts (stub wrangler package recording the options, cwd changed away from the root): config under root is passed with the persist path under the root; name order; upward search from a nested root (state stays under the nested root); no config gives undefined options. Red without the fix (3 of 4 fail: expected undefined to deeply equal { configPath, persist }), green with it.
  • vite build tests/cloudflare-basic from the repo root now passes (OK /build-env).
  • playwright test --project=production --no-deps build-env in tests/cloudflare-basic: 2 passed.
  • typecheck, test:unit:all, lint, format, check:e2e-bucketing, check:e2e-parity --strict, check:docs-api.
  • test:hmr-routes-local: 21 passed.
  • No e2e added: build tooling with no browser-visible behavior; the existing production build-env suites cover the normal build.

Notes

  • A from-root build of tests/cloudflare-basic still logs SHELL SKIP ... Cannot read properties of null (reading 'useState') for its 5 PPR shells (runtime capture is kept, exit 0). The in-directory build captures them (SHELL OK). That is a separate working-directory dependence in the shell-capture server, hidden until now because this build failed earlier. Filed as Vite started from another working directory: plugin-rsc externalizes the app's React-peer dependencies, so build-time and dev PPR shell captures are skipped #1044, not addressed here.
  • Review: one independent four-angle pass (reuse, simplification, efficiency, altitude). Applied: persisted state anchored to the Vite root instead of the config's directory (it has to match where the Cloudflare Vite plugin reads), and a .catch(() => {}) in the upward-search test that would have hidden a failure is gone. Skipped: rewriting the find-up loop as while (true) (style), and testing the pure helper instead of the call (the test would no longer prove the options reach getPlatformProxy).
  • Docs: changelog entry, skills/cloudflare/SKILL.md, docs/internal/feature-map.md, and the tests/cloudflare-basic sentence in docs/design/per-app-cache-version.md.

@pkg-pr-new

pkg-pr-new Bot commented Oct 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@rangojs/router@1045

commit: 77f0bb5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

buildEnv: "auto" reads the wrangler config from the working directory, not the Vite root

1 participant