mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
fix(nuxt): allow granularly overriding pages in layers (#23134)
This commit is contained in:
parent
aa2c5c3df4
commit
15e6dfb560
@ -33,6 +33,11 @@ interface SegmentToken {
|
||||
value: string
|
||||
}
|
||||
|
||||
interface ScannedFile {
|
||||
relativePath: string
|
||||
absolutePath: string
|
||||
}
|
||||
|
||||
export async function resolvePagesRoutes (): Promise<NuxtPage[]> {
|
||||
const nuxt = useNuxt()
|
||||
|
||||
@ -40,30 +45,30 @@ export async function resolvePagesRoutes (): Promise<NuxtPage[]> {
|
||||
layer => resolve(layer.config.srcDir, layer.config.dir?.pages || 'pages')
|
||||
)
|
||||
|
||||
const allRoutes = (await Promise.all(
|
||||
pagesDirs.map(async (dir) => {
|
||||
const scannedFiles: ScannedFile[] = []
|
||||
for (const dir of pagesDirs) {
|
||||
const files = await resolveFiles(dir, `**/*{${nuxt.options.extensions.join(',')}}`)
|
||||
// Sort to make sure parent are listed first
|
||||
files.sort()
|
||||
return generateRoutesFromFiles(files, dir, nuxt.options.experimental.typedPages, nuxt.vfs)
|
||||
})
|
||||
)).flat()
|
||||
scannedFiles.push(...files.map(file => ({ relativePath: relative(dir, file), absolutePath: file })))
|
||||
}
|
||||
scannedFiles.sort((a, b) => a.relativePath.localeCompare(b.relativePath))
|
||||
|
||||
const allRoutes = await generateRoutesFromFiles(scannedFiles, nuxt.options.experimental.typedPages, nuxt.vfs)
|
||||
|
||||
return uniqueBy(allRoutes, 'path')
|
||||
}
|
||||
|
||||
export async function generateRoutesFromFiles (files: string[], pagesDir: string, shouldExtractBuildMeta = false, vfs?: Record<string, string>): Promise<NuxtPage[]> {
|
||||
export async function generateRoutesFromFiles (files: ScannedFile[], shouldExtractBuildMeta = false, vfs?: Record<string, string>): Promise<NuxtPage[]> {
|
||||
const routes: NuxtPage[] = []
|
||||
|
||||
for (const file of files) {
|
||||
const segments = relative(pagesDir, file)
|
||||
.replace(new RegExp(`${escapeRE(extname(file))}$`), '')
|
||||
const segments = file.relativePath
|
||||
.replace(new RegExp(`${escapeRE(extname(file.relativePath))}$`), '')
|
||||
.split('/')
|
||||
|
||||
const route: NuxtPage = {
|
||||
name: '',
|
||||
path: '',
|
||||
file,
|
||||
file: file.absolutePath,
|
||||
children: []
|
||||
}
|
||||
|
||||
@ -94,7 +99,7 @@ export async function generateRoutesFromFiles (files: string[], pagesDir: string
|
||||
}
|
||||
|
||||
if (shouldExtractBuildMeta && vfs) {
|
||||
const fileContent = file in vfs ? vfs[file] : fs.readFileSync(resolve(pagesDir, file), 'utf-8')
|
||||
const fileContent = file.absolutePath in vfs ? vfs[file.absolutePath] : fs.readFileSync(file.absolutePath, 'utf-8')
|
||||
const overrideRouteName = await getRouteName(fileContent)
|
||||
if (overrideRouteName) {
|
||||
route.name = overrideRouteName
|
||||
|
@ -5,6 +5,7 @@ import { generateRouteKey } from '../src/pages/runtime/utils'
|
||||
|
||||
describe('pages:generateRoutesFromFiles', () => {
|
||||
const pagesDir = 'pages'
|
||||
const layerDir = 'layer/pages'
|
||||
const tests: Array<{
|
||||
description: string
|
||||
files: Array<{ path: string; template?: string; }>
|
||||
@ -176,7 +177,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
{
|
||||
children: [],
|
||||
name: 'slug',
|
||||
file: 'pages/[slug].vue',
|
||||
file: `${pagesDir}/[slug].vue`,
|
||||
path: '/:slug()'
|
||||
},
|
||||
{
|
||||
@ -189,7 +190,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
children: []
|
||||
}
|
||||
],
|
||||
file: 'pages/[[foo]]',
|
||||
file: `${pagesDir}/[[foo]]`,
|
||||
path: '/:foo?'
|
||||
},
|
||||
{
|
||||
@ -220,7 +221,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
{
|
||||
children: [],
|
||||
name: 'bar',
|
||||
file: 'pages/[bar]/index.vue',
|
||||
file: `${pagesDir}/[bar]/index.vue`,
|
||||
path: '/:bar()'
|
||||
},
|
||||
{
|
||||
@ -378,11 +379,11 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
description: 'should correctly merge nested routes',
|
||||
files: [
|
||||
{ path: `${pagesDir}/param.vue` },
|
||||
{ path: `${pagesDir}/param/index.vue` },
|
||||
{ path: `${layerDir}/param/index.vue` },
|
||||
{ path: `${pagesDir}/param/index/index.vue` },
|
||||
{ path: `${pagesDir}/param/index/sibling.vue` },
|
||||
{ path: `${layerDir}/param/index/sibling.vue` },
|
||||
{ path: `${pagesDir}/wrapper-expose/other.vue` },
|
||||
{ path: `${pagesDir}/wrapper-expose/other/index.vue` },
|
||||
{ path: `${layerDir}/wrapper-expose/other/index.vue` },
|
||||
{ path: `${pagesDir}/wrapper-expose/other/sibling.vue` },
|
||||
{ path: `${pagesDir}/param/sibling.vue` }
|
||||
],
|
||||
@ -393,46 +394,46 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
children: [
|
||||
{
|
||||
children: [],
|
||||
file: 'pages/param/index/index.vue',
|
||||
file: `${pagesDir}/param/index/index.vue`,
|
||||
name: 'param-index',
|
||||
path: ''
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
file: 'pages/param/index/sibling.vue',
|
||||
file: `${layerDir}/param/index/sibling.vue`,
|
||||
name: 'param-index-sibling',
|
||||
path: 'sibling'
|
||||
}
|
||||
],
|
||||
file: 'pages/param/index.vue',
|
||||
file: `${layerDir}/param/index.vue`,
|
||||
path: ''
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
file: 'pages/param/sibling.vue',
|
||||
file: `${pagesDir}/param/sibling.vue`,
|
||||
name: 'param-sibling',
|
||||
path: 'sibling'
|
||||
}
|
||||
],
|
||||
file: 'pages/param.vue',
|
||||
file: `${pagesDir}/param.vue`,
|
||||
path: '/param'
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
children: [],
|
||||
file: 'pages/wrapper-expose/other/index.vue',
|
||||
file: `${layerDir}/wrapper-expose/other/index.vue`,
|
||||
name: 'wrapper-expose-other',
|
||||
path: ''
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
file: 'pages/wrapper-expose/other/sibling.vue',
|
||||
file: `${pagesDir}/wrapper-expose/other/sibling.vue`,
|
||||
name: 'wrapper-expose-other-sibling',
|
||||
path: 'sibling'
|
||||
}
|
||||
],
|
||||
file: 'pages/wrapper-expose/other.vue',
|
||||
file: `${pagesDir}/wrapper-expose/other.vue`,
|
||||
path: '/wrapper-expose/other'
|
||||
}
|
||||
]
|
||||
@ -447,7 +448,10 @@ describe('pages:generateRoutesFromFiles', () => {
|
||||
|
||||
let result
|
||||
try {
|
||||
result = await generateRoutesFromFiles(test.files.map(file => file.path), pagesDir, true, vfs)
|
||||
result = await generateRoutesFromFiles(test.files.map(file => ({
|
||||
absolutePath: file.path,
|
||||
relativePath: file.path.replace(/^(pages|layer\/pages)\//, '')
|
||||
})), true, vfs)
|
||||
} catch (error: any) {
|
||||
expect(error.message).toEqual(test.error)
|
||||
}
|
||||
|
@ -981,6 +981,7 @@ describe('extends support', () => {
|
||||
const html = await $fetch('/override')
|
||||
expect(html).toContain('Extended layout from bar')
|
||||
expect(html).toContain('Extended page from bar')
|
||||
expect(html).toContain('This child page should not be overridden by bar')
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -10,5 +10,6 @@ definePageMeta({
|
||||
<div>Extended page from bar</div>
|
||||
<div>Middleware | override: {{ $route.meta.override }}</div>
|
||||
<ExtendsOverride />
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</template>
|
||||
|
5
test/fixtures/basic/extends/node_modules/foo/pages/override/index.vue
generated
vendored
Normal file
5
test/fixtures/basic/extends/node_modules/foo/pages/override/index.vue
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
This child page should not be overridden by bar
|
||||
</div>
|
||||
</template>
|
Loading…
Reference in New Issue
Block a user