Skip to content

Commit 2b36cab

Browse files
authored
feat(nextjs): Make tracing package treeshakable (#5166)
1 parent 549512d commit 2b36cab

File tree

8 files changed

+70
-28
lines changed

8 files changed

+70
-28
lines changed

MIGRATION.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,8 @@ For our efforts to reduce bundle size of the SDK we had to remove and refactor p
351351
- Removed `eventStatusFromHttpCode` to save on bundle size.
352352
- Replace `BrowserTracing` `maxTransactionDuration` option with `finalTimeout` option
353353
- Removed `ignoreSentryErrors` option from AWS lambda SDK. Errors originating from the SDK will now *always* be caught internally.
354+
- Removed `Integrations.BrowserTracing` export from `@sentry/nextjs`. Please import `BrowserTracing` from `@sentry/nextjs` directly.
355+
- Removed static `id` property from `BrowserTracing` integration.
354356

355357
## Sentry Angular SDK Changes
356358

packages/ember/addon/instance-initializers/sentry-performance.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,22 @@ export async function instrumentForPerformance(appInstance: ApplicationInstance)
380380
}),
381381
];
382382

383-
if (isTesting() && Sentry.getCurrentHub()?.getIntegration(tracing.Integrations.BrowserTracing)) {
383+
class FakeBrowserTracingClass {
384+
static id = tracing.BROWSER_TRACING_INTEGRATION_ID;
385+
public name = FakeBrowserTracingClass.id;
386+
setupOnce() {
387+
// noop - We're just faking this class for a lookup
388+
}
389+
}
390+
391+
if (
392+
isTesting() &&
393+
Sentry.getCurrentHub()?.getIntegration(
394+
// This is a temporary hack because the BrowserTracing integration cannot have a static `id` field for tree
395+
// shaking reasons. However, `getIntegration` needs that field.
396+
FakeBrowserTracingClass,
397+
)
398+
) {
384399
// Initializers are called more than once in tests, causing the integrations to not be setup correctly.
385400
return;
386401
}

packages/nextjs/src/index.client.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { configureScope, init as reactInit, Integrations as BrowserIntegrations } from '@sentry/react';
1+
import { configureScope, init as reactInit, Integrations } from '@sentry/react';
22
import { BrowserTracing, defaultRequestInstrumentationOptions } from '@sentry/tracing';
33
import { EventProcessor } from '@sentry/types';
44

@@ -10,12 +10,8 @@ import { addIntegration, UserIntegrations } from './utils/userIntegrations';
1010
export * from '@sentry/react';
1111
export { nextRouterInstrumentation } from './performance/client';
1212

13-
export const Integrations = { ...BrowserIntegrations, BrowserTracing };
13+
export { Integrations };
1414

15-
// This is already exported as part of `Integrations` above (and for the moment will remain so for
16-
// backwards compatibility), but that interferes with treeshaking, so we also export it separately
17-
// here.
18-
//
1915
// Previously we expected users to import `BrowserTracing` like this:
2016
//
2117
// import { Integrations } from '@sentry/nextjs';
@@ -28,16 +24,23 @@ export const Integrations = { ...BrowserIntegrations, BrowserTracing };
2824
// const instance = new BrowserTracing();
2925
export { BrowserTracing };
3026

27+
// Treeshakable guard to remove all code related to tracing
28+
declare const __SENTRY_TRACING__: boolean;
29+
3130
/** Inits the Sentry NextJS SDK on the browser with the React SDK. */
3231
export function init(options: NextjsOptions): void {
3332
buildMetadata(options, ['nextjs', 'react']);
3433
options.environment = options.environment || process.env.NODE_ENV;
3534

36-
// Only add BrowserTracing if a tracesSampleRate or tracesSampler is set
37-
const integrations =
38-
options.tracesSampleRate === undefined && options.tracesSampler === undefined
39-
? options.integrations
40-
: createClientIntegrations(options.integrations);
35+
let integrations = options.integrations;
36+
37+
// Guard below evaluates to true unless __SENTRY_TRACING__ is text-replaced with "false"
38+
if (typeof __SENTRY_TRACING__ === 'undefined' || __SENTRY_TRACING__) {
39+
// Only add BrowserTracing if a tracesSampleRate or tracesSampler is set
40+
if (options.tracesSampleRate !== undefined || options.tracesSampler !== undefined) {
41+
integrations = createClientIntegrations(options.integrations);
42+
}
43+
}
4144

4245
reactInit({
4346
...options,
@@ -53,12 +56,12 @@ export function init(options: NextjsOptions): void {
5356
});
5457
}
5558

56-
const defaultBrowserTracingIntegration = new BrowserTracing({
57-
tracingOrigins: [...defaultRequestInstrumentationOptions.tracingOrigins, /^(api\/)/],
58-
routingInstrumentation: nextRouterInstrumentation,
59-
});
60-
6159
function createClientIntegrations(integrations?: UserIntegrations): UserIntegrations {
60+
const defaultBrowserTracingIntegration = new BrowserTracing({
61+
tracingOrigins: [...defaultRequestInstrumentationOptions.tracingOrigins, /^(api\/)/],
62+
routingInstrumentation: nextRouterInstrumentation,
63+
});
64+
6265
if (integrations) {
6366
return addIntegration(defaultBrowserTracingIntegration, integrations, {
6467
BrowserTracing: { keyPath: 'options.routingInstrumentation', value: nextRouterInstrumentation },

packages/tracing/src/browser/browsertracing.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
} from './request';
1616
import { instrumentRoutingWithDefaults } from './router';
1717

18+
export const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';
19+
1820
/** Options for Browser Tracing integration */
1921
export interface BrowserTracingOptions extends RequestInstrumentationOptions {
2022
/**
@@ -111,18 +113,18 @@ const DEFAULT_BROWSER_TRACING_OPTIONS = {
111113
* any routing library. This integration uses {@see IdleTransaction} to create transactions.
112114
*/
113115
export class BrowserTracing implements Integration {
114-
/**
115-
* @inheritDoc
116-
*/
117-
public static id: string = 'BrowserTracing';
116+
// This class currently doesn't have a static `id` field like the other integration classes, because it prevented
117+
// @sentry/tracing from being treeshaken. Tree shakers do not like static fields, because they behave like side effects.
118+
// TODO: Come up with a better plan, than using static fields on integration classes, and use that plan on all
119+
// integrations.
118120

119121
/** Browser Tracing integration options */
120122
public options: BrowserTracingOptions;
121123

122124
/**
123125
* @inheritDoc
124126
*/
125-
public name: string = BrowserTracing.id;
127+
public name: string = BROWSER_TRACING_INTEGRATION_ID;
126128

127129
private _getCurrentHub?: () => Hub;
128130

packages/tracing/src/browser/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export type { RequestInstrumentationOptions } from './request';
22

3-
export { BrowserTracing } from './browsertracing';
3+
export { BrowserTracing, BROWSER_TRACING_INTEGRATION_ID } from './browsertracing';
44
export { instrumentOutgoingRequests, defaultRequestInstrumentationOptions } from './request';

packages/tracing/src/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export { Integrations };
2222
// const instance = new BrowserTracing();
2323
//
2424
// For an example of of the new usage of BrowserTracing, see @sentry/nextjs index.client.ts
25-
export { BrowserTracing } from './browser';
25+
export { BrowserTracing, BROWSER_TRACING_INTEGRATION_ID } from './browser';
2626

2727
export { Span, spanStatusfromHttpCode } from './span';
2828
// eslint-disable-next-line deprecation/deprecation
@@ -32,8 +32,14 @@ export { instrumentOutgoingRequests, defaultRequestInstrumentationOptions } from
3232
export { IdleTransaction } from './idletransaction';
3333
export { startIdleTransaction } from './hubextensions';
3434

35-
// We are patching the global object with our hub extension methods
36-
addExtensionMethods();
35+
// Treeshakable guard to remove all code related to tracing
36+
declare const __SENTRY_TRACING__: boolean;
37+
38+
// Guard for tree
39+
if (typeof __SENTRY_TRACING__ === 'undefined' || __SENTRY_TRACING__) {
40+
// We are patching the global object with our hub extension methods
41+
addExtensionMethods();
42+
}
3743

3844
export { addExtensionMethods };
3945

packages/tracing/test/index.bundle.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@ import { Integrations } from '../src/index.bundle';
33
describe('Integrations export', () => {
44
it('is exported correctly', () => {
55
Object.keys(Integrations).forEach(key => {
6-
expect(Integrations[key as keyof typeof Integrations].id).toStrictEqual(expect.any(String));
6+
// Skip BrowserTracing because it doesn't have a static id field.
7+
if (key === 'BrowserTracing') {
8+
return;
9+
}
10+
11+
expect(Integrations[key as keyof Omit<typeof Integrations, 'BrowserTracing'>].id).toStrictEqual(
12+
expect.any(String),
13+
);
714
});
815
});
916
});

packages/tracing/test/index.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ describe('index', () => {
1212
describe('Integrations', () => {
1313
it('is exported correctly', () => {
1414
Object.keys(Integrations).forEach(key => {
15-
expect(Integrations[key as keyof typeof Integrations].id).toStrictEqual(expect.any(String));
15+
// Skip BrowserTracing because it doesn't have a static id field.
16+
if (key === 'BrowserTracing') {
17+
return;
18+
}
19+
20+
expect(Integrations[key as keyof Omit<typeof Integrations, 'BrowserTracing'>].id).toStrictEqual(
21+
expect.any(String),
22+
);
1623
});
1724
});
1825

0 commit comments

Comments
 (0)