Skip to content

Commit 4806b8a

Browse files
RulaKhaledchargome
andauthored
fix(nextjs): Skip re instrumentating on generate phase of experimental build mode (#16410)
Next.js v15.3.0-canary.1 introduced a new approach to the two-phase experimental build (--experimental-build-mode=compile then =generate) that applies env inlining during generate build mode. Why it breaks? Our `withSentryConfig` still assumes a single “full” build and reruns its Webpack instrumentation in both phases. During the generate step it collides with Next.js’s new inliner (e.g. for assetPrefix), producing malformed JS and build failures. Root cause: Double application of build-time transforms—Sentry inlines/reprocesses a bundle that Next.js’s generate mode is simultaneously trying to finalize—leads to conflicting replacements and syntax errors. This PR is a quick workaround that patches our build script so that: 1. Compile phase (--experimental-build-mode=compile): Sentry’s instrumentation runs as usual. 2. Generate phase (--experimental-build-mode=generate): We skip Sentry’s build-time hooks entirely, letting Next.js handle inlining and prerendering without collision. This immediately prevents the build failures and defers full “generate” work to Next.js’s own pipeline. I confirmed that source maps and error / tracing still function as expected, BUT things might still occur as it's still an experimental undocumented feature. --------- Co-authored-by: Charly Gomez <[email protected]>
1 parent dcdf074 commit 4806b8a

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

packages/nextjs/src/config/withSentryConfig.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { getNextjsVersion } from './util';
1515
import { constructWebpackConfigFunction } from './webpack';
1616

1717
let showedExportModeTunnelWarning = false;
18+
let showedExperimentalBuildModeWarning = false;
1819

1920
/**
2021
* Modifies the passed in Next.js configuration with automatic build-time instrumentation and source map upload.
@@ -67,6 +68,27 @@ function getFinalConfigObject(
6768
}
6869
}
6970

71+
if (process.argv.includes('--experimental-build-mode')) {
72+
if (!showedExperimentalBuildModeWarning) {
73+
showedExperimentalBuildModeWarning = true;
74+
// eslint-disable-next-line no-console
75+
console.warn(
76+
'[@sentry/nextjs] The Sentry Next.js SDK does not currently fully support next build --experimental-build-mode',
77+
);
78+
}
79+
if (process.argv.includes('generate')) {
80+
// Next.js v15.3.0-canary.1 splits the experimental build into two phases:
81+
// 1. compile: Code compilation
82+
// 2. generate: Environment variable inlining and prerendering (We don't instrument this phase, we inline in the compile phase)
83+
//
84+
// We assume a single “full” build and reruns Webpack instrumentation in both phases.
85+
// During the generate step it collides with Next.js’s inliner
86+
// producing malformed JS and build failures.
87+
// We skip Sentry processing during generate to avoid this issue.
88+
return incomingUserNextConfigObject;
89+
}
90+
}
91+
7092
setUpBuildTimeVariables(incomingUserNextConfigObject, userSentryOptions, releaseName);
7193

7294
const nextJsVersion = getNextjsVersion();

packages/nextjs/test/config/withSentryConfig.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,29 @@ describe('withSentryConfig', () => {
5050

5151
expect(exportedNextConfigFunction).toHaveBeenCalledWith(defaultRuntimePhase, defaultsObject);
5252
});
53+
54+
it('handles experimental build mode correctly', () => {
55+
const originalArgv = process.argv;
56+
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
57+
58+
try {
59+
process.argv = [...originalArgv, '--experimental-build-mode'];
60+
materializeFinalNextConfig(exportedNextConfig);
61+
62+
expect(consoleWarnSpy).toHaveBeenCalledWith(
63+
'[@sentry/nextjs] The Sentry Next.js SDK does not currently fully support next build --experimental-build-mode',
64+
);
65+
66+
// Generate phase
67+
process.argv = [...process.argv, 'generate'];
68+
const generateConfig = materializeFinalNextConfig(exportedNextConfig);
69+
70+
expect(generateConfig).toEqual(exportedNextConfig);
71+
72+
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
73+
} finally {
74+
process.argv = originalArgv;
75+
consoleWarnSpy.mockRestore();
76+
}
77+
});
5378
});

0 commit comments

Comments
 (0)