Repository: nuxt/nuxt
File: packages/nuxt/src/core/app.ts (TypeScript)

Code before:
  const extGlob = `{${nuxt.options.extensions.join(',')}}`

  // Resolve main (app.vue)
  const [main, welcome] = await Promise.all([
    findPath(
      layers.flatMap(layer => [
        join(layer.config.srcDir, 'App'),
        join(layer.config.srcDir, 'app'),
      ]),
    ),
    Promise.resolve(resolve(nuxt.options.appDir, 'components/welcome.vue')),
  ])
  app.mainComponent ||= main || welcome
  // Resolve root component
  app.rootComponent ||= await findPath(['~/app.root', resolve(nuxt.options.appDir, 'components/nuxt-root.vue')])

  // Resolve error component
  app.errorComponent ||= (await findPath(
    layers.map(layer => join(layer.config.srcDir, 'error')),
  )) ?? resolve(nuxt.options.appDir, 'components/nuxt-error-page.vue')

  // Resolve layouts/ from all config layers
  app.layouts = {}
  for (const config of layerConfigs) {
    const layoutDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options.dir : config.dir)?.layouts || 'layouts'
    const layoutFiles = await resolveFiles(config.srcDir, `${layoutDir}/**/*{${extGlob}}}`)
    for (const file of layoutFiles) {
      const name = getNameFromPath(file, resolve(config.srcDir, layoutDir))
      if (!name) {
        // Ignore files like `~/layouts/index.vue` which end up not having a name at all
        logger.warn(`No layout name could be resolved for \`~/${relative(nuxt.options.srcDir, file)}\`. Bear in mind that \`index\` is ignored for the purpose of creating a layout name.`)
        continue
      }
      app.layouts[name] ||= { name, file }
    }
  }

  // Resolve middleware/ from all config layers, layers first
  app.middleware = []
  for (const config of reversedConfigs) {
    const middlewareDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options.dir : config.dir)?.middleware || 'middleware'
    const middlewareFiles = await resolveFiles(config.srcDir, [
      `${middlewareDir}/*{${extGlob}}`,
      ...nuxt.options.future.compatibilityVersion === 4
        ? [`${middlewareDir}/*/index{${extGlob}}`]
        : [],
    ])
    for (const file of middlewareFiles) {
      const name = getNameFromPath(file)
      if (!name) {
        // Ignore files like `~/middleware/index.vue` which end up not having a name at all

Review comment (bug):
The 'extGlob' variable is already defined with curly braces, so wrapping it with additional braces may produce an incorrect glob pattern. Consider updating the pattern to `${layoutDir}/**/*${extGlob}`.
```suggestion
    const layoutFiles = await resolveFiles(config.srcDir, `${layoutDir}/**/*${extGlob}`)
```

Code after:
      join(layer.config.srcDir, 'App'),
      join(layer.config.srcDir, 'app'),
    ]),
  )
  app.mainComponent ||= resolve(nuxt.options.appDir, 'components/welcome.vue')

  // Resolve root component
  app.rootComponent ||= await findPath(['~/app.root', resolve(nuxt.options.appDir, 'components/nuxt-root.vue')])

  // Resolve error component
  app.errorComponent ||= (await findPath(
    nuxt.options._layers.map(layer => join(layer.config.srcDir, 'error')),
  )) ?? resolve(nuxt.options.appDir, 'components/nuxt-error-page.vue')

  const extensionGlob = nuxt.options.extensions.join(',')

  // Resolve layouts/ from all config layers
  const layerConfigs = nuxt.options._layers.map(layer => layer.config)
  const reversedConfigs = layerConfigs.slice().reverse()
  app.layouts = {}
  for (const config of layerConfigs) {
    const layoutDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options.dir : config.dir)?.layouts || 'layouts'
    const layoutFiles = await resolveFiles(config.srcDir, `${layoutDir}/**/*{${extensionGlob}}`)
    for (const file of layoutFiles) {
      const name = getNameFromPath(file, resolve(config.srcDir, layoutDir))
      if (!name) {
        // Ignore files like `~/layouts/index.vue` which end up not having a name at all
        logger.warn(`No layout name could be resolved for \`~/${relative(nuxt.options.srcDir, file)}\`. Bear in mind that \`index\` is ignored for the purpose of creating a layout name.`)
        continue
      }
      app.layouts[name] ||= { name, file }
    }
  }

  // Resolve middleware/ from all config layers, layers first
  app.middleware = []
  for (const config of reversedConfigs) {
    const middlewareDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options.dir : config.dir)?.middleware || 'middleware'
    const middlewareFiles = await resolveFiles(config.srcDir, [
      `${middlewareDir}/*{${extensionGlob}}`,
      ...nuxt.options.future.compatibilityVersion === 4
        ? [`${middlewareDir}/*/index{${extensionGlob}}`]
        : [],
    ])
    for (const file of middlewareFiles) {
      const name = getNameFromPath(file)
      if (!name) {
        // Ignore files like `~/middleware/index.vue` which end up not having a name at all
        logger.warn(`No middleware name could be resolved for \`~/${relative(nuxt.options.srcDir, file)}\`. Bear in mind that \`index\` is ignored for the purpose of creating a middleware name.`)
        continue
      }