Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script lang="ts">
let responses = $state(0);

$effect(() => {
fetch('/api/users').then(() => {
responses++;
});
});
</script>

<p id="effect-fetch-responses">responses: {responses}</p>
<a href="/effect-fetch?q=1">Same route, new query</a>
<a href="/nav1">Leave page</a>
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,23 @@ test.describe('client-specific performance events', () => {
);
});
});

test('fetch instrumentation does not make effects re-run on navigation', async ({ page }) => {
const effectFetches: string[] = [];
page.on('request', request => {
if (new URL(request.url()).pathname === '/api/users') {
effectFetches.push(request.url());
}
});

await waitForInitialPageload(page, { route: '/effect-fetch' });
await expect(page.locator('#effect-fetch-responses')).toHaveText('responses: 1');

await page.getByText('Same route, new query').click();
await page.waitForURL('**/effect-fetch?q=1');

await page.getByText('Leave page').click();
await expect(page.getByText('Navigation 1')).toBeVisible();

expect(effectFetches).toHaveLength(1);
});
8 changes: 7 additions & 1 deletion packages/sveltekit/rollup.npm.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ export default makeNPMConfigVariants(
packageSpecificConfig: {
// Keep the variant subpath external so the transpiled output preserves the import for the
// consumer to resolve (via `exports` or the `sentrySvelteKit()` plugin).
external: ['$app/state', '$app/stores', '@sentry/sveltekit/browser-tracing-variant', 'cloudflare:workers'],
external: [
'svelte',
'$app/state',
'$app/stores',
'@sentry/sveltekit/browser-tracing-variant',
'cloudflare:workers',
],
output: {
dynamicImportInCjs: true,
},
Expand Down
5 changes: 4 additions & 1 deletion packages/sveltekit/src/client/navigationState.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Navigation } from '@sveltejs/kit';
import { navigating, page } from '$app/state';
import { untrack } from 'svelte';

declare const $effect: {
(callback: () => void): void;
Expand Down Expand Up @@ -31,9 +32,11 @@ export function onNavigationChange(callback: (navigation: Navigation | null) =>
* Reads the current navigation synchronously. `$effect`s are always batched to a microtask, which is
* too late to catch SvelteKit's synchronous data-request `fetch` at navigation start; a synchronous
* rune read lets us start the navigation span before that request so it propagates the right trace.
* The read is untracked: the `fetch` wrapper calls this from user code, often inside a `$effect`,
* and a tracked read would make that effect re-run on every navigation.
*/
export function getCurrentNavigation(): Navigation | null {
return _snapshot();
return untrack(_snapshot);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to double-check: This file is only pulled in on Svelte 5, correct? Just to make sure we don't break someone on Svelte 4 where I think this function wasn't available.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, just used on svelte5BrowserTracing.ts

}

function _snapshot(): Navigation | null {
Expand Down
7 changes: 7 additions & 0 deletions packages/sveltekit/src/client/svelte5.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// The package is type-checked against Svelte 4, but the Kit 3 variant only ever runs on Svelte 5.
// Declares the Svelte 5 export it uses; build-time only and never emitted.
export {};

declare module 'svelte' {
export function untrack<T>(fn: () => T): T;
}
Loading