fix(react-router): Resolve the Cloudflare entry in Workers and skip trace meta tags in prerendered pages (#24866)
Three bugs in `@sentry/react-router`, found by running the `react-router-8-framework` e2e suite on workerd and Bun. Cloudflare builds resolve with both the `worker` and the `browser` condition (the Vite plugin sets `workerd, worker, module, browser`, `wrangler` sets `workerd, worker, browser`), and the exports map listed `browser` before `worker`, so `worker` was never reached. `import * as Sentry from '@sentry/react-router'` in a route got the client build, and `Sentry.startSpan()` / `Sentry.flush()` compiled to `undefined`: loaders and middleware that call them threw `TypeError: (void 0) is not a function`. A `workerd` key now comes first and resolves the Cloudflare entry. Only Cloudflare sets `workerd`, so nothing else changes: moving `worker` above `browser` would also have switched webpack builds with `target: 'webworker'`, which set `worker` and `browser`, to the Cloudflare entry. On Cloudflare, `react-router build` prerenders pages by running them through the wrapped Worker, so `injectTraceMetaTags` wrote a build-time `sentry-trace` and `baggage` into the static HTML. Every visitor of a prerendered page then continued that one trace with its sampling decision. Such a path never reaches the handler in production (it is served as a static file), so a render of a path from the build's `prerender` list is the build-time prerender, and it now gets no meta tags. For that, the server build capture also records `prerender`, and `wrapSentryHandleRequest` registers the capture: on Cloudflare only the Node server integration did that before, so the build was never captured there. An index route has no `path` of its own, so `wrapSentryHandleRequest` never gave it a route name. On Node, Express names the span first and hid this. On runtimes without that layer (Bun, and a React Router app on any non-Express server) the index page kept a URL-sourced name, so its baggage had no `sentry-transaction`. An index route now takes its nearest ancestor's path, or `/`. On Node this changes the transaction of an index page from Express's catch-all `GET *` to `GET /`, which is why `react-router-7-framework-static` now expects that name. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
J
Jan Peer Stöcklmair committed
425a304da030cdeeb9e6e1eba7a83fdcee328b57
Parent: 8198603
Committed by GitHub <noreply@github.com>
on 10/2/2026, 9:51:39 AM