Skip to content

Commit 8e9839a

Browse files
feature: Replace sveltekit:* with valid HTML attributes like data-sveltekit-* (#6170)
* WIP: Replace `sveltekit:prefetch` with `data-sveltekit-prefetch` at build time. * WIP: Use svelte-preprocess to replace values. Significant progress! PoC works great if run from the user's svelte.config.js, but we need to extend the user config and still make it work. Currently it only works when run with the default svelte config loading. * Improve attribute replacement and make it work even if app devs have custom preprocessing config. Auto-reloading doesn't work though, so that needs to be fixed, along with regex specificity. * WIP: Explore how to combine the svelte config by the user with the options needed by sveltekit. * Improve type definition for `config.preprocess` to match what's used internally. Also allow object configs. * Use API from vite-plugin-svelte to add internal SvelteKit preprocessing Much cleaner solution, which also should be a tiny bit more performant than before. * Cleanup * Breaking: Rename sveltekit:prefetch to data-sveltekit-precfetch * Breaking: Rename sveltekit:noscroll to data-sveltekit-noscroll * Breaking: Rename sveltekit:reload to data-sveltekit-reload * print console error for removed attributes in dev * lint * Update packages/kit/types/index.d.ts * Update packages/kit/types/index.d.ts * Create neat-pots-flash.md Co-authored-by: Rich Harris <[email protected]>
1 parent 3d12949 commit 8e9839a

File tree

14 files changed

+60
-30
lines changed

14 files changed

+60
-30
lines changed

Diff for: .changeset/neat-pots-flash.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"create-svelte": patch
3+
"@sveltejs/kit": patch
4+
---
5+
6+
[breaking] Replace `sveltekit:*` with valid HTML attributes like `data-sveltekit-*`

Diff for: documentation/docs/09-a-options.md

+9-9
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22
title: Anchor options
33
---
44

5-
### sveltekit:prefetch
5+
### data-sveltekit-prefetch
66

77
SvelteKit uses code splitting to break your app into small chunks (one per route), ensuring fast startup times.
88

99
For _dynamic_ routes, such as our `src/routes/blog/[slug]/+page.svelte` example, that's not enough. In order to render the blog post, we need to fetch the data for it, and we can't do that until we know what `slug` is. In the worst case, that could cause lag as the browser waits for the data to come back from the server.
1010

11-
We can mitigate that by _prefetching_ the data. Adding a `sveltekit:prefetch` attribute to a link...
11+
We can mitigate that by _prefetching_ the data. Adding a `data-sveltekit-prefetch` attribute to a link...
1212

1313
```html
14-
<a sveltekit:prefetch href="blog/what-is-sveltekit">What is SvelteKit?</a>
14+
<a data-sveltekit-prefetch href="blog/what-is-sveltekit">What is SvelteKit?</a>
1515
```
1616

1717
...will cause SvelteKit to run the page's `load` function as soon as the user hovers over the link (on a desktop) or touches it (on mobile), rather than waiting for the `click` event to trigger navigation. Typically, this buys us an extra couple of hundred milliseconds, which is the difference between a user interface that feels laggy, and one that feels snappy.
@@ -20,28 +20,28 @@ Note that prefetching will not work if the [`router`](/docs/page-options#router)
2020

2121
You can also programmatically invoke `prefetch` from `$app/navigation`.
2222

23-
### sveltekit:reload
23+
### data-sveltekit-reload
2424

2525
By default, the SvelteKit runtime intercepts clicks on `<a>` elements and bypasses the normal browser navigation for relative (same-origin) URLs that match one of your page routes. We sometimes need to tell SvelteKit that certain links need to be handled by normal browser navigation. Examples of this might be linking to another page on your domain that's not part of your SvelteKit app or linking to an endpoint.
2626

27-
Adding a `sveltekit:reload` attribute to a link...
27+
Adding a `data-sveltekit-reload` attribute to a link...
2828

2929
```html
30-
<a sveltekit:reload href="path">Path</a>
30+
<a data-sveltekit-reload href="path">Path</a>
3131
```
3232

3333
...will cause browser to navigate via a full page reload when the link is clicked.
3434

3535
Links with a `rel="external"` attribute will receive the same treatment. In addition, they will be ignored during [prerendering](https://kit.svelte.dev/docs/page-options#prerender).
3636

37-
### sveltekit:noscroll
37+
### data-sveltekit-noscroll
3838

3939
When navigating to internal links, SvelteKit mirrors the browser's default navigation behaviour: it will change the scroll position to 0,0 so that the user is at the very top left of the page (unless the link includes a `#hash`, in which case it will scroll to the element with a matching ID).
4040

41-
In certain cases, you may wish to disable this behaviour. Adding a `sveltekit:noscroll` attribute to a link...
41+
In certain cases, you may wish to disable this behaviour. Adding a `data-sveltekit-noscroll` attribute to a link...
4242

4343
```html
44-
<a href="path" sveltekit:noscroll>Path</a>
44+
<a href="path" data-sveltekit-noscroll>Path</a>
4545
```
4646

4747
...will prevent scrolling after the link is clicked.

Diff for: documentation/docs/80-migrating.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ This caused problems and is no longer the case in SvelteKit. Instead, relative U
133133

134134
#### &lt;a&gt; attributes
135135

136-
- `sapper:prefetch` is now `sveltekit:prefetch`
137-
- `sapper:noscroll` is now `sveltekit:noscroll`
136+
- `sapper:prefetch` is now `data-sveltekit-prefetch`
137+
- `sapper:noscroll` is now `data-sveltekit-noscroll`
138138

139139
### Endpoints
140140

Diff for: packages/create-svelte/templates/default/src/lib/header/Header.svelte

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
<path d="M0,0 L1,2 C1.5,3 1.5,3 2,3 L2,0 Z" />
1616
</svg>
1717
<ul>
18-
<li class:active={$page.url.pathname === '/'}><a sveltekit:prefetch href="/">Home</a></li>
18+
<li class:active={$page.url.pathname === '/'}>
19+
<a data-sveltekit-prefetch href="/">Home</a>
20+
</li>
1921
<li class:active={$page.url.pathname === '/about'}>
20-
<a sveltekit:prefetch href="/about">About</a>
22+
<a data-sveltekit-prefetch href="/about">About</a>
2123
</li>
2224
<li class:active={$page.url.pathname === '/todos'}>
23-
<a sveltekit:prefetch href="/todos">Todos</a>
25+
<a data-sveltekit-prefetch href="/todos">Todos</a>
2426
</li>
2527
</ul>
2628
<svg viewBox="0 0 2 3" aria-hidden="true">

Diff for: packages/kit/src/core/prerender/fixtures/basic-href/input.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<body>
88
<a href="https://external.com">https://external.com</a>
99
<a href="/wheee">/wheee</a>
10-
<a sveltekit:prefetch href="/wheee2">/wheee</a>
11-
<a href="/wheee3" sveltekit:prefetch>/wheee</a>
10+
<a data-sveltekit-prefetch href="/wheee2">/wheee</a>
11+
<a href="/wheee3" data-sveltekit-prefetch>/wheee</a>
1212
<a href="/wheee4">/wheee</a>
1313
</body>
1414
</html>

Diff for: packages/kit/src/exports/vite/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ function kit() {
195195
async config(config, config_env) {
196196
vite_config_env = config_env;
197197
svelte_config = await load_config();
198+
198199
env = get_env(svelte_config.kit.env, vite_config_env.mode);
199200

200201
// The config is created in build_server for SSR mode and passed inline

Diff for: packages/kit/src/runtime/client/client.js

+24-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,23 @@ function update_scroll_positions(index) {
4444
scroll_positions[index] = scroll_state();
4545
}
4646

47+
/** @type {Record<string, true>} */
48+
let warned_about_attributes = {};
49+
50+
function check_for_removed_attributes() {
51+
const attrs = ['prefetch', 'noscroll', 'reload'];
52+
for (const attr of attrs) {
53+
if (document.querySelector(`[sveltekit\\:${attr}]`)) {
54+
if (!warned_about_attributes[attr]) {
55+
warned_about_attributes[attr] = true;
56+
console.error(
57+
`The sveltekit:${attr} attribute has been replaced with data-sveltekit-${attr}`
58+
);
59+
}
60+
}
61+
}
62+
}
63+
4764
/**
4865
* @param {{
4966
* target: Element;
@@ -271,6 +288,8 @@ export function create_client({ target, base, trailing_slash }) {
271288
};
272289
root.$set(navigation_result.props);
273290
tick().then(() => (console.warn = warn));
291+
292+
check_for_removed_attributes();
274293
} else {
275294
root.$set(navigation_result.props);
276295
}
@@ -369,6 +388,8 @@ export function create_client({ target, base, trailing_slash }) {
369388
hydrate: true
370389
});
371390
console.warn = warn;
391+
392+
check_for_removed_attributes();
372393
} else {
373394
root = new Root({
374395
target,
@@ -1138,7 +1159,7 @@ export function create_client({ target, base, trailing_slash }) {
11381159
/** @param {Event} event */
11391160
const trigger_prefetch = (event) => {
11401161
const a = find_anchor(event);
1141-
if (a && a.href && a.hasAttribute('sveltekit:prefetch')) {
1162+
if (a && a.href && a.hasAttribute('data-sveltekit-prefetch')) {
11421163
prefetch(get_href(a));
11431164
}
11441165
};
@@ -1195,7 +1216,7 @@ export function create_client({ target, base, trailing_slash }) {
11951216
if (
11961217
a.hasAttribute('download') ||
11971218
rel.includes('external') ||
1198-
a.hasAttribute('sveltekit:reload')
1219+
a.hasAttribute('data-sveltekit-reload')
11991220
) {
12001221
return;
12011222
}
@@ -1222,7 +1243,7 @@ export function create_client({ target, base, trailing_slash }) {
12221243

12231244
navigate({
12241245
url,
1225-
scroll: a.hasAttribute('sveltekit:noscroll') ? scroll_state() : null,
1246+
scroll: a.hasAttribute('data-sveltekit-noscroll') ? scroll_state() : null,
12261247
keepfocus: false,
12271248
redirect_chain: [],
12281249
details: {

Diff for: packages/kit/test/apps/basics/src/routes/routing/+page.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
<a href="http://localhost:{$page.url.searchParams.get('port')}">elsewhere</a>
1010
<a href="/static.json">static.json</a>
1111

12-
<a href="/routing/b" sveltekit:reload>b</a>
12+
<a href="/routing/b" data-sveltekit-reload>b</a>
1313

1414
<div class="hydrate-test" />

Diff for: packages/kit/test/apps/basics/test/test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1427,7 +1427,7 @@ test.describe('Routing', () => {
14271427
expect(await page.textContent('body')).toBe('ok');
14281428
});
14291429

1430-
test('does not attempt client-side navigation to links with sveltekit:reload', async ({
1430+
test('does not attempt client-side navigation to links with data-sveltekit-reload', async ({
14311431
baseURL,
14321432
page
14331433
}) => {
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<a sveltekit:prefetch href="/path-base/prefetching/prefetched">click me</a>
1+
<a data-sveltekit-prefetch href="/path-base/prefetching/prefetched">click me</a>

Diff for: packages/kit/types/ambient.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ declare module '$app/navigation' {
122122
* 1. ensuring that the code for the page is loaded, and
123123
* 2. calling the page's load function with the appropriate options.
124124
*
125-
* This is the same behaviour that SvelteKit triggers when the user taps or mouses over an `<a>` element with `sveltekit:prefetch`.
125+
* This is the same behaviour that SvelteKit triggers when the user taps or mouses over an `<a>` element with `data-sveltekit-prefetch`.
126126
* If the next navigation is to `href`, the values returned from load will be used, making navigation instantaneous.
127127
* Returns a Promise that resolves when the prefetch is complete.
128128
*

Diff for: sites/kit.svelte.dev/src/lib/docs/Contents.svelte

+3-3
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
{#each contents as section}
8383
<li>
8484
<a
85-
sveltekit:prefetch
85+
data-sveltekit-prefetch
8686
class="section"
8787
class:active={section.path === path}
8888
href={section.path}
@@ -95,7 +95,7 @@
9595
{#each section.sections as subsection}
9696
<li>
9797
<a
98-
sveltekit:prefetch
98+
data-sveltekit-prefetch
9999
class="subsection"
100100
class:active={subsection.path === path}
101101
href={subsection.path}
@@ -109,7 +109,7 @@
109109
{#each subsection.sections as subsection}
110110
<li>
111111
<a
112-
sveltekit:prefetch
112+
data-sveltekit-prefetch
113113
class="nested subsection"
114114
class:active={subsection.path === path}
115115
href={subsection.path}

Diff for: sites/kit.svelte.dev/src/lib/search/SearchResultList.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
{#each results as result, i}
3838
<li>
3939
<a
40-
sveltekit:prefetch
40+
data-sveltekit-prefetch
4141
href={result.href}
4242
on:click={() => dispatch('select', { href: result.href })}
4343
data-has-node={result.node ? true : undefined}

Diff for: sites/kit.svelte.dev/src/routes/+page.svelte

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
of an SPA
4141
</p>
4242

43-
<a sveltekit:prefetch href="/docs" class="cta">read the docs</a>
43+
<a data-sveltekit-prefetch href="/docs" class="cta">read the docs</a>
4444
</div>
4545

4646
<div slot="three">
@@ -50,7 +50,7 @@
5050
support and more
5151
</p>
5252

53-
<a sveltekit:prefetch href="/docs" class="cta">read the docs</a>
53+
<a data-sveltekit-prefetch href="/docs" class="cta">read the docs</a>
5454
</div>
5555

5656
<div class="description" slot="what">
@@ -77,7 +77,7 @@ cd my-app
7777
npm install
7878
npm run dev -- --open</code
7979
></pre>
80-
<a sveltekit:prefetch href="/docs" class="cta">get started</a>
80+
<a data-sveltekit-prefetch href="/docs" class="cta">get started</a>
8181
</div>
8282
</Blurb>
8383
</div>

0 commit comments

Comments
 (0)