Skip to content

Commit 58a36e4

Browse files
authored
feat(svelte): Add Svelte 5 support (#11807)
Update our Svelte and SvelteKit SDKs to support Svelte 5 Concrete changes and adjustments: - Removed `current_component` import from Svelte SDK `trackComponent` function, due to the export no longer being available in Svelte 5 - Added a dummy/no-op `trackComponent` utility to the Server-side of the SvelteKit SDK. Component tracking doesn't make much sense in SSR but only in client-side hydration and subsequent navigations. With this change, users can now manually call `trackComponent` within their pages/components. - Adjusted peer dependencies in the Svelte SDK to permit `svelte@5.x` whenever it's released. I don't think we should add the preview versions here but happy to change/remove for now if reviewers prefer. - Added SvelteKit 2 + Svelte 5 E2E test app with latest preview release with all the tests from the older SvelteKit E2E test apps. Also added a test for manual component tracking and backported it to the other Sveltekit E2E tests
1 parent 7eef5df commit 58a36e4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1561
-11
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,7 @@ jobs:
10081008
'standard-frontend-react',
10091009
'sveltekit',
10101010
'sveltekit-2',
1011+
'sveltekit-2-svelte-5',
10111012
'generic-ts3.8',
10121013
'node-fastify-app',
10131014
# TODO(v8): Re-enable hapi tests
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.DS_Store
2+
node_modules
3+
/build
4+
/.svelte-kit
5+
/package
6+
.env
7+
.env.*
8+
!.env.example
9+
vite.config.js.timestamp-*
10+
vite.config.ts.timestamp-*
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# create-svelte
2+
3+
Everything you need to build a Svelte project, powered by
4+
[`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
5+
6+
## Creating a project
7+
8+
If you're seeing this, you've probably already done this step. Congrats!
9+
10+
```bash
11+
# create a new project in the current directory
12+
npm create svelte@latest
13+
14+
# create a new project in my-app
15+
npm create svelte@latest my-app
16+
```
17+
18+
## Developing
19+
20+
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a
21+
development server:
22+
23+
```bash
24+
npm run dev
25+
26+
# or start the server and open the app in a new browser tab
27+
npm run dev -- --open
28+
```
29+
30+
## Building
31+
32+
To create a production version of your app:
33+
34+
```bash
35+
npm run build
36+
```
37+
38+
You can preview the production build with `npm run preview`.
39+
40+
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target
41+
> environment.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "sveltekit-2-svelte-5",
3+
"version": "0.0.1",
4+
"private": true,
5+
"scripts": {
6+
"dev": "vite dev",
7+
"build": "vite build",
8+
"preview": "vite preview",
9+
"proxy": "node start-event-proxy.cjs",
10+
"clean": "npx rimraf node_modules,pnpm-lock.yaml",
11+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13+
"test:prod": "TEST_ENV=production playwright test",
14+
"test:build": "pnpm install && npx playwright install && pnpm build",
15+
"test:assert": "pnpm test:prod"
16+
},
17+
"dependencies": {
18+
"@sentry/sveltekit": "latest || *",
19+
"@spotlightjs/spotlight": "2.0.0-alpha.1"
20+
},
21+
"devDependencies": {
22+
"@playwright/test": "^1.36.2",
23+
"@sentry-internal/event-proxy-server": "link:../../../event-proxy-server",
24+
"@sentry/types": "latest || *",
25+
"@sentry/utils": "latest || *",
26+
"@sveltejs/adapter-auto": "^3.0.0",
27+
"@sveltejs/kit": "^2.0.0",
28+
"@sveltejs/vite-plugin-svelte": "^3.0.0",
29+
"svelte": "^5.0.0-next.115",
30+
"svelte-check": "^3.6.0",
31+
"ts-node": "10.9.1",
32+
"tslib": "^2.4.1",
33+
"typescript": "^5.0.0",
34+
"vite": "^5.0.3",
35+
"wait-port": "1.0.4"
36+
},
37+
"type": "module"
38+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import type { PlaywrightTestConfig } from '@playwright/test';
2+
import { devices } from '@playwright/test';
3+
4+
// Fix urls not resolving to localhost on Node v17+
5+
// See: https://github.com/axios/axios/issues/3821#issuecomment-1413727575
6+
import { setDefaultResultOrder } from 'dns';
7+
setDefaultResultOrder('ipv4first');
8+
9+
const testEnv = process.env.TEST_ENV;
10+
11+
if (!testEnv) {
12+
throw new Error('No test env defined');
13+
}
14+
15+
const svelteKitPort = 3030;
16+
const eventProxyPort = 3031;
17+
18+
/**
19+
* See https://playwright.dev/docs/test-configuration.
20+
*/
21+
const config: PlaywrightTestConfig = {
22+
testDir: './test',
23+
/* Maximum time one test can run for. */
24+
timeout: 150_000,
25+
expect: {
26+
/**
27+
* Maximum time expect() should wait for the condition to be met.
28+
* For example in `await expect(locator).toHaveText();`
29+
*/
30+
timeout: 10000,
31+
},
32+
/* Run tests in files in parallel */
33+
fullyParallel: false,
34+
workers: 1,
35+
/* Fail the build on CI if you accidentally left test.only in the source code. */
36+
forbidOnly: !!process.env.CI,
37+
/* `next dev` is incredibly buggy with the app dir */
38+
retries: testEnv === 'development' ? 3 : 0,
39+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
40+
reporter: 'list',
41+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
42+
use: {
43+
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
44+
actionTimeout: 0,
45+
/* Base URL to use in actions like `await page.goto('/')`. */
46+
baseURL: `http://localhost:${svelteKitPort}`,
47+
48+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
49+
trace: 'on-first-retry',
50+
},
51+
52+
/* Configure projects for major browsers */
53+
projects: [
54+
{
55+
name: 'chromium',
56+
use: {
57+
...devices['Desktop Chrome'],
58+
},
59+
},
60+
],
61+
62+
/* Run your local dev server before starting the tests */
63+
webServer: [
64+
{
65+
command: 'node start-event-proxy.cjs',
66+
port: eventProxyPort,
67+
reuseExistingServer: false,
68+
},
69+
{
70+
command: `pnpm wait-port ${eventProxyPort} && pnpm preview --port ${svelteKitPort}`,
71+
port: svelteKitPort,
72+
reuseExistingServer: false,
73+
},
74+
],
75+
};
76+
77+
export default config;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// See https://kit.svelte.dev/docs/types#app
2+
// for information about these interfaces
3+
declare global {
4+
namespace App {
5+
// interface Error {}
6+
// interface Locals {}
7+
// interface PageData {}
8+
// interface PageState {}
9+
// interface Platform {}
10+
}
11+
}
12+
13+
export {};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
%sveltekit.head%
8+
</head>
9+
<body data-sveltekit-preload-data="hover">
10+
<div style="display: contents">%sveltekit.body%</div>
11+
</body>
12+
</html>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { env } from '$env/dynamic/public';
2+
import * as Sentry from '@sentry/sveltekit';
3+
import * as Spotlight from '@spotlightjs/spotlight';
4+
5+
Sentry.init({
6+
environment: 'qa', // dynamic sampling bias to keep transactions
7+
dsn: env.PUBLIC_E2E_TEST_DSN,
8+
debug: true,
9+
tunnel: `http://localhost:3031/`, // proxy server
10+
tracesSampleRate: 1.0,
11+
});
12+
13+
const myErrorHandler = ({ error, event }: any) => {
14+
console.error('An error occurred on the client side:', error, event);
15+
};
16+
17+
export const handleError = Sentry.handleErrorWithSentry(myErrorHandler);
18+
19+
if (import.meta.env.DEV) {
20+
Spotlight.init({
21+
injectImmediately: true,
22+
});
23+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { E2E_TEST_DSN } from '$env/static/private';
2+
import * as Sentry from '@sentry/sveltekit';
3+
import { setupSidecar } from '@spotlightjs/spotlight/sidecar';
4+
5+
Sentry.init({
6+
environment: 'qa', // dynamic sampling bias to keep transactions
7+
dsn: E2E_TEST_DSN,
8+
debug: true,
9+
tunnel: `http://localhost:3031/`, // proxy server
10+
tracesSampleRate: 1.0,
11+
spotlight: import.meta.env.DEV,
12+
});
13+
14+
// not logging anything to console to avoid noise in the test output
15+
export const handleError = Sentry.handleErrorWithSentry(() => {});
16+
17+
export const handle = Sentry.sentryHandle();
18+
19+
if (import.meta.env.DEV) {
20+
setupSidecar();
21+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script lang="ts">
2+
import { onMount } from "svelte";
3+
4+
onMount(() => {
5+
// Indicate that the SvelteKit app was hydrated
6+
document.body.classList.add("hydrated");
7+
});
8+
9+
10+
</script>
11+
12+
<h1>Sveltekit E2E Test app</h1>
13+
<div data-sveltekit-preload-data="off">
14+
<slot></slot>
15+
</div>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<h1>Welcome to SvelteKit 2 with Svelte 5!</h1>
2+
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
3+
4+
<ul>
5+
<li>
6+
<a href="/client-error">Client error</a>
7+
</li>
8+
<li>
9+
<a href="/universal-load-error">Universal Load error</a>
10+
</li>
11+
<li>
12+
<a href="/server-load-error">Server Load error</a>
13+
</li>
14+
<li>
15+
<a href="/server-route-error">Server Route error</a>
16+
</li>
17+
<li>
18+
<a id="routeWithParamsLink" href="/users/123abc">Route with Params</a>
19+
</li>
20+
<li>
21+
<a href="/users">Route with Server Load</a>
22+
</li>
23+
<li>
24+
<a href="/universal-load-fetch">Route with fetch in universal load</a>
25+
</li>
26+
<li>
27+
<a id="redirectLink" href="/redirect1">Redirect</a>
28+
</li>
29+
<li>
30+
<a href="/server-load-fetch">Route with nested fetch in server load</a>
31+
</li>
32+
<li>
33+
<a href="/nav1">Nav 1</a>
34+
</li>
35+
<li>
36+
<a href="/nav2">Nav 2</a>
37+
</li>
38+
<li>
39+
<a href="components">Component Tracking</a>
40+
</li>
41+
</ul>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const GET = () => {
2+
return new Response(JSON.stringify({ users: ['alice', 'bob', 'carol'] }));
3+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { PageServerLoad } from './$types';
2+
3+
export const load = (async _event => {
4+
return { name: 'building (server)' };
5+
}) satisfies PageServerLoad;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<script lang="ts">
2+
import * as Sentry from '@sentry/sveltekit';
3+
4+
async function getSentryData() {
5+
Sentry.startSpan({
6+
name: 'Example Frontend Span',
7+
}, async () => {
8+
const res = await fetch('/sentry-example');
9+
if (!res.ok) {
10+
throw new Error('Sentry Example Frontend Error');
11+
}
12+
})
13+
}
14+
</script>
15+
16+
<h1>Check Build</h1>
17+
18+
<p>
19+
This route only exists to check that Typescript definitions
20+
and auto instrumentation are working when the project is built.
21+
</p>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { PageLoad } from './$types';
2+
3+
export const load = (async _event => {
4+
return { name: 'building' };
5+
}) satisfies PageLoad;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script lang="ts">
2+
function throwError() {
3+
throw new Error('Click Error');
4+
}
5+
</script>
6+
7+
<h1>Client error</h1>
8+
9+
<button on:click={throwError}>Throw error</button>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script>
2+
import * as Sentry from '@sentry/sveltekit';
3+
4+
import Component1 from "./Component1.svelte";
5+
import Component2 from "./Component2.svelte";
6+
import Component3 from "./Component3.svelte";
7+
8+
Sentry.trackComponent({componentName: 'components/+page'})
9+
10+
</script>
11+
<h2>Demonstrating Component Tracking</h2>
12+
13+
<Component1></Component1>
14+
<Component2></Component2>
15+
<Component3></Component3>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
import Component2 from "./Component2.svelte";
3+
import {trackComponent} from '@sentry/sveltekit';
4+
5+
trackComponent({componentName: 'Component1'});
6+
7+
</script>
8+
<h3>Howdy, I'm component 1</h3>
9+
10+
<Component2></Component2>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
import Component3 from "./Component3.svelte";
3+
import {trackComponent} from '@sentry/sveltekit';
4+
5+
trackComponent({componentName: 'Component2'});
6+
</script>
7+
<h3>Howdy, I'm component 2</h3>
8+
9+
<Component3></Component3>

0 commit comments

Comments
 (0)