fix(nuxt): Nuxt 3 does not respect layouts in separate folders (#14275)

This commit is contained in:
Aleks 2023-04-11 13:47:47 +10:00
parent 73dda01f67
commit fd0e186a73
3 changed files with 60 additions and 7 deletions

View File

@ -55,7 +55,46 @@ export default defineComponent({
// Need to ensure (if we are not a child of `<NuxtPage>`) that we use synchronous route (not deferred)
const injectedRoute = inject('_route') as RouteLocationNormalizedLoaded
const route = injectedRoute === useRoute() ? useVueRouterRoute() : injectedRoute
const layout = computed(() => unref(props.name) ?? route.meta.layout as string ?? 'default')
const layout = computed(() => {
const layoutName = unref(props.name) ?? route.meta.layout as string ?? 'default'
if (typeof layoutName === 'string') {
const layoutPath = layoutName.replace(/-/g, '/')
// Check if layout exists for example `desktop-default` will translate to `layouts/desktop/default`
if (layoutPath in layouts) {
return layoutPath
}
// Check if layout exists for example `desktop` or `desktop-index` will translate to ` `layouts/desktop/index`
if ((layoutPath + '/index') in layouts) {
return layoutPath + '/index'
}
// If the directory inside layouts has has a dash in the name such as `desktop-base` we need to check for that
if (layoutName.includes('-')) {
const layoutPath = layoutName.replace(/-/g, '/')
// Check if layout exists for example `desktop-base` will translate to `layouts/desktop/base`
if (layoutPath in layouts) {
return layoutPath
}
// Check if layout exists for example `desktop-base` will translate to `layouts/desktop-base/base`
const layoutPathLast = layoutName.split('-').pop()
if (layoutName + '/' + layoutPathLast in layouts) {
return layoutName + '/' + layoutPathLast
}
// Check if layout exists for example `desktop-base` will translate to `layouts/desktop-base/index`
if (layoutName + '/index' in layouts) {
return layoutName + '/index'
}
}
}
return layoutName
})
let vnode: VNode
let _layout: string | false

View File

@ -5,7 +5,7 @@ import { compileTemplate, findPath, normalizePlugin, normalizeTemplate, resolveA
import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate, ResolvedNuxtTemplate } from 'nuxt/schema'
import * as defaultTemplates from './templates'
import { getNameFromPath, hasSuffix, uniqueBy } from './utils'
import { getNameFromPath, getNameFromPathLocal, hasSuffix, uniqueBy } from './utils'
export function createApp (nuxt: Nuxt, options: Partial<NuxtApp> = {}): NuxtApp {
return defu(options, {
@ -85,10 +85,10 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
// Resolve layouts/ from all config layers
app.layouts = {}
for (const config of nuxt.options._layers.map(layer => layer.config)) {
const layoutFiles = await resolveFiles(config.srcDir, `${config.dir?.layouts || 'layouts'}/*{${nuxt.options.extensions.join(',')}}`)
for (const file of layoutFiles) {
const name = getNameFromPath(file)
app.layouts[name] = app.layouts[name] || { name, file }
const layoutFiles = await resolveFiles(config.srcDir, `${config.dir?.layouts || 'layouts'}/**/*{${nuxt.options.extensions.join(',')}}`)
for (const file of layoutFiles) {
const name = getNameFromPathLocal(file, config.srcDir + '/layouts')
app.layouts[name] = app.layouts[name] || { name, file }
}
}

View File

@ -1,10 +1,24 @@
import { basename, extname } from 'pathe'
import { kebabCase, pascalCase } from 'scule'
import { kebabCase, pascalCase, snakeCase } from 'scule'
export function getNameFromPath (path: string) {
return kebabCase(basename(path).replace(extname(path), '')).replace(/["']/g, '')
}
export function getNameFromPathLocal (path: string, src: string) {
const sourcePath = path
.replace(src + '/', '')
.split('/')
.slice(0, -1)
// .map(e => snakeCase(e))
.join('/')
return (
sourcePath +
(sourcePath ? '/' : '') +
kebabCase(basename(path).replace(extname(path), '')).replace(/["']/g, '')
)
}
export function uniqueBy <T, K extends keyof T> (arr: T[], key: K) {
const res: T[] = []
const seen = new Set<T[K]>()