Skip to content

Commit bb7237a

Browse files
authored
feat(svelte)!: Disable component update tracking by default (#15265)
Due to a change in the lifecycle of Svelte components in Svelte 5 (using Rune mode), our SDK can no longer leverage the `(before|after)Update` hooks to track component update spans. For v9, this patch therefore disables update tracking by default.
1 parent 3c4df06 commit bb7237a

File tree

13 files changed

+57
-95
lines changed

13 files changed

+57
-95
lines changed

dev-packages/e2e-tests/test-applications/sveltekit-2-svelte-5/tests/performance.client.test.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -109,30 +109,6 @@ test.describe('client-specific performance events', () => {
109109
op: 'ui.svelte.init',
110110
origin: 'auto.ui.svelte',
111111
}),
112-
expect.objectContaining({
113-
data: { 'sentry.op': 'ui.svelte.update', 'sentry.origin': 'auto.ui.svelte' },
114-
description: '<components/+page>',
115-
op: 'ui.svelte.update',
116-
origin: 'auto.ui.svelte',
117-
}),
118-
expect.objectContaining({
119-
data: { 'sentry.op': 'ui.svelte.update', 'sentry.origin': 'auto.ui.svelte' },
120-
description: '<Component1>',
121-
op: 'ui.svelte.update',
122-
origin: 'auto.ui.svelte',
123-
}),
124-
expect.objectContaining({
125-
data: { 'sentry.op': 'ui.svelte.update', 'sentry.origin': 'auto.ui.svelte' },
126-
description: '<Component2>',
127-
op: 'ui.svelte.update',
128-
origin: 'auto.ui.svelte',
129-
}),
130-
expect.objectContaining({
131-
data: { 'sentry.op': 'ui.svelte.update', 'sentry.origin': 'auto.ui.svelte' },
132-
description: '<Component3>',
133-
op: 'ui.svelte.update',
134-
origin: 'auto.ui.svelte',
135-
}),
136112
]),
137113
);
138114
});

dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/components/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import Component2 from "./Component2.svelte";
66
import Component3 from "./Component3.svelte";
77
8-
Sentry.trackComponent({componentName: 'components/+page'})
8+
Sentry.trackComponent({componentName: 'components/+page', trackUpdates: true})
99
1010
</script>
1111
<h2>Demonstrating Component Tracking</h2>

dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/components/Component1.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import Component2 from "./Component2.svelte";
33
import {trackComponent} from '@sentry/sveltekit';
44
5-
trackComponent({componentName: 'Component1'});
5+
trackComponent({componentName: 'Component1', trackUpdates: true});
66
77
</script>
88
<h3>Howdy, I'm component 1</h3>

dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/components/Component2.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import Component3 from "./Component3.svelte";
33
import {trackComponent} from '@sentry/sveltekit';
44
5-
trackComponent({componentName: 'Component2'});
5+
trackComponent({componentName: 'Component2', trackUpdates: true});
66
</script>
77
<h3>Howdy, I'm component 2</h3>
88

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import * as Sentry from '@sentry/sveltekit';
3-
Sentry.trackComponent({componentName: 'Component3'});
3+
Sentry.trackComponent({componentName: 'Component3', trackUpdates: true});
44
</script>
55

66
<h3>Howdy, I'm component 3</h3>

packages/svelte/src/config.ts

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { PreprocessorGroup } from 'svelte/types/compiler/preprocess';
33
import { componentTrackingPreprocessor, defaultComponentTrackingOptions } from './preprocessors';
44
import type { SentryPreprocessorGroup, SentrySvelteConfigOptions, SvelteConfig } from './types';
55

