Skip to content

Commit 1c9dabf

Browse files
authored
refactor(nextjs): Change ESM interop. to remove lazy loading (#22193)
Code checking `default` like this always points to an ESM/CJS interop issue: https://github.com/getsentry/sentry-javascript/blob/8c6358a31de99cdb697509e4e2b1fcc38efba401/packages/server-utils/src/orchestrion/bundler/webpack.ts#L53 This is caused by our repo-wide Rollup setting of `interop: 'esModule'`. This is required for us to be able to monkey patch Node built-ins but causes the above issues with CJS dependencies that use the classic CJS default export (`module.exports = fn`). This PR overrides the `interop` setting for the suspect package and removes the lazy dependency loading.
1 parent 3522661 commit 1c9dabf

4 files changed

Lines changed: 16 additions & 6 deletions

File tree

dev-packages/rollup-utils/npmHelpers.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ export function makeBaseNPMConfig(options = {}) {
9494
// (We don't need it, so why waste the bytes?)
9595
freeze: false,
9696

97+
// Assume externals are ESM-shaped (`__esModule` + `.default`), which our own `@sentry/*`
98+
// packages satisfy via `esModule: 'if-default-prop'`. This keeps `import * as x` a live
99+
// reference to the real module rather than an `_interopNamespace` copy — instrumentation code
100+
// relies on that to monkey-patch modules like `fs` in place. Packages that pull in bare-CJS
101+
// third-party deps (no `.default`) override this per-module (see server-utils).
97102
interop: 'esModule',
98103
},
99104

packages/nextjs/src/config/webpack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ export function constructWebpackConfigFunction({
433433

434434
// Orchestrion code-transform loader — Node server runtime only, never the edge compilation
435435
if (runtime === 'server' && userSentryOptions._experimental?.useDiagnosticsChannelInjection) {
436-
newConfig.plugins.push(sentryOrchestrionWebpackPlugin() as WebpackPluginInstance);
436+
newConfig.plugins.push(sentryOrchestrionWebpackPlugin() as unknown as WebpackPluginInstance);
437437
}
438438

439439
return newConfig;

packages/server-utils/rollup.npm.config.mjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ export default [
4444
exports: 'named',
4545
// set preserveModules to true because we don't want to bundle everything into one file.
4646
preserveModules: true,
47+
// `@apm-js-collab/code-transformer-bundler-plugins` ships CJS entries as bare
48+
// `module.exports = fn` with no `__esModule`/`.default`. The repo default
49+
// `interop: 'esModule'` assumes ESM-shaped externals and would dereference a nonexistent
50+
// `.default`, so a default import compiles to `codeTransformer.default(...)` → "not a
51+
// function". Use 'auto' for just these so Rollup emits its interop helper. Scoped here (not
52+
// repo-wide) because 'auto' also turns `import * as x` into a copy, which breaks in-place
53+
// monkey-patching that other packages (e.g. the OTel fs instrumentation) depend on.
54+
interop: id => (id?.startsWith('@apm-js-collab/code-transformer-bundler-plugins') ? 'auto' : 'esModule'),
4755
},
4856
},
4957
}),

packages/server-utils/src/orchestrion/bundler/webpack.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { createRequire } from 'node:module';
55
import { dirname } from 'node:path';
66
import type { InstrumentationConfig } from '..';
77
import { SENTRY_INSTRUMENTATIONS } from '../config';
8+
import codeTransformerWebpack from '@apm-js-collab/code-transformer-bundler-plugins/webpack';
89
import type { PluginOptions } from './options';
910
import { orchestrionTransformOptions } from './options';
1011

@@ -46,10 +47,6 @@ export function getSentryInstrumentations(): InstrumentationConfig[] {
4647
/**
4748
* The code-transform webpack plugin, pre-fed the instrumentation config
4849
*/
49-
export function sentryOrchestrionWebpackPlugin(options: PluginOptions = {}): unknown {
50-
const mod = getOrchestrionRequire()('@apm-js-collab/code-transformer-bundler-plugins/webpack') as {
51-
default?: (options: { instrumentations: InstrumentationConfig[] }) => unknown;
52-
};
53-
const codeTransformerWebpack = mod.default ?? (mod as unknown as NonNullable<typeof mod.default>);
50+
export function sentryOrchestrionWebpackPlugin(options: PluginOptions = {}): ReturnType<typeof codeTransformerWebpack> {
5451
return codeTransformerWebpack(orchestrionTransformOptions(options));
5552
}

0 commit comments

Comments
 (0)