Skip to content

Commit 936541e

Browse files
andreiborzaclaude
andauthored
fix(server-utils): Keep orchestrion registration out of tree-shaking (#23590)
## What Keep the orchestrion registration that the bundler transform injects from being tree-shaken away. - Assign the injected `orchestrionModuleInjected(...)` result to a `globalThis` property instead of discarding it. ## Why The helper returns `void` and `@sentry/server-utils` sets `sideEffects: false`, so a bare call statement is one a bundler can prove droppable. rollup 4.63.0 (released 2026-08-25) does, and drops the registration. Instrumented modules then publish on their diagnostics channel with nothing subscribed, so no spans are recorded. This currently breaks every Cloudflare E2E app that instruments through the vite transform, and it silently disables DB instrumentation for users on vite or rollup 4.63.0 and later. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent cd518e2 commit 936541e

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

‎packages/server-utils/src/orchestrion/bundler/moduleInjectedTransform.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ interface ProgramNode {
1919
// tree-shakes to just the helper and the factories actually referenced.
2020
const DEFAULT_IMPORT_SPECIFIER = '@sentry/server-utils';
2121

22+
/**
23+
* Assignment target that keeps the injected call from being tree-shaken. See
24+
* {@link moduleInjectedSnippet}. The value written is always `undefined`; only
25+
* the assignment matters.
26+
*/
27+
const MODULE_INJECTED_SINK = 'globalThis.__SENTRY_ORCHESTRION_INJECT__';
28+
2229
/**
2330
* Entry-chunk banner that marks "the bundler plugin ran" for
2431
* `detectOrchestrionSetup()`. Merge-only (`g.bundler = g.bundler || []`) so it
@@ -50,6 +57,13 @@ export const ORCHESTRION_BUNDLER_MARKER_BANNER =
5057
* inside a transformed `node_modules` file can't resolve (Turbopack under
5158
* isolated installs); it's embedded via `JSON.stringify` so absolute Windows
5259
* paths survive.
60+
*
61+
* The call result is assigned to a global rather than discarded. The helper
62+
* returns `void` and `@sentry/server-utils` is `sideEffects: false`, so a bare
63+
* call statement is something a bundler can prove droppable: rollup >= 4.63.0
64+
* does exactly that and removes the whole registration, leaving the module
65+
* instrumented but unsubscribed. Writing to a property of `globalThis` is a
66+
* side effect no bundler can shake out, so the call survives.
5367
*/
5468
function moduleInjectedSnippet(
5569
moduleName: string,
@@ -63,7 +77,7 @@ function moduleInjectedSnippet(
6377
: `const { ${bindings} } = require(${JSON.stringify(importSpecifier)});`;
6478

6579
const args = exportName ? `${JSON.stringify(moduleName)}, ${exportName}` : JSON.stringify(moduleName);
66-
return `${importStmt}\norchestrionModuleInjected(${args});`;
80+
return `${importStmt}\n${MODULE_INJECTED_SINK} = orchestrionModuleInjected(${args});`;
6781
}
6882

6983
/**

‎packages/server-utils/test/orchestrion/moduleInjectedTransform.test.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ describe('module-injected transform', () => {
8383
// needed at runtime and the lazy-subscription event matches what channel
8484
// integrations wait for.
8585
expect(result!.code).toContain('orchestrionModuleInjected("mysql", mysqlIntegration)');
86+
// The result is assigned to a global. `@sentry/server-utils` is `sideEffects: false` and the
87+
// helper returns `void`, so a bare call statement is one a bundler can prove droppable.
88+
// rollup >= 4.63.0 removes it, leaving the module instrumented but unsubscribed.
89+
expect(result!.code).toContain('globalThis.__SENTRY_ORCHESTRION_INJECT__ = orchestrionModuleInjected(');
8690
// No separate @sentry/core import at the injection site — the helper owns that.
8791
expect(result!.code).not.toContain('@sentry/core');
8892
// It imports ONLY the mysql factory — no central dispatch pulling in others.

0 commit comments

Comments
 (0)