From 912eafbbf6ee72859198405fce3e51a1648ce1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Thu, 19 Jan 2023 14:01:21 +0100 Subject: [PATCH] feat(nuxt): prefetch middleware/layouts + await layout loading (#10155) --- packages/nuxt/src/pages/module.ts | 5 ++- .../pages/runtime/plugins/prefetch.client.ts | 40 +++++++++++++++++++ .../src/pages/runtime/{ => plugins}/router.ts | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 packages/nuxt/src/pages/runtime/plugins/prefetch.client.ts rename packages/nuxt/src/pages/runtime/{ => plugins}/router.ts (99%) diff --git a/packages/nuxt/src/pages/module.ts b/packages/nuxt/src/pages/module.ts index 32b38b2857..b571dd5b14 100644 --- a/packages/nuxt/src/pages/module.ts +++ b/packages/nuxt/src/pages/module.ts @@ -140,8 +140,11 @@ export default defineNuxtModule({ addVitePlugin(PageMetaPlugin.vite(pageMetaOptions)) addWebpackPlugin(PageMetaPlugin.webpack(pageMetaOptions)) + // Add prefetching support for middleware & layouts + addPlugin(resolve(runtimeDir, 'plugins/prefetch.client')) + // Add router plugin - addPlugin(resolve(runtimeDir, 'router')) + addPlugin(resolve(runtimeDir, 'plugins/router')) const getSources = (pages: NuxtPage[]): string[] => pages.flatMap(p => [relative(nuxt.options.srcDir, p.file), ...getSources(p.children || [])] diff --git a/packages/nuxt/src/pages/runtime/plugins/prefetch.client.ts b/packages/nuxt/src/pages/runtime/plugins/prefetch.client.ts new file mode 100644 index 0000000000..637ae4454a --- /dev/null +++ b/packages/nuxt/src/pages/runtime/plugins/prefetch.client.ts @@ -0,0 +1,40 @@ +import { hasProtocol } from 'ufo' +import { defineNuxtPlugin, useNuxtApp, useRouter } from '#app' +// @ts-ignore +import layouts from '#build/layouts' +// @ts-ignore +import { namedMiddleware } from '#build/middleware' + +export default defineNuxtPlugin(() => { + const nuxtApp = useNuxtApp() + const router = useRouter() + + // Force layout prefetch on route changes + nuxtApp.hooks.hook('app:mounted', () => { + router.beforeEach(async (to) => { + const layout = to?.meta?.layout + if (layout && typeof layouts[layout] === 'function') { + await layouts[layout]() + } + }) + }) + // Prefetch layouts & middleware + nuxtApp.hooks.hook('link:prefetch', (url) => { + if (hasProtocol(url)) { return } + const route = router.resolve(url) + if (!route) { return } + const layout = route?.meta?.layout + let middleware = Array.isArray(route?.meta?.middleware) ? route?.meta?.middleware : [route?.meta?.middleware] + middleware = middleware.filter(m => typeof m === 'string') + + for (const name of middleware) { + if (typeof namedMiddleware[name] === 'function') { + namedMiddleware[name]() + } + } + + if (layout && typeof layouts[layout] === 'function') { + layouts[layout]() + } + }) +}) diff --git a/packages/nuxt/src/pages/runtime/router.ts b/packages/nuxt/src/pages/runtime/plugins/router.ts similarity index 99% rename from packages/nuxt/src/pages/runtime/router.ts rename to packages/nuxt/src/pages/runtime/plugins/router.ts index 989849a452..396945b7ab 100644 --- a/packages/nuxt/src/pages/runtime/router.ts +++ b/packages/nuxt/src/pages/runtime/plugins/router.ts @@ -11,7 +11,7 @@ import { } from 'vue-router' import { createError } from 'h3' import { withoutBase, isEqual } from 'ufo' -import type NuxtPage from './page' +import type NuxtPage from '../page' import { callWithNuxt, defineNuxtPlugin, useRuntimeConfig, showError, clearError, navigateTo, useError, useState } from '#app' // @ts-ignore import _routes from '#build/routes'