fix(nuxt): delay navigation until user input is acknowledged (#27743)

This commit is contained in:
Daniel Roe 2024-06-20 23:18:57 +01:00 committed by GitHub
parent b026797d7b
commit 5e76587490
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 0 deletions

View File

@ -0,0 +1,19 @@
import { defineNuxtPlugin } from '../nuxt'
import { useRouter } from '../composables'
export default defineNuxtPlugin(() => {
useRouter().beforeResolve(async () => {
/**
* This gives an opportunity for the browser to repaint, acknowledging user interaction.
* It can reduce INP when navigating on prerendered routes.
*
* @see https://github.com/nuxt/nuxt/issues/26271#issuecomment-2178582037
* @see https://vercel.com/blog/demystifying-inp-new-tools-and-actionable-insights
*/
await new Promise((resolve) => {
// Ensure we always resolve, even if the animation frame never fires
setTimeout(resolve, 100)
requestAnimationFrame(() => { setTimeout(resolve, 0) })
})
})
})

View File

@ -532,6 +532,12 @@ async function initNuxt (nuxt: Nuxt) {
}
}
if (nuxt.options.experimental.navigationRepaint) {
addPlugin({
src: resolve(nuxt.options.appDir, 'plugins/navigation-repaint.client'),
})
}
nuxt.hooks.hook('builder:watch', (event, relativePath) => {
const path = resolve(nuxt.options.srcDir, relativePath)
// Local module patterns

View File

@ -43,6 +43,10 @@ describe('resolveApp', () => {
"mode": "client",
"src": "<repoRoot>/packages/nuxt/src/app/plugins/payload.client.ts",
},
{
"mode": "client",
"src": "<repoRoot>/packages/nuxt/src/app/plugins/navigation-repaint.client.ts",
},
{
"mode": "client",
"src": "<repoRoot>/packages/nuxt/src/app/plugins/check-outdated-build.client.ts",

View File

@ -417,5 +417,13 @@ export default defineUntypedSchema({
* @type {boolean}
*/
clientNodeCompat: false,
/**
* Wait for a single animation frame before navigation, which gives an opportunity
* for the browser to repaint, acknowledging user interaction.
*
* It can reduce INP when navigating on prerendered routes.
*/
navigationRepaint: true,
},
})