6-
const DEFAULT_SENTRY_OPTIONS: SentrySvelteConfigOptions = {
6+
const defaultSentryOptions: SentrySvelteConfigOptions = {
77
componentTracking: defaultComponentTrackingOptions,
88
};
99

@@ -20,32 +20,25 @@ export function withSentryConfig(
2020
sentryOptions?: SentrySvelteConfigOptions,
2121
): SvelteConfig {
2222
const mergedOptions = {
23-
...DEFAULT_SENTRY_OPTIONS,
23+
...defaultSentryOptions,
2424
...sentryOptions,
25+
componentTracking: {
26+
...defaultSentryOptions.componentTracking,
27+
...sentryOptions?.componentTracking,
28+
},
2529
};
2630

2731
const originalPreprocessors = getOriginalPreprocessorArray(originalConfig);
2832

29-
// Map is insertion-order-preserving. It's important to add preprocessors
30-
// to this map in the right order we want to see them being executed.
31-
// see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
32-
const sentryPreprocessors = new Map<string, SentryPreprocessorGroup>();
33-
34-
const shouldTrackComponents = mergedOptions.componentTracking?.trackComponents;
35-
if (shouldTrackComponents) {
36-
const firstPassPreproc: SentryPreprocessorGroup = componentTrackingPreprocessor(mergedOptions.componentTracking);
37-
sentryPreprocessors.set(firstPassPreproc.sentryId || '', firstPassPreproc);
33+
// Bail if users already added the preprocessor
34+
if (originalPreprocessors.find((p: PreprocessorGroup) => !!(p as SentryPreprocessorGroup).sentryId)) {
35+
return originalConfig;
3836
}
3937

40-
// We prioritize user-added preprocessors, so we don't insert sentry processors if they
41-
// have already been added by users.
42-
originalPreprocessors.forEach((p: SentryPreprocessorGroup) => {
43-
if (p.sentryId) {
44-
sentryPreprocessors.delete(p.sentryId);
45-
}
46-
});
47-
48-
const mergedPreprocessors = [...sentryPreprocessors.values(), ...originalPreprocessors];
38+
const mergedPreprocessors = [...originalPreprocessors];
39+
if (mergedOptions.componentTracking.trackComponents) {
40+
mergedPreprocessors.unshift(componentTrackingPreprocessor(mergedOptions.componentTracking));
41+
}
4942

5043
return {
5144
...originalConfig,

packages/svelte/src/constants.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

packages/svelte/src/performance.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/browser';
22
import type { Span } from '@sentry/core';
33
import { afterUpdate, beforeUpdate, onMount } from 'svelte';
44

5-
import { startInactiveSpan } from '@sentry/core';
6-
import { DEFAULT_COMPONENT_NAME, UI_SVELTE_INIT, UI_SVELTE_UPDATE } from './constants';
5+
import { logger, startInactiveSpan } from '@sentry/core';
76
import type { TrackComponentOptions } from './types';
87

98
const defaultTrackComponentOptions: {
@@ -12,7 +11,7 @@ const defaultTrackComponentOptions: {
1211
componentName?: string;
1312
} = {
1413
trackInit: true,
15-
trackUpdates: true,
14+
trackUpdates: false,
1615
};
1716

1817
/**
@@ -29,21 +28,27 @@ export function trackComponent(options?: TrackComponentOptions): void {
2928

3029
const customComponentName = mergedOptions.componentName;
3130

32-
const componentName = `<${customComponentName || DEFAULT_COMPONENT_NAME}>`;
31+
const componentName = `<${customComponentName || 'Svelte Component'}>`;
3332

3433
if (mergedOptions.trackInit) {
3534
recordInitSpan(componentName);
3635
}
3736

3837
if (mergedOptions.trackUpdates) {
39-
recordUpdateSpans(componentName);
38+
try {
39+
recordUpdateSpans(componentName);
40+
} catch {
41+
logger.warn(
42+
"Cannot track component updates. This is likely because you're using Svelte 5 in Runes mode. Set `trackUpdates: false` in `withSentryConfig` or `trackComponent` to disable this warning.",
43+
);
44+
}
4045
}
4146
}
4247

4348
function recordInitSpan(componentName: string): void {
4449
const initSpan = startInactiveSpan({
4550
onlyIfParent: true,
46-
op: UI_SVELTE_INIT,
51+
op: 'ui.svelte.init',
4752
name: componentName,
4853
attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.svelte' },
4954
});
@@ -58,7 +63,7 @@ function recordUpdateSpans(componentName: string): void {
5863
beforeUpdate(() => {
5964
updateSpan = startInactiveSpan({
6065
onlyIfParent: true,
61-
op: UI_SVELTE_UPDATE,
66+
op: 'ui.svelte.update',
6267
name: componentName,
6368
attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.svelte' },
6469
});

packages/svelte/src/preprocessors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { ComponentTrackingInitOptions, SentryPreprocessorGroup, TrackCompon
66
export const defaultComponentTrackingOptions: Required<ComponentTrackingInitOptions> = {
77
trackComponents: true,
88
trackInit: true,
9-
trackUpdates: true,
9+
trackUpdates: false,
1010
};
1111

1212
export const FIRST_PASS_COMPONENT_TRACKING_PREPROC_ID = 'FIRST_PASS_COMPONENT_TRACKING_PREPROCESSOR';

packages/svelte/src/types.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,18 @@ export type SpanOptions = {
2929
* onMount lifecycle hook. This span tells how long it takes a component
3030
* to be created and inserted into the DOM.
3131
*
32-
* Defaults to true if component tracking is enabled
32+
* @default `true` if component tracking is enabled
3333
*/
3434
trackInit?: boolean;
3535

3636
/**
3737
* If true, a span is recorded between a component's beforeUpdate and afterUpdate
3838
* lifecycle hooks.
3939
*
40-
* Defaults to true if component tracking is enabled
40+
* Caution: Component updates can only be tracked in Svelte versions prior to version 5
41+
* or in Svelte 5 in legacy mode (i.e. without Runes).
42+
*
43+
* @default `false` if component tracking is enabled
4144
*/
4245
trackUpdates?: boolean;
4346
};

0 commit comments

Comments
 (0)