Skip to content

fix(vxrn): wrap dev native bundle in function scope to stop global var leaks#715

Merged
natew merged 1 commit into
mainfrom
fix/rolldown-dev-global-scope-leak
Jun 9, 2026
Merged

fix(vxrn): wrap dev native bundle in function scope to stop global var leaks#715
natew merged 1 commit into
mainfrom
fix/rolldown-dev-global-scope-leak

Conversation

@natew

@natew natew commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Problem

Native iOS Tests (dev, rolldown) times out (45-min job limit → run cancelled). Root-caused from the cancelled run's failure screenshots: the dev app is stuck on a LogBox redbox Failed to set polyfill. Headers is not configurable., so quick-navigate-pixel never mounts and every appium navigation waits the full 120s before falling back → the suite blows the timeout.

Mechanism (verified against the actual dev bundle)

rolldown's dev() emits the native bundle as a script. RN's Libraries/Network/fetch.js declares var fetch_hot, fetch$1, Headers, Request, Response$1; at top level — and a top-level var in a script creates a non-configurable property on the global object. So global.Headers/global.Request become non-configurable. RN's setUpXHR then runs polyfillGlobal('Headers')polyfillObjectProperty does Object.defineProperty(global, 'Headers', { configurable: true, … }), which throws Cannot redefine property → RN turns that into console.error('Failed to set polyfill. Headers is not configurable.'). In dev that becomes a blocking redbox.

prod is immune: its modules are wrapped in closures (no global leak) and it has no LogBox — which is why prod, rolldown passes.

Proven in isolation:

script-scope  var Headers → descriptor { configurable: false }  → defineProperty throws (the bug)
wrapped (IIFE) var Headers → no global own prop                 → defineProperty succeeds

Fix

Wrap everything after the prelude in an IIFE (wrapNativeBundleModuleScope, dev path only) so module top-level vars stay function-scoped, matching the prod build. The prelude stays at script scope (it deliberately installs globalThis.global/__DEV__/process/…). Intentional globals survive: the runtime is assigned via globalThis.__rolldown_runtime__, and HMR updates run through a direct eval inside the wrap, so they still see the closure's helpers/module bindings.

Verification

  • Rebuilt vxrn, re-fetched the real dev bundle: ;(function() { is inserted right after the prelude, the leaking var … Headers decl is now inside the wrap, })(); closes before the (preserved) sourceMappingURL, and node --check parses it.
  • New regression test wrapNativeBundleModuleScope (wrap structure + no-op without marker + syntactic validity). vxrn suite 39/39, typecheck 0, oxlint 0/0.
  • Real iOS E2E validated on a workflow_dispatch run of this branch (below).

…r leaks

rolldown dev() emits the native bundle as a script, so module top-level
vars (RN fetch.js's `var Headers, Request, Response`) leak as
non-configurable global properties. RN's polyfillGlobal then fails
('Failed to set polyfill. Headers is not configurable'), which in dev
becomes a blocking LogBox redbox — the app never mounts, every appium
navigation times out, and the iOS dev jobs hit the 45-min limit.

Wrap everything after the prelude in an IIFE so module top-level vars stay
function-scoped (matching the prod build). The prelude stays at script
scope (it installs globals); the runtime is assigned via globalThis and
HMR updates run through a direct eval, so both survive the wrap.
@railway-app railway-app Bot temporarily deployed to onestack.dev / one-pr-715 June 9, 2026 05:58 Destroyed
@railway-app

railway-app Bot commented Jun 9, 2026

Copy link
Copy Markdown

🚅 Deployed to the one-pr-715 environment in onestack.dev

Service Status Web Updated (UTC)
one ✅ Success (View Logs) Web Jun 9, 2026 at 6:00 am

@natew natew added this pull request to the merge queue Jun 9, 2026
Merged via the queue into main with commit 82786b9 Jun 9, 2026
10 of 11 checks passed
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.

1 participant