Skip to content

Commit da1c41f

Browse files
authored
feat(nextjs): Emit warning for conflicting treeshaking / debug settings (#18638)
With this PR we emit a warning for client, node and edge whenever the user sets `debug: true` in `init` but at the same time treeshakes logging statements using webpack. This will not emit anything for turbopack. closes https://linear.app/getsentry/issue/FE-610/warn-at-build-time-for-conflicting-disablelogger-and-debug-settings-in
1 parent fdbddaa commit da1c41f

4 files changed

Lines changed: 107 additions & 0 deletions

File tree

packages/nextjs/src/client/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Client, EventProcessor, Integration } from '@sentry/core';
55
import { addEventProcessor, applySdkMetadata, consoleSandbox, getGlobalScope, GLOBAL_OBJ } from '@sentry/core';
66
import type { BrowserOptions } from '@sentry/react';
77
import { getDefaultIntegrations as getReactDefaultIntegrations, init as reactInit } from '@sentry/react';
8+
import { DEBUG_BUILD } from '../common/debug-build';
89
import { devErrorSymbolicationEventProcessor } from '../common/devErrorSymbolicationEventProcessor';
910
import { getVercelEnv } from '../common/getVercelEnv';
1011
import { isRedirectNavigationError } from '../common/nextNavigationErrorUtils';
@@ -48,6 +49,15 @@ export function init(options: BrowserOptions): Client | undefined {
4849
}
4950
clientIsInitialized = true;
5051

52+
if (!DEBUG_BUILD && options.debug) {
53+
consoleSandbox(() => {
54+
// eslint-disable-next-line no-console
55+
console.warn(
56+
'[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `withSentryConfig({ disableLogger: true })` / `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.',
57+
);
58+
});
59+
}
60+
5161
// Remove cached trace meta tags for ISR/SSG pages before initializing
5262
// This prevents the browser tracing integration from using stale trace IDs
5363
if (typeof __SENTRY_TRACING__ === 'undefined' || __SENTRY_TRACING__) {

packages/nextjs/src/edge/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
import { getScopesFromContext } from '@sentry/opentelemetry';
2323
import type { VercelEdgeOptions } from '@sentry/vercel-edge';
2424
import { getDefaultIntegrations, init as vercelEdgeInit } from '@sentry/vercel-edge';
25+
import { DEBUG_BUILD } from '../common/debug-build';
2526
import { ATTR_NEXT_SPAN_TYPE } from '../common/nextSpanAttributes';
2627
import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../common/span-attributes-with-logic-attached';
2728
import { addHeadersAsAttributes } from '../common/utils/addHeadersAsAttributes';
@@ -55,6 +56,13 @@ export function init(options: VercelEdgeOptions = {}): void {
5556
return;
5657
}
5758

59+
if (!DEBUG_BUILD && options.debug) {
60+
// eslint-disable-next-line no-console
61+
console.warn(
62+
'[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `withSentryConfig({ disableLogger: true })` / `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.',
63+
);
64+
}
65+
5866
const customDefaultIntegrations = getDefaultIntegrations(options);
5967

6068
// This value is injected at build time, based on the output directory specified in the build config. Though a default

packages/nextjs/src/server/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ export function init(options: NodeOptions): NodeClient | undefined {
9696
return;
9797
}
9898

99+
if (!DEBUG_BUILD && options.debug) {
100+
// eslint-disable-next-line no-console
101+
console.warn(
102+
'[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `withSentryConfig({ disableLogger: true })` / `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.',
103+
);
104+
}
105+
99106
const customDefaultIntegrations = getDefaultIntegrations(options)
100107
.filter(integration => integration.name !== 'Http')
101108
.concat(
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { JSDOM } from 'jsdom';
2+
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
3+
4+
const TEST_DSN = 'https://public@dsn.ingest.sentry.io/1337';
5+
6+
function didWarnAboutDebugRemoved(warnSpy: ReturnType<typeof vi.spyOn>): boolean {
7+
return warnSpy.mock.calls.some(call =>
8+
call.some(
9+
arg =>
10+
typeof arg === 'string' &&
11+
arg.includes('You have enabled `debug: true`') &&
12+
arg.includes('debug logging was removed from your bundle'),
13+
),
14+
);
15+
}
16+
17+
describe('debug: true + removeDebugLogging warning', () => {
18+
let dom: JSDOM;
19+
let originalDocument: unknown;
20+
let originalLocation: unknown;
21+
let originalAddEventListener: unknown;
22+
23+
beforeAll(() => {
24+
dom = new JSDOM('<!doctype html><html><head></head><body></body></html>', { url: 'https://example.com/' });
25+
26+
originalDocument = (globalThis as any).document;
27+
originalLocation = (globalThis as any).location;
28+
originalAddEventListener = (globalThis as any).addEventListener;
29+
30+
Object.defineProperty(globalThis, 'document', { value: dom.window.document, writable: true });
31+
Object.defineProperty(globalThis, 'location', { value: dom.window.location, writable: true });
32+
Object.defineProperty(globalThis, 'addEventListener', { value: () => undefined, writable: true });
33+
});
34+
35+
afterAll(() => {
36+
Object.defineProperty(globalThis, 'document', { value: originalDocument, writable: true });
37+
Object.defineProperty(globalThis, 'location', { value: originalLocation, writable: true });
38+
Object.defineProperty(globalThis, 'addEventListener', { value: originalAddEventListener, writable: true });
39+
});
40+
41+
afterEach(() => {
42+
vi.restoreAllMocks();
43+
vi.resetModules();
44+
vi.unmock('../../src/common/debug-build.js');
45+
delete process.env.NEXT_OTEL_FETCH_DISABLED;
46+
delete process.env.NEXT_PHASE;
47+
});
48+
49+
it('warns on client/server/edge when debug is true but DEBUG_BUILD is false', async () => {
50+
vi.doMock('../../src/common/debug-build.js', () => ({ DEBUG_BUILD: false }));
51+
52+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
53+
54+
const client = await import('../../src/client/index.js');
55+
client.init({ dsn: TEST_DSN, debug: true } as any);
56+
57+
const server = await import('../../src/server/index.js');
58+
server.init({ dsn: TEST_DSN, debug: true } as any);
59+
60+
const edge = await import('../../src/edge/index.js');
61+
edge.init({ dsn: TEST_DSN, debug: true } as any);
62+
63+
expect(didWarnAboutDebugRemoved(warnSpy)).toBe(true);
64+
});
65+
66+
it('does not emit that warning when DEBUG_BUILD is true', async () => {
67+
vi.doMock('../../src/common/debug-build.js', () => ({ DEBUG_BUILD: true }));
68+
69+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
70+
71+
const client = await import('../../src/client/index.js');
72+
client.init({ dsn: TEST_DSN, debug: true } as any);
73+
74+
const server = await import('../../src/server/index.js');
75+
server.init({ dsn: TEST_DSN, debug: true } as any);
76+
77+
const edge = await import('../../src/edge/index.js');
78+
edge.init({ dsn: TEST_DSN, debug: true } as any);
79+
80+
expect(didWarnAboutDebugRemoved(warnSpy)).toBe(false);
81+
});
82+
});

0 commit comments

Comments
 (0)