From f3ea3e437818f5d863a10b8d98eda947503c89ab Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 17 May 2024 09:23:32 -0400 Subject: [PATCH 1/5] fix: yield main thread before navigating --- .changeset/pink-tigers-whisper.md | 5 +++++ packages/kit/src/runtime/client/client.js | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 .changeset/pink-tigers-whisper.md diff --git a/.changeset/pink-tigers-whisper.md b/.changeset/pink-tigers-whisper.md new file mode 100644 index 000000000000..6837fa592298 --- /dev/null +++ b/.changeset/pink-tigers-whisper.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: yield main thread before navigating diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index d39f3edbcf6e..2e1800e6a239 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -2120,6 +2120,16 @@ function _start_router() { event.preventDefault(); + // allow the browser to repaint before navigating — + // this prevents INP scores being penalised + new Promise((fulfil) => { + requestAnimationFrame(() => { + setTimeout(fulfil, 0); + }); + + setTimeout(fulfil, 100); // fallback for edge case where rAF doesn't fire because e.g. tab was backgrounded + }); + navigate({ type: 'link', url, From 3bfeeb38fb88a7abb8f46f5962dc3c0dbae4a58c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 17 May 2024 10:37:59 -0400 Subject: [PATCH 2/5] Update packages/kit/src/runtime/client/client.js --- packages/kit/src/runtime/client/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 2e1800e6a239..529af053409e 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -2122,7 +2122,7 @@ function _start_router() { // allow the browser to repaint before navigating — // this prevents INP scores being penalised - new Promise((fulfil) => { + await new Promise((fulfil) => { requestAnimationFrame(() => { setTimeout(fulfil, 0); }); From 33144c50f64f16631682392331c75a3cbf500258 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 17 May 2024 10:39:13 -0400 Subject: [PATCH 3/5] gah --- packages/kit/src/runtime/client/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 529af053409e..d2c1de27f0a7 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -2027,7 +2027,7 @@ function _start_router() { } /** @param {MouseEvent} event */ - container.addEventListener('click', (event) => { + container.addEventListener('click', async (event) => { // Adapted from https://github.com/visionmedia/page.js // MIT license https://github.com/visionmedia/page.js#license if (event.button || event.which !== 1) return; From 1c97fd7b25bf2b43230234b2817a4443237467af Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 17 May 2024 11:24:55 -0400 Subject: [PATCH 4/5] add test --- .../basics/src/routes/routing/+page.svelte | 1 + .../routes/routing/next-paint/+page.svelte | 1 + .../kit/test/apps/basics/test/client.test.js | 29 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 packages/kit/test/apps/basics/src/routes/routing/next-paint/+page.svelte diff --git a/packages/kit/test/apps/basics/src/routes/routing/+page.svelte b/packages/kit/test/apps/basics/src/routes/routing/+page.svelte index ed56fb4855eb..e676c47a6533 100644 --- a/packages/kit/test/apps/basics/src/routes/routing/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/routing/+page.svelte @@ -6,6 +6,7 @@ a ok +next-paint symlinked elsewhere static.json diff --git a/packages/kit/test/apps/basics/src/routes/routing/next-paint/+page.svelte b/packages/kit/test/apps/basics/src/routes/routing/next-paint/+page.svelte new file mode 100644 index 000000000000..1aea392f7b8d --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/routing/next-paint/+page.svelte @@ -0,0 +1 @@ +

next-paint

diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 2a57fd5566cd..181217970741 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1163,3 +1163,32 @@ test.describe('reroute', () => { expect(await page.textContent('h1')).toContain('Full Navigation'); }); }); + +test.describe('INP', () => { + test('does not block next paint', async ({ page }) => { + // Thanks to https://publishing-project.rivendellweb.net/measuring-performance-tasks-with-playwright/#interaction-to-next-paint-inp + async function measureInteractionToPaint(selector) { + return page.evaluate(async (selector) => { + return new Promise((resolve) => { + const startTime = performance.now(); + document.querySelector(selector).click(); + requestAnimationFrame(() => { + const endTime = performance.now(); + resolve(endTime - startTime); + }); + }); + }, selector); + } + + await page.goto('/routing'); + + const client = await page.context().newCDPSession(page); + await client.send('Emulation.setCPUThrottlingRate', { rate: 100 }); + + const time = await measureInteractionToPaint('a[href="/routing/next-paint"]'); + + // we may need to tweak this number, and the `rate` above, + // depending on if this proves flaky + expect(time).toBeLessThan(200); + }); +}); From 5cfa4a987d595d39f23a4267d1fff9730318b50d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 17 May 2024 11:58:59 -0400 Subject: [PATCH 5/5] bigger magic number --- packages/kit/test/apps/basics/test/client.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 181217970741..2d729e903adf 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1189,6 +1189,6 @@ test.describe('INP', () => { // we may need to tweak this number, and the `rate` above, // depending on if this proves flaky - expect(time).toBeLessThan(200); + expect(time).toBeLessThan(400); }); });