Skip to content

Commit ef1e804

Browse files
authored
fix: correctly preload links on mousedown/touchstart (#13486)
fixes #13466 This PR changes the link preload behaviour so that it only ignores a link which has already triggered a preload. Previously, it would start ignoring a link the moment it was hovered on. This caused a link that only preloads on mousedown to always be ignored since a user's mouse would hover on the link first, causing it to be ignored on the subsequent mousedown event. This PR also fixes the data-sveltekit-preload tests that did not manage to catch this regression by changing the tests to use playwright mouse hover simulation instead of programmatically dispatching the mouseover event which didn't complete before firing the other events.
1 parent 908a948 commit ef1e804

File tree

5 files changed

+64
-19
lines changed

5 files changed

+64
-19
lines changed

Diff for: .changeset/mighty-kiwis-laugh.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: correctly preload links on `mousedown`/`touchstart`

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -1677,8 +1677,6 @@ function setup_preload() {
16771677
const a = find_anchor(element, container);
16781678
if (!a || a === current_a) return;
16791679

1680-
current_a = a;
1681-
16821680
const { url, external, download } = get_link_info(a, base, app.hash);
16831681
if (external || download) return;
16841682

@@ -1689,6 +1687,7 @@ function setup_preload() {
16891687

16901688
if (!options.reload && !same_url) {
16911689
if (priority <= options.preload_data) {
1690+
current_a = a;
16921691
const intent = await get_navigation_intent(url, false);
16931692
if (intent) {
16941693
if (DEV) {
@@ -1707,6 +1706,7 @@ function setup_preload() {
17071706
}
17081707
}
17091708
} else if (priority <= options.preload_code) {
1709+
current_a = a;
17101710
void _preload_code(/** @type {URL} */ (url));
17111711
}
17121712
}

Diff for: packages/kit/test/apps/basics/src/routes/data-sveltekit/preload-code/+page.svelte

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
<a id="eager" href="/data-sveltekit/preload-code/target/eager" data-sveltekit-preload-code="eager"
2+
>eager</a
3+
>
4+
15
<div style="height: 200vh"></div>
26

37
<a

Diff for: packages/kit/test/apps/basics/src/routes/data-sveltekit/preload-data/+page.svelte

+2
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
>three</a
77
>
88
</div>
9+
10+
<a id="tap" href="/data-sveltekit/preload-data/target" data-sveltekit-preload-data="tap">tap</a>

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

+51-17
Original file line numberDiff line numberDiff line change
@@ -827,32 +827,56 @@ test.describe('Invalidation', () => {
827827
test.describe('data-sveltekit attributes', () => {
828828
test('data-sveltekit-preload-code', async ({ page }) => {
829829
/** @type {string[]} */
830-
const requests = [];
831-
page.on('request', (r) => {
832-
requests.push(r.url());
830+
const responses = [];
831+
832+
const nodes_location = process.env.DEV
833+
? '.svelte-kit/generated/client/nodes/'
834+
: '/_app/immutable/nodes/';
835+
836+
page.on('response', async (response) => {
837+
const url = response.url();
838+
if (url.includes(nodes_location)) {
839+
responses.push(url);
840+
}
833841
});
834842

835843
// eager
836844
await page.goto('/data-sveltekit/preload-code');
837-
expect(requests.length).toBeGreaterThanOrEqual(1);
845+
await page.locator('#eager').hover();
846+
await page.locator('#eager').dispatchEvent('touchstart');
847+
// expect 4 nodes on initial load: root layout, root error, current page, and eager preload
848+
expect(responses.length).toEqual(4);
838849

839850
// viewport
840-
requests.length = 0;
851+
responses.length = 0;
841852
page.locator('#viewport').scrollIntoViewIfNeeded();
842-
await Promise.all([page.waitForTimeout(100), page.waitForLoadState('networkidle')]);
843-
expect(requests.length).toBeGreaterThanOrEqual(1);
853+
await page.locator('#viewport').hover();
854+
await page.locator('#viewport').dispatchEvent('touchstart');
855+
await Promise.all([
856+
page.waitForTimeout(100), // wait for preloading to start
857+
page.waitForLoadState('networkidle') // wait for preloading to finish
858+
]);
859+
expect(responses.length).toEqual(1);
844860

845861
// hover
846-
requests.length = 0;
847-
await page.locator('#hover').dispatchEvent('mousemove');
848-
await Promise.all([page.waitForTimeout(100), page.waitForLoadState('networkidle')]);
849-
expect(requests.length).toBeGreaterThanOrEqual(1);
862+
responses.length = 0;
863+
await page.locator('#hover').hover();
864+
await page.locator('#hover').dispatchEvent('touchstart');
865+
await Promise.all([
866+
page.waitForTimeout(100), // wait for preloading to start
867+
page.waitForLoadState('networkidle') // wait for preloading to finish
868+
]);
869+
expect(responses.length).toEqual(1);
850870

851871
// tap
852-
requests.length = 0;
872+
responses.length = 0;
873+
await page.locator('#tap').hover();
853874
await page.locator('#tap').dispatchEvent('touchstart');
854-
await Promise.all([page.waitForTimeout(100), page.waitForLoadState('networkidle')]);
855-
expect(requests.length).toBeGreaterThanOrEqual(1);
875+
await Promise.all([
876+
page.waitForTimeout(100), // wait for preloading to start
877+
page.waitForLoadState('networkidle') // wait for preloading to finish
878+
]);
879+
expect(responses.length).toEqual(1);
856880
});
857881

858882
test('data-sveltekit-preload-data', async ({ page }) => {
@@ -875,7 +899,7 @@ test.describe('data-sveltekit attributes', () => {
875899
});
876900

877901
await page.goto('/data-sveltekit/preload-data');
878-
await page.locator('#one').dispatchEvent('mousemove');
902+
await page.locator('#one').hover();
879903
await Promise.all([
880904
page.waitForTimeout(100), // wait for preloading to start
881905
page.waitForLoadState('networkidle') // wait for preloading to finish
@@ -884,7 +908,7 @@ test.describe('data-sveltekit attributes', () => {
884908

885909
requests.length = 0;
886910
await page.goto('/data-sveltekit/preload-data');
887-
await page.locator('#two').dispatchEvent('mousemove');
911+
await page.locator('#two').hover();
888912
await Promise.all([
889913
page.waitForTimeout(100), // wait for preloading to start
890914
page.waitForLoadState('networkidle') // wait for preloading to finish
@@ -893,12 +917,22 @@ test.describe('data-sveltekit attributes', () => {
893917

894918
requests.length = 0;
895919
await page.goto('/data-sveltekit/preload-data');
896-
await page.locator('#three').dispatchEvent('mousemove');
920+
await page.locator('#three').hover();
897921
await Promise.all([
898922
page.waitForTimeout(100), // wait for preloading to start
899923
page.waitForLoadState('networkidle') // wait for preloading to finish
900924
]);
901925
expect(requests.length).toBe(0);
926+
927+
requests.length = 0;
928+
await page.goto('/data-sveltekit/preload-data');
929+
await page.locator('#tap').hover();
930+
await page.locator('#tap').dispatchEvent('touchstart');
931+
await Promise.all([
932+
page.waitForTimeout(100), // wait for preloading to start
933+
page.waitForLoadState('networkidle') // wait for preloading to finish
934+
]);
935+
expect(requests.length).toBe(1);
902936
});
903937

904938
test('data-sveltekit-preload-data network failure does not trigger navigation', async ({

0 commit comments

Comments
 (0)