Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.

Fixes #1667 prefetching fails if clicking quickly back and forth #1668

Merged
merged 5 commits into from
Dec 14, 2020
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
43 changes: 24 additions & 19 deletions runtime/src/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,29 +236,34 @@ export async function hydrate_target(dest: Target): Promise<HydratedTarget> {

const j = l++;

if (!session_dirty && !segment_dirty && current_branch[i] && current_branch[i].part === part.i) {
return current_branch[i];
}

segment_dirty = false;
let result;

const { default: component, preload } = await components[part.i].js();

let preloaded: object;
if (ready || !initial_data.preloaded[i + 1]) {
preloaded = preload
? await preload.call(preload_context, {
host: page.host,
path: page.path,
query: page.query,
params: part.params ? part.params(dest.match) : {}
}, $session)
: {};
if (!session_dirty && !segment_dirty && current_branch[i] && current_branch[i].part === part.i) {
result = current_branch[i];
} else {
preloaded = initial_data.preloaded[i + 1];
segment_dirty = false;

const { default: component, preload } = await components[part.i].js();

let preloaded: object;

if (ready || !initial_data.preloaded[i + 1]) {
preloaded = preload
? await preload.call(preload_context, {
host: page.host,
path: page.path,
query: page.query,
params: part.params ? part.params(dest.match) : {}
}, $session)
: {};
} else {
preloaded = initial_data.preloaded[i + 1];
}

result = { component, props: preloaded, segment, match, part: part.i };
}

return (props[`level${j}`] = { component, props: preloaded, segment, match, part: part.i });
return (props[`level${j}`] = result);
}));
} catch (error) {
props.error = error;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script context="module">
export function preload() {
if (typeof window !== 'undefined' && window.onPrefetched) {
Promise.resolve().then(() => window.onPrefetched());
}
}
</script>

<script>
import { onMount } from 'svelte';
let prefetchlink;

onMount(() => {
let timeout;

/**
* This emulates the logic in start prefetching. Just firing after the first mouse move
* would also work fine in the Puppeteer tests, just not if you try it manually.
*/
prefetchlink.addEventListener('mousemove', () => {
clearTimeout(timeout);

if (window.onPrefetched) {
timeout = setTimeout(() => {
window.onPrefetched();
}, 50);
}
});
});
</script>

<h1>Prefetched</h1>

<a href="/prefetch-timing/prefetcher">prefetcher</a>
<a href="/prefetch-timing/prefetched" rel="prefetch" bind:this={prefetchlink}>prefetched</a>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script context="module">
export function preload() {
if (typeof window !== 'undefined') {
return new Promise((resolve) => {
window.onPrefetched = resolve;
});
}
}
</script>

<h1>Prefetcher</h1>

<a href="/prefetch-timing/prefetched" rel="prefetch">prefetched</a>
30 changes: 30 additions & 0 deletions test/apps/basics/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,36 @@ describe('basics', function() {
assert.equal(await r.text('h2'), 'Called 1 time');
});

/**
* Before a page navigation finishes, hover over a prefetching link back to the page we came from.
* Prefetching starts, but we're still on the page being preloaded!
* After that happened, clicking on the link back to the original page did not work.
* https://github.com/sveltejs/sapper/issues/1667
*/
it('handles prefetching to the current page', async () => {
await r.load('/prefetch-timing/prefetched');
await r.sapper.start();
await r.sapper.prefetchRoutes();

assert.strictEqual(await r.text('h1'), 'Prefetched');

const prefetchedSelector = 'a[href="/prefetch-timing/prefetched"]';
const prefetcherSelector = 'a[href="/prefetch-timing/prefetcher"]';

await r.page.click(prefetcherSelector);
await r.wait();

await r.page.hover(prefetchedSelector);
await r.wait(50);

await r.page.waitForFunction(() => document.querySelector('h1').innerHTML == 'Prefetcher');

await r.page.click(prefetchedSelector);
await r.wait();

assert.strictEqual(await r.text('h1'), 'Prefetched');
});

it('survives the tests with no server errors', () => {
assert.deepEqual(r.errors, []);
});
Expand Down