Skip to content

Commit bbb1324

Browse files
authored
fix(nextjs): Display updated turbopack warnings (#17737)
1 parent d7538cd commit bbb1324

File tree

4 files changed

+280
-164
lines changed

4 files changed

+280
-164
lines changed

packages/nextjs/src/config/util.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,16 @@ function resolveNextjsPackageJson(): string | undefined {
3333
* Checks if the current Next.js version supports the runAfterProductionCompile hook.
3434
* This hook was introduced in Next.js 15.4.1. (https://github.com/vercel/next.js/pull/77345)
3535
*
36+
* @param version - version string to check.
3637
* @returns true if Next.js version is 15.4.1 or higher
3738
*/
38-
export function supportsProductionCompileHook(): boolean {
39-
const version = getNextjsVersion();
40-
if (!version) {
39+
export function supportsProductionCompileHook(version: string): boolean {
40+
const versionToCheck = version;
41+
if (!versionToCheck) {
4142
return false;
4243
}
4344

44-
const { major, minor, patch } = parseSemver(version);
45+
const { major, minor, patch } = parseSemver(versionToCheck);
4546

4647
if (major === undefined || minor === undefined || patch === undefined) {
4748
return false;

packages/nextjs/src/config/withSentryConfig.ts

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -253,52 +253,33 @@ function getFinalConfigObject(
253253
}
254254

255255
let nextMajor: number | undefined;
256-
const isTurbopack = process.env.TURBOPACK;
257-
let isTurbopackSupported = false;
258256
if (nextJsVersion) {
259-
const { major, minor, patch, prerelease } = parseSemver(nextJsVersion);
257+
const { major } = parseSemver(nextJsVersion);
260258
nextMajor = major;
261-
const isSupportedVersion =
262-
major !== undefined &&
263-
minor !== undefined &&
264-
patch !== undefined &&
265-
(major > 15 ||
266-
(major === 15 && minor > 3) ||
267-
(major === 15 && minor === 3 && patch === 0 && prerelease === undefined) ||
268-
(major === 15 && minor === 3 && patch > 0));
269-
isTurbopackSupported = isSupportedVersion;
270-
const isSupportedCanary =
271-
major !== undefined &&
272-
minor !== undefined &&
273-
patch !== undefined &&
274-
prerelease !== undefined &&
275-
major === 15 &&
276-
minor === 3 &&
277-
patch === 0 &&
278-
prerelease.startsWith('canary.') &&
279-
parseInt(prerelease.split('.')[1] || '', 10) >= 28;
280-
const supportsClientInstrumentation = isSupportedCanary || isSupportedVersion;
259+
}
281260

282-
if (!supportsClientInstrumentation && isTurbopack) {
283-
if (process.env.NODE_ENV === 'development') {
284-
// eslint-disable-next-line no-console
285-
console.warn(
286-
`[@sentry/nextjs] WARNING: You are using the Sentry SDK with Turbopack (\`next dev --turbo\`). The Sentry SDK is compatible with Turbopack on Next.js version 15.3.0 or later. You are currently on ${nextJsVersion}. Please upgrade to a newer Next.js version to use the Sentry SDK with Turbopack. Note that the SDK will continue to work for non-Turbopack production builds. This warning is only about dev-mode.`,
287-
);
288-
} else if (process.env.NODE_ENV === 'production') {
289-
// eslint-disable-next-line no-console
290-
console.warn(
291-
`[@sentry/nextjs] WARNING: You are using the Sentry SDK with Turbopack (\`next build --turbo\`). The Sentry SDK is compatible with Turbopack on Next.js version 15.3.0 or later. You are currently on ${nextJsVersion}. Please upgrade to a newer Next.js version to use the Sentry SDK with Turbopack. Note that as Turbopack is still experimental for production builds, some of the Sentry SDK features like source maps will not work. Follow this issue for progress on Sentry + Turbopack: https://github.com/getsentry/sentry-javascript/issues/8105.`,
292-
);
293-
}
261+
const isTurbopack = process.env.TURBOPACK;
262+
const isTurbopackSupported = supportsProductionCompileHook(nextJsVersion ?? '');
263+
264+
if (!isTurbopackSupported && isTurbopack) {
265+
if (process.env.NODE_ENV === 'development') {
266+
// eslint-disable-next-line no-console
267+
console.warn(
268+
`[@sentry/nextjs] WARNING: You are using the Sentry SDK with Turbopack (\`next dev --turbopack\`). The Sentry SDK is compatible with Turbopack on Next.js version 15.4.1 or later. You are currently on ${nextJsVersion}. Please upgrade to a newer Next.js version to use the Sentry SDK with Turbopack.`,
269+
);
270+
} else if (process.env.NODE_ENV === 'production') {
271+
// eslint-disable-next-line no-console
272+
console.warn(
273+
`[@sentry/nextjs] WARNING: You are using the Sentry SDK with Turbopack (\`next build --turbopack\`). The Sentry SDK is compatible with Turbopack on Next.js version 15.4.1 or later. You are currently on ${nextJsVersion}. Please upgrade to a newer Next.js version to use the Sentry SDK with Turbopack.`,
274+
);
294275
}
295276
}
296277

297278
// If not explicitly set, turbopack uses the runAfterProductionCompile hook (as there are no alternatives), webpack does not.
298279
const shouldUseRunAfterProductionCompileHook =
299280
userSentryOptions?.useRunAfterProductionCompileHook ?? (isTurbopack ? true : false);
300281

301-
if (shouldUseRunAfterProductionCompileHook && supportsProductionCompileHook()) {
282+
if (shouldUseRunAfterProductionCompileHook && supportsProductionCompileHook(nextJsVersion ?? '')) {
302283
if (incomingUserNextConfigObject?.compiler?.runAfterProductionCompile === undefined) {
303284
incomingUserNextConfigObject.compiler ??= {};
304285
incomingUserNextConfigObject.compiler.runAfterProductionCompile = async ({ distDir }) => {

packages/nextjs/test/config/util.test.ts

Lines changed: 22 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,169 +1,98 @@
1-
import * as fs from 'fs';
2-
import { afterEach, describe, expect, it, vi } from 'vitest';
1+
import { describe, expect, it } from 'vitest';
32
import * as util from '../../src/config/util';
43

5-
// Mock fs to control what getNextjsVersion reads
6-
vi.mock('fs');
7-
84
describe('util', () => {
95
describe('supportsProductionCompileHook', () => {
10-
afterEach(() => {
11-
vi.restoreAllMocks();
12-
});
13-
146
describe('supported versions', () => {
157
it('returns true for Next.js 15.4.1', () => {
16-
const mockReadFileSync = fs.readFileSync as any;
17-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.1' }));
18-
19-
const result = util.supportsProductionCompileHook();
8+
const result = util.supportsProductionCompileHook('15.4.1');
209
expect(result).toBe(true);
2110
});
2211

2312
it('returns true for Next.js 15.4.2', () => {
24-
const mockReadFileSync = fs.readFileSync as any;
25-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.2' }));
26-
27-
expect(util.supportsProductionCompileHook()).toBe(true);
13+
expect(util.supportsProductionCompileHook('15.4.2')).toBe(true);
2814
});
2915

3016
it('returns true for Next.js 15.5.0', () => {
31-
const mockReadFileSync = fs.readFileSync as any;
32-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.5.0' }));
33-
34-
expect(util.supportsProductionCompileHook()).toBe(true);
17+
expect(util.supportsProductionCompileHook('15.5.0')).toBe(true);
3518
});
3619

3720
it('returns true for Next.js 16.0.0', () => {
38-
const mockReadFileSync = fs.readFileSync as any;
39-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '16.0.0' }));
40-
41-
expect(util.supportsProductionCompileHook()).toBe(true);
21+
expect(util.supportsProductionCompileHook('16.0.0')).toBe(true);
4222
});
4323

4424
it('returns true for Next.js 17.0.0', () => {
45-
const mockReadFileSync = fs.readFileSync as any;
46-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '17.0.0' }));
47-
48-
expect(util.supportsProductionCompileHook()).toBe(true);
25+
expect(util.supportsProductionCompileHook('17.0.0')).toBe(true);
4926
});
5027

5128
it('returns true for supported canary versions', () => {
52-
const mockReadFileSync = fs.readFileSync as any;
53-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.1-canary.42' }));
54-
55-
expect(util.supportsProductionCompileHook()).toBe(true);
29+
expect(util.supportsProductionCompileHook('15.4.1-canary.42')).toBe(true);
5630
});
5731

5832
it('returns true for supported rc versions', () => {
59-
const mockReadFileSync = fs.readFileSync as any;
60-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.1-rc.1' }));
61-
62-
expect(util.supportsProductionCompileHook()).toBe(true);
33+
expect(util.supportsProductionCompileHook('15.4.1-rc.1')).toBe(true);
6334
});
6435
});
6536

6637
describe('unsupported versions', () => {
6738
it('returns false for Next.js 15.4.0', () => {
68-
const mockReadFileSync = fs.readFileSync as any;
69-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.0' }));
70-
71-
expect(util.supportsProductionCompileHook()).toBe(false);
39+
expect(util.supportsProductionCompileHook('15.4.0')).toBe(false);
7240
});
7341

7442
it('returns false for Next.js 15.3.9', () => {
75-
const mockReadFileSync = fs.readFileSync as any;
76-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.3.9' }));
77-
78-
expect(util.supportsProductionCompileHook()).toBe(false);
43+
expect(util.supportsProductionCompileHook('15.3.9')).toBe(false);
7944
});
8045

8146
it('returns false for Next.js 15.0.0', () => {
82-
const mockReadFileSync = fs.readFileSync as any;
83-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.0.0' }));
84-
85-
expect(util.supportsProductionCompileHook()).toBe(false);
47+
expect(util.supportsProductionCompileHook('15.0.0')).toBe(false);
8648
});
8749

8850
it('returns false for Next.js 14.2.0', () => {
89-
const mockReadFileSync = fs.readFileSync as any;
90-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '14.2.0' }));
91-
92-
expect(util.supportsProductionCompileHook()).toBe(false);
51+
expect(util.supportsProductionCompileHook('14.2.0')).toBe(false);
9352
});
9453

9554
it('returns false for unsupported canary versions', () => {
96-
const mockReadFileSync = fs.readFileSync as any;
97-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.0-canary.42' }));
98-
99-
expect(util.supportsProductionCompileHook()).toBe(false);
55+
expect(util.supportsProductionCompileHook('15.4.0-canary.42')).toBe(false);
10056
});
10157
});
10258

10359
describe('edge cases', () => {
10460
it('returns false for invalid version strings', () => {
105-
const mockReadFileSync = fs.readFileSync as any;
106-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: 'invalid.version' }));
107-
108-
expect(util.supportsProductionCompileHook()).toBe(false);
61+
expect(util.supportsProductionCompileHook('invalid.version')).toBe(false);
10962
});
11063

11164
it('handles versions with build metadata', () => {
112-
const mockReadFileSync = fs.readFileSync as any;
113-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.1+build.123' }));
114-
115-
expect(util.supportsProductionCompileHook()).toBe(true);
65+
expect(util.supportsProductionCompileHook('15.4.1+build.123')).toBe(true);
11666
});
11767

11868
it('handles versions with pre-release identifiers', () => {
119-
const mockReadFileSync = fs.readFileSync as any;
120-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.1-alpha.1' }));
121-
122-
expect(util.supportsProductionCompileHook()).toBe(true);
69+
expect(util.supportsProductionCompileHook('15.4.1-alpha.1')).toBe(true);
12370
});
12471

12572
it('returns false for versions missing patch number', () => {
126-
const mockReadFileSync = fs.readFileSync as any;
127-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4' }));
128-
129-
expect(util.supportsProductionCompileHook()).toBe(false);
73+
expect(util.supportsProductionCompileHook('15.4')).toBe(false);
13074
});
13175

13276
it('returns false for versions missing minor number', () => {
133-
const mockReadFileSync = fs.readFileSync as any;
134-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15' }));
135-
136-
expect(util.supportsProductionCompileHook()).toBe(false);
77+
expect(util.supportsProductionCompileHook('15')).toBe(false);
13778
});
13879
});
13980

14081
describe('version boundary tests', () => {
14182
it('returns false for 15.4.0 (just below threshold)', () => {
142-
const mockReadFileSync = fs.readFileSync as any;
143-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.0' }));
144-
145-
expect(util.supportsProductionCompileHook()).toBe(false);
83+
expect(util.supportsProductionCompileHook('15.4.0')).toBe(false);
14684
});
14785

14886
it('returns true for 15.4.1 (exact threshold)', () => {
149-
const mockReadFileSync = fs.readFileSync as any;
150-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.1' }));
151-
152-
expect(util.supportsProductionCompileHook()).toBe(true);
87+
expect(util.supportsProductionCompileHook('15.4.1')).toBe(true);
15388
});
15489

15590
it('returns true for 15.4.2 (just above threshold)', () => {
156-
const mockReadFileSync = fs.readFileSync as any;
157-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.4.2' }));
158-
159-
expect(util.supportsProductionCompileHook()).toBe(true);
91+
expect(util.supportsProductionCompileHook('15.4.2')).toBe(true);
16092
});
16193

16294
it('returns false for 15.3.999 (high patch but wrong minor)', () => {
163-
const mockReadFileSync = fs.readFileSync as any;
164-
mockReadFileSync.mockReturnValue(JSON.stringify({ version: '15.3.999' }));
165-
166-
expect(util.supportsProductionCompileHook()).toBe(false);
95+
expect(util.supportsProductionCompileHook('15.3.999')).toBe(false);
16796
});
16897
});
16998
});

0 commit comments

Comments
 (0)