feat(nuxt,schema): pages:resolved hook + scan meta post extend (#28861)

This commit is contained in:
Bobbie Goede 2024-10-22 21:32:46 +09:00 committed by GitHub
parent cd8a124123
commit eaeda4ee1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 79 additions and 12 deletions

View File

@ -67,6 +67,7 @@ export default defineNuxtConfig({
// app: 'app' // app: 'app'
// }, // },
// experimental: { // experimental: {
// scanPageMeta: 'after-resolve',
// sharedPrerenderData: false, // sharedPrerenderData: false,
// compileTemplate: true, // compileTemplate: true,
// resetAsyncDataToUndefined: true, // resetAsyncDataToUndefined: true,
@ -236,6 +237,45 @@ export default defineNuxtConfig({
}) })
``` ```
#### Scan Page Meta After Resolution
🚦 **Impact Level**: Minimal
##### What Changed
We now scan page metadata (defined in `definePageMeta`) _after_ calling the `pages:extend` hook rather than before.
##### Reasons for Change
This was to allow scanning metadata for pages that users wanted to add in `pages:extend`. We still offer an opportunity to change or override page metadata in a new `pages:resolved` hook.
##### Migration Steps
If you want to override page metadata, do that in `pages:resolved` rather than in `pages:extend`.
```diff
export default defineNuxtConfig({
hooks: {
- 'pages:extend'(pages) {
+ 'pages:resolved'(pages) {
const myPage = pages.find(page => page.path === '/')
myPage.meta ||= {}
myPage.meta.layout = 'overridden-layout'
}
}
})
```
Alternatively, you can revert to the previous behaviour with:
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
scanPageMeta: true
}
})
```
#### Shared Prerender Data #### Shared Prerender Data
🚦 **Impact Level**: Medium 🚦 **Impact Level**: Medium

View File

@ -334,6 +334,8 @@ This option allows exposing some route metadata defined in `definePageMeta` at b
This only works with static or strings/arrays rather than variables or conditional assignment. See [original issue](https://github.com/nuxt/nuxt/issues/24770) for more information and context. This only works with static or strings/arrays rather than variables or conditional assignment. See [original issue](https://github.com/nuxt/nuxt/issues/24770) for more information and context.
It is also possible to scan page metadata only after all routes have been registered in `pages:extend`. Then another hook, `pages:resolved` will be called. To enable this behavior, set `scanPageMeta: 'after-resolve'`.
You can disable this feature if it causes issues in your project. You can disable this feature if it causes issues in your project.
```ts twoslash [nuxt.config.ts] ```ts twoslash [nuxt.config.ts]

View File

@ -61,6 +61,7 @@ export default defineNuxtConfig({
app: 'app' app: 'app'
}, },
experimental: { experimental: {
scanPageMeta: 'after-resolve',
sharedPrerenderData: false, sharedPrerenderData: false,
compileTemplate: true, compileTemplate: true,
resetAsyncDataToUndefined: true, resetAsyncDataToUndefined: true,

View File

@ -503,7 +503,7 @@ export default defineNuxtModule({
const { routes, imports } = normalizeRoutes(app.pages, new Set(), { const { routes, imports } = normalizeRoutes(app.pages, new Set(), {
serverComponentRuntime, serverComponentRuntime,
clientComponentRuntime, clientComponentRuntime,
overrideMeta: nuxt.options.experimental.scanPageMeta, overrideMeta: !!nuxt.options.experimental.scanPageMeta,
}) })
return [...imports, `export default ${routes}`].join('\n') return [...imports, `export default ${routes}`].join('\n')
}, },

View File

@ -64,18 +64,25 @@ export async function resolvePagesRoutes (): Promise<NuxtPage[]> {
}) })
const pages = uniqueBy(allRoutes, 'path') const pages = uniqueBy(allRoutes, 'path')
const shouldAugment = nuxt.options.experimental.scanPageMeta || nuxt.options.experimental.typedPages const shouldAugment = nuxt.options.experimental.scanPageMeta || nuxt.options.experimental.typedPages
if (shouldAugment) { if (shouldAugment === false) {
await nuxt.callHook('pages:extend', pages)
return pages
}
if (shouldAugment === 'after-resolve') {
await nuxt.callHook('pages:extend', pages)
await augmentPages(pages, nuxt.vfs)
} else {
const augmentedPages = await augmentPages(pages, nuxt.vfs) const augmentedPages = await augmentPages(pages, nuxt.vfs)
await nuxt.callHook('pages:extend', pages) await nuxt.callHook('pages:extend', pages)
await augmentPages(pages, nuxt.vfs, augmentedPages) await augmentPages(pages, nuxt.vfs, augmentedPages)
augmentedPages.clear() augmentedPages.clear()
} else {
await nuxt.callHook('pages:extend', pages)
} }
await nuxt.callHook('pages:resolved', pages)
return pages return pages
} }

View File

@ -297,8 +297,13 @@ export default defineUntypedSchema({
* This only works with static or strings/arrays rather than variables or conditional assignment. * This only works with static or strings/arrays rather than variables or conditional assignment.
* *
* @see [Nuxt Issues #24770](https://github.com/nuxt/nuxt/issues/24770) * @see [Nuxt Issues #24770](https://github.com/nuxt/nuxt/issues/24770)
* @type {boolean | 'after-resolve'}
*/ */
scanPageMeta: true, scanPageMeta: {
async $resolve (val, get) {
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion === 4 ? 'after-resolve' : true)
},
},
/** /**
* Automatically share payload _data_ between pages that are prerendered. This can result in a significant * Automatically share payload _data_ between pages that are prerendered. This can result in a significant

View File

@ -183,12 +183,19 @@ export interface NuxtHooks {
'builder:watch': (event: WatchEvent, path: string) => HookResult 'builder:watch': (event: WatchEvent, path: string) => HookResult
/** /**
* Called after pages routes are resolved. * Called after page routes are scanned from the file system.
* @param pages Array containing resolved pages * @param pages Array containing scanned pages
* @returns Promise * @returns Promise
*/ */
'pages:extend': (pages: NuxtPage[]) => HookResult 'pages:extend': (pages: NuxtPage[]) => HookResult
/**
* Called after page routes have been augmented with scanned metadata.
* @param pages Array containing resolved pages
* @returns Promise
*/
'pages:resolved': (pages: NuxtPage[]) => HookResult
/** /**
* Called when resolving `app/router.options` files. It allows modifying the detected router options files * Called when resolving `app/router.options` files. It allows modifying the detected router options files
* and adding new ones. * and adding new ones.

View File

@ -13,13 +13,18 @@ export default defineNuxtModule({
name: 'page-extend', name: 'page-extend',
path: '/page-extend', path: '/page-extend',
file: resolver.resolve('../runtime/page.vue'), file: resolver.resolve('../runtime/page.vue'),
}, { })
})
nuxt.hook('pages:resolved', (pages) => {
pages.push({
path: '/big-page-1', path: '/big-page-1',
file: resolver.resolve('./pages/big-page.vue'), file: resolver.resolve('./pages/big-page.vue'),
meta: { meta: {
layout: false, layout: false,
}, },
}, { },
{
path: '/big-page-2', path: '/big-page-2',
file: resolver.resolve('./pages/big-page.vue'), file: resolver.resolve('./pages/big-page.vue'),
meta: { meta: {

View File

@ -75,7 +75,7 @@ export default defineNuxtConfig({
_layout: page.meta?.layout, _layout: page.meta?.layout,
}, },
}) })
nuxt.hook('pages:extend', (pages) => { nuxt.hook('pages:resolved', (pages) => {
const newPages = [] const newPages = []
for (const page of pages) { for (const page of pages) {
if (routesToDuplicate.includes(page.path)) { if (routesToDuplicate.includes(page.path)) {
@ -88,7 +88,7 @@ export default defineNuxtConfig({
}, },
function (_options, nuxt) { function (_options, nuxt) {
// to check that page metadata is preserved // to check that page metadata is preserved
nuxt.hook('pages:extend', (pages) => { nuxt.hook('pages:resolved', (pages) => {
const customName = pages.find(page => page.name === 'some-custom-name') const customName = pages.find(page => page.name === 'some-custom-name')
if (!customName) { throw new Error('Page with custom name not found') } if (!customName) { throw new Error('Page with custom name not found') }
if (customName.path !== '/some-custom-path') { throw new Error('Page path not extracted') } if (customName.path !== '/some-custom-path') { throw new Error('Page path not extracted') }