Repository: nuxt/nuxt
Pull request #31507: fix(nuxt): ensure layer array-type config is merged in order
Author: login: aadamcik
Labels: name: 3.x
name: 🐛 bug
description: Something isn't working as expected
Created: 2025-03-23T16:19:32Z | Merged: 2025-03-31T10:27:37Z

### 🔗 Linked issue

- #25719

### 📚 Description

This PR fixes the the incorrect order of array values in config when using layers.

- Resolves #25719 


Linked issue #25719: Incorrect order of modules: modules from project root are loaded before the ones in layer
### Environment

- Operating System: Linux
- Node Version:     v18.18.0
- Nuxt Version:     3.10.1
- CLI Version:      3.10.0
- Nitro Version:    2.8.1
- Package Manager:  npm@10.2.3
- Builder:          -
- User Config:      extends, modules
- Runtime Modules:  ()
- Build Modules:    -

### Reproduction

https://stackblitz.com/edit/github-vg4ayj

You can see in the console that the module from the root folder is loaded first.

### Describe the bug

I'd expect modules from any layers to be loaded before the ones in project root.

### Additional context

This issue seems to be in `defu` when merging arrays in config object here https://github.com/unjs/defu/blob/main/src/defu.ts#L33

### Logs

_No response_
Linked issue comments: user: login: bolt-new-by-stackblitz[bot]
created_at: 2024-02-09T17:44:26Z
body: <a href='https://stackblitz.com/~/github.com/nuxt/nuxt/issues/25719?repros=github-vg4ayj'><img src='https://developer.stackblitz.com/img/fix_this_issue_small.svg' alt='Fix this issue in StackBlitz Codeflow' align='left' width='117' height='20'></a> _Start a new pull request in [StackBlitz Codeflow](https://stackblitz.com/~/github.com/nuxt/nuxt/issues/25719?repros=github-vg4ayj)._

- [**github-vg4ayj** (Open reproduction)](https://stackblitz.com/edit/github-vg4ayj?issueRepo=nuxt/nuxt&issueNumber=25719)

author_association: NONE
user: login: danielroe
created_at: 2024-02-13T09:49:51Z
body: @pi0 do you think we could revisit merging order for `c12`?
author_association: MEMBER
user: login: danielroe
created_at: 2024-02-16T11:09:52Z
body: Tracking in https://github.com/unjs/c12/issues/138.
author_association: MEMBER
user: login: jwahdatehagh
created_at: 2024-09-17T16:02:48Z
body: Somewhat confused right now how to deal with the ordering of layer config.

E.g. when defining CSS, you'd want the order to be `root layer -> ... -> application` (https://github.com/nuxt/nuxt/issues/25167).

Same for resolving layer/module tree (e.g. if a layer extends another module the main application would expect this to be loaded before its own registered layers/application code)?
author_association: CONTRIBUTOR

Diff:
diff --git a/packages/kit/src/loader/config.ts b/packages/kit/src/loader/config.ts
index eb1450e1142e..7e192c77be0f 100644
--- a/packages/kit/src/loader/config.ts
+++ b/packages/kit/src/loader/config.ts
@@ -6,7 +6,7 @@ import type { ConfigLayer, ConfigLayerMeta, LoadConfigOptions } from 'c12'
 import { loadConfig } from 'c12'
 import type { NuxtConfig, NuxtOptions } from '@nuxt/schema'
 import { globby } from 'globby'
-import defu from 'defu'
+import defu, { createDefu } from 'defu'
 import { basename, join, relative } from 'pathe'
 import { resolveModuleURL } from 'exsolve'
 
@@ -17,22 +17,31 @@ export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig
   overrides?: Exclude<LoadConfigOptions<NuxtConfig>['overrides'], Promise<any> | Function>
 }
 
+const merger = createDefu((obj, key, value) => {
+  if (Array.isArray(obj[key]) && Array.isArray(value)) {
+    obj[key] = obj[key].concat(value)
+    return true
+  }
+})
+
 export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<NuxtOptions> {
   // Automatically detect and import layers from `~~/layers/` directory
   const localLayers = await globby('layers/*', { onlyDirectories: true, cwd: opts.cwd || process.cwd() })
-  opts.overrides = defu(opts.overrides, { _extends: localLayers });
+  opts.overrides = defu(opts.overrides, { _extends: localLayers })
 
-  (globalThis as any).defineNuxtConfig = (c: any) => c
+  const globalSelf = globalThis as any
+  globalSelf.defineNuxtConfig = (c: any) => c
   const { configFile, layers = [], cwd, config: nuxtConfig, meta } = await loadConfig<NuxtConfig>({
     name: 'nuxt',
     configFile: 'nuxt.config',
     rcFile: '.nuxtrc',
-    extend: { extendKey: ['theme', 'extends', '_extends'] },
+    extend: { extendKey: ['theme', '_extends', 'extends'] },
     dotenv: true,
     globalRc: true,
+    merger: merger as any, // TODO: fix type in c12, it should accept createDefu directly
     ...opts,
   })
-  delete (globalThis as any).defineNuxtConfig
+  delete globalSelf.defineNuxtConfig
 
   // Fill config
   nuxtConfig.rootDir ||= cwd
diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts
index cacb7f42f9e8..de9b16425360 100644
--- a/packages/nuxt/src/core/nuxt.ts
+++ b/packages/nuxt/src/core/nuxt.ts
@@ -480,53 +480,11 @@ async function initNuxt (nuxt: Nuxt) {
 
   // Init user modules
   await nuxt.callHook('modules:before')
-  const modulesToInstall = new Map<string | NuxtModule, Record<string, any>>()
-
-  const modulePaths = new Set<string>()
-  const specifiedModules = new Set<string>()
-
-  for (const _mod of nuxt.options.modules) {
-    const mod = Array.isArray(_mod) ? _mod[0] : _mod
-    if (typeof mod !== 'string') { continue }
-    const modAlias = resolveAlias(mod)
-    const modPath = resolveModulePath(modAlias, {
-      try: true,
-      from: nuxt.options.modulesDir.map(m => directoryToURL(m.replace(/\/node_modules\/?$/, '/'))),
-      suffixes: ['nuxt', 'nuxt/index', 'module', 'module/index', '', 'index'],
-      extensions: ['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'],
-    })
-    specifiedModules.add(modPath || modAlias)
-  }
 
-  // Automatically register user modules
-  for (const config of nuxt.options._layers.map(layer => layer.config).reverse()) {
-    const modulesDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options : config).dir?.modules || 'modules'
-    const layerModules = await resolveFiles(config.srcDir, [
-      `${modulesDir}/*{${nuxt.options.extensions.join(',')}}`,
-      `${modulesDir}/*/index{${nuxt.options.extensions.join(',')}}`,
-    ])
-    for (const mod of layerModules) {
-      modulePaths.add(mod)
-      if (specifiedModules.has(mod)) { continue }
-      specifiedModules.add(mod)
-      modulesToInstall.set(mod, {})
-    }
-  }
+  const { paths: modulePaths, modules } = await resolveModules(nuxt)
 
   nuxt.options.watch.push(...modulePaths)
 
-  // Register user and then ad-hoc modules
-  for (const key of ['modules', '_modules'] as const) {
-    for (const item of nuxt.options[key as 'modules']) {
-      if (item) {
-        const [key, options = {}] = Array.isArray(item) ? item : [item]
-        if (!modulesToInstall.has(key)) {
-          modulesToInstall.set(key, options)
-        }
-      }
-    }
-  }
-
   // Add <NuxtWelcome>
   // TODO: revert when deep server component config is properly bundle-split: https://github.com/nuxt/nuxt/pull/29956
   const islandsConfig = nuxt.options.experimental.componentIslands
@@ -645,7 +603,7 @@ async function initNuxt (nuxt: Nuxt) {
     addPlugin(resolve(nuxt.options.appDir, 'plugins/browser-devtools-timing.client'))
   }
 
-  for (const [key, options] of modulesToInstall) {
+  for (const [key, options] of modules) {
     await installModule(key, options)
   }
 
@@ -655,6 +613,10 @@ async function initNuxt (nuxt: Nuxt) {
 
   await nuxt.callHook('modules:done')
 
+  // remove duplicate css after modules are done
+  nuxt.options.css = nuxt.options.css
+    .filter((value, index, array) => !array.includes(value, index + 1))
+
   // Add <NuxtIsland>
   if (nuxt.options.experimental.componentIslands) {
     addComponent({
@@ -816,21 +778,6 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
     options.app.head[key as 'link'] = deduplicateArray(options.app.head[key as 'link'])
   }
 
-  // Ensure CSS from project overrides CSS from layers
-  const orderedCSS = new Set<string>()
-  const optionsCSS = new Set(options.css)
-  for (const config of options._layers.map(layer => layer.config).reverse()) {
-    for (const style of config.css || []) {
-      if (typeof style === 'string') {
-        // ensure later layer CSS has priority over earlier layers
-        orderedCSS.delete(style)
-        optionsCSS.delete(style)
-        orderedCSS.add(style)
-      }
-    }
-  }
-  options.css = [...orderedCSS, ...optionsCSS]
-
   // Nuxt DevTools only works for Vite
   if (options.builder === '@nuxt/vite-builder') {
     const isDevToolsEnabled = typeof options.devtools === 'boolean'
@@ -988,6 +935,97 @@ function createPortalProperties (sourceValue: any, options: NuxtOptions, paths:
   }
 }
 
+function resolveModule (
+  definition: NuxtModule<any> | string | false | undefined | null | [(NuxtModule | string)?, Record<string, any>?],
+  nuxt: Nuxt,
+): { resolvedPath?: string, module: string | NuxtModule<any>, options: Record<string, any> } | undefined {
+  const [module, options = {}] = Array.isArray(definition) ? definition : [definition, {}]
+
+  if (!module) {
+    return
+  }
+
+  if (typeof module !== 'string') {
+    return {
+      module,
+      options,
+    }
+  }
+
+  const modAlias = resolveAlias(module)
+  const modPath = resolveModulePath(modAlias, {
+    try: true,
+    from: nuxt.options.modulesDir.map(m => directoryToURL(m.replace(/\/node_modules\/?$/, '/'))),
+    suffixes: ['nuxt', 'nuxt/index', 'module', 'module/index', '', 'index'],
+    extensions: ['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'],
+  })
+
+  return {
+    module,
+    resolvedPath: modPath || modAlias,
+    options,
+  }
+}
+
+async function resolveModules (nuxt: Nuxt) {
+  const modules = new Map<string | NuxtModule, Record<string, any>>()
+  const paths = new Set<string>()
+  const resolvedModulePaths = new Set<string>()
+
+  // Loop layers in reverse order, so that the extends are loaded first and project is the last
+  const configs = nuxt.options._layers.map(layer => layer.config).reverse()
+  for (const config of configs) {
+    // First register modules defined in layer's config
+    const definedModules = config.modules ?? []
+    for (const module of definedModules) {
+      const resolvedModule = resolveModule(module, nuxt)
+      if (resolvedModule && (!resolvedModule.resolvedPath || !resolvedModulePaths.has(resolvedModule.resolvedPath))) {
+        modules.set(resolvedModule.module, resolvedModule.options)
+        const path = resolvedModule.resolvedPath || typeof resolvedModule.module
+        if (typeof path === 'string') {
+          resolvedModulePaths.add(path)
+        }
+      }
+    }
+
+    // Secondly automatically register modules from layer's module directory
+    const modulesDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options : config).dir?.modules || 'modules'
+    const layerModules = await resolveFiles(config.srcDir, [
+      `${modulesDir}/*{${nuxt.options.extensions.join(',')}}`,
+      `${modulesDir}/*/index{${nuxt.options.extensions.join(',')}}`,
+    ])
+
+    for (const module of layerModules) {
+      // add path to watch
+      paths.add(module)
+
+      if (!modules.has(module)) {
+        modules.set(module, {})
+      }
+    }
+  }
+
+  // Lastly register private modules and modules added after loading config
+  for (const key of ['modules', '_modules'] as const) {
+    for (const module of nuxt.options[key as 'modules']) {
+      const resolvedModule = resolveModule(module, nuxt)
+
+      if (resolvedModule && !modules.has(resolvedModule.module) && (!resolvedModule.resolvedPath || !resolvedModulePaths.has(resolvedModule.resolvedPath))) {
+        modules.set(resolvedModule.module, resolvedModule.options)
+        const path = resolvedModule.resolvedPath || typeof resolvedModule.module
+        if (typeof path === 'string') {
+          resolvedModulePaths.add(path)
+        }
+      }
+    }
+  }
+
+  return {
+    paths,
+    modules,
+  }
+}
+
 const _getDefaultNuxtConfig = () => /* js */
   `// https://nuxt.com/docs/api/configuration/nuxt-config
 export default defineNuxtConfig({
diff --git a/packages/nuxt/test/layers-fixture/custom/module.ts b/packages/nuxt/test/layers-fixture/custom/module.ts
new file mode 100644
index 000000000000..510e0b6f569d
--- /dev/null
+++ b/packages/nuxt/test/layers-fixture/custom/module.ts
@@ -0,0 +1 @@
+export default function customLayerModule () {}
diff --git a/packages/nuxt/test/layers-fixture/custom/modules/module.ts b/packages/nuxt/test/layers-fixture/custom/modules/module.ts
new file mode 100644
index 000000000000..0680e9a55400
--- /dev/null
+++ b/packages/nuxt/test/layers-fixture/custom/modules/module.ts
@@ -0,0 +1 @@
+export default function customLayerAutoModule () {}
diff --git a/packages/nuxt/test/layers-fixture/custom/nuxt.config.ts b/packages/nuxt/test/layers-fixture/custom/nuxt.config.ts
index 76e7c6b5db32..2e558b418497 100644
--- a/packages/nuxt/test/layers-fixture/custom/nuxt.config.ts
+++ b/packages/nuxt/test/layers-fixture/custom/nuxt.config.ts
@@ -1,3 +1,7 @@
 export default defineNuxtConfig({
+  modules: [
+    function customLayerInlineModule () {},
+    import.meta.dirname + '/module',
+  ],
   css: ['custom.css'],
 })
diff --git a/packages/nuxt/test/layers-fixture/layers/auto/module.ts b/packages/nuxt/test/layers-fixture/layers/auto/module.ts
new file mode 100644
index 000000000000..9fd29852cd14
--- /dev/null
+++ b/packages/nuxt/test/layers-fixture/layers/auto/module.ts
@@ -0,0 +1 @@
+export default function autoLayerModule () {}
diff --git a/packages/nuxt/test/layers-fixture/layers/auto/modules/module.ts b/packages/nuxt/test/layers-fixture/layers/auto/modules/module.ts
new file mode 100644
index 000000000000..f4554ca4379c
--- /dev/null
+++ b/packages/nuxt/test/layers-fixture/layers/auto/modules/module.ts
@@ -0,0 +1 @@
+export default function autoLayerAutoModule () {}
diff --git a/packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts b/packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts
index f0d5a46c5951..ea41ed73362b 100644
--- a/packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts
+++ b/packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts
@@ -1,3 +1,7 @@
 export default defineNuxtConfig({
+  modules: [
+    function autoLayerInlineModule () {},
+    import.meta.dirname + '/module',
+  ],
   css: ['duplicate.css', 'auto.css'],
 })
diff --git a/packages/nuxt/test/layers-fixture/module.ts b/packages/nuxt/test/layers-fixture/module.ts
new file mode 100644
index 000000000000..6d50895f1e69
--- /dev/null
+++ b/packages/nuxt/test/layers-fixture/module.ts
@@ -0,0 +1 @@
+export default function projectModule () {}
diff --git a/packages/nuxt/test/layers-fixture/modules/module.ts b/packages/nuxt/test/layers-fixture/modules/module.ts
new file mode 100644
index 000000000000..5f4a210294b3
--- /dev/null
+++ b/packages/nuxt/test/layers-fixture/modules/module.ts
@@ -0,0 +1 @@
+export default function projectAutoModule () {}
diff --git a/packages/nuxt/test/layers-fixture/nuxt.config.ts b/packages/nuxt/test/layers-fixture/nuxt.config.ts
index 52a123b021c2..340c5dade90a 100644
--- a/packages/nuxt/test/layers-fixture/nuxt.config.ts
+++ b/packages/nuxt/test/layers-fixture/nuxt.config.ts
@@ -1,7 +1,9 @@
 export default defineNuxtConfig({
   extends: ['./custom'],
   modules: [
-    function (_options, nuxt) {
+    import.meta.dirname + '/module',
+    function projectInlineModule () {},
+    function css (_options, nuxt) {
       nuxt.options.css.push('new-css-added-by-module.css')
     },
   ],
diff --git a/packages/nuxt/test/load-nuxt.test.ts b/packages/nuxt/test/load-nuxt.test.ts
index 0c215093732e..75b1127426ae 100644
--- a/packages/nuxt/test/load-nuxt.test.ts
+++ b/packages/nuxt/test/load-nuxt.test.ts
@@ -60,8 +60,8 @@ describe('loadNuxt', () => {
 
     expect(nuxt.options.css).toMatchInlineSnapshot(`
       [
-        "auto.css",
         "custom.css",
+        "auto.css",
         "final-project.css",
         "duplicate.css",
         "override.css",
@@ -107,6 +107,36 @@ describe('loadNuxt', () => {
 
     expect(loggerWarn).not.toHaveBeenCalled()
   })
+
+  it('ensures layer modules remain in order', async () => {
+    const layerFixtureDir = withoutTrailingSlash(normalize(fileURLToPath(new URL('./layers-fixture', import.meta.url))))
+    const nuxt = await loadNuxt({ cwd: layerFixtureDir })
+    await nuxt.close()
+
+    const modules = nuxt.options._installedModules.map(item => item.meta.name ?? item.module.name)
+
+    expect(modules).toMatchInlineSnapshot(`
+      [
+        "customLayerInlineModule",
+        "customLayerModule",
+        "customLayerAutoModule",
+        "autoLayerInlineModule",
+        "autoLayerModule",
+        "autoLayerAutoModule",
+        "projectModule",
+        "projectInlineModule",
+        "css",
+        "projectAutoModule",
+        "@nuxt/devtools",
+        "nuxt:pages",
+        "nuxt:meta",
+        "nuxt:components",
+        "nuxt:imports",
+        "nuxt:nuxt-config-schema",
+        "@nuxt/telemetry",
+      ]
+    `)
+  })
 })
 
 const pagesDetectionTests: [test: string, overrides: NuxtConfig, result: NuxtConfig['pages']][] = [
diff --git a/packages/nuxt/test/shared-dir-config.test.ts b/packages/nuxt/test/shared-dir-config.test.ts
index c066a98327d3..7483dd69bf70 100644
--- a/packages/nuxt/test/shared-dir-config.test.ts
+++ b/packages/nuxt/test/shared-dir-config.test.ts
@@ -19,10 +19,10 @@ describe('loadNuxt', () => {
         "<rootDir>/shared/types",
         "<rootDir>/extends/bar/shared/utils",
         "<rootDir>/extends/bar/shared/types",
-        "<rootDir>/extends/node_modules/foo/shared/utils",
-        "<rootDir>/extends/node_modules/foo/shared/types",
         "<rootDir>/layers/bar/shared/utils",
         "<rootDir>/layers/bar/shared/types",
+        "<rootDir>/extends/node_modules/foo/shared/utils",
+        "<rootDir>/extends/node_modules/foo/shared/types",
       ]
     `)
   })


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (5)</summary><blockquote>

<details>
<summary>packages/nuxt/test/layers-fixture/custom/module.ts (1)</summary><blockquote>

`1-1`: **Consider adding JSDoc documentation**

Even for test modules, adding documentation can help clarify the purpose and expected behaviour of this module. This is especially useful for other developers who may be working with these test fixtures.


```diff
+/**
+ * Custom test module for Nuxt layers functionality
+ */
 export default function custom () {}
```

</blockquote></details>
<details>
<summary>packages/nuxt/src/core/utils/index.ts (1)</summary><blockquote>

`4-6`: **Consider using a Set for better performance**

The current implementation has O(n²) time complexity because `indexOf` performs a linear search for each element. For larger arrays, this could be inefficient. Consider using a Set for O(n) performance, similar to the `uniqueBy` function below.


```diff
 export function unique<T> (array: readonly T[]): T[] {
-  return array.filter((value, index) => array.indexOf(value) === index)
+  return [...new Set(array)]
 }
```

</blockquote></details>
<details>
<summary>packages/nuxt/test/layers-fixture/custom/nuxt.config.ts (1)</summary><blockquote>

`2-2`: **Consider using path utilities for cross-platform compatibility**

While the current implementation works for test fixtures, using string concatenation for paths can cause issues on different operating systems. For better cross-platform compatibility, consider using a path utility.


```diff
-  modules: [import.meta.dirname + '/module'],
+  modules: [import.meta.dirname + '/module'.replace(/\//g, path.sep)],
```

Note that you would need to import the `path` module at the top of the file:

```typescript
import path from 'path'
```

</blockquote></details>
<details>
<summary>packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts (1)</summary><blockquote>

`2-2`: **Consider extracting the inline module function**

For better readability and maintainability, consider extracting the inline function definition to a separate constant or file, even in test fixtures.


```diff
+function layer() {}
+
 export default defineNuxtConfig({
-  modules: [function layer () {}],
+  modules: [layer],
   css: ['duplicate.css', 'auto.css'],

   array: ['test'],
 })
```

</blockquote></details>
<details>
<summary>packages/kit/src/loader/config.ts (1)</summary><blockquote>

`51-51`: **Consider using undefined assignment instead of delete operator.**

The delete operator can have performance implications. Consider using an undefined assignment instead.

```diff
-delete globalSelf.defineNuxtConfig
+globalSelf.defineNuxtConfig = undefined
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 51-51: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 36e5cfdd056a20065cee618f019f63ca5cf57a33 and cc7309bd27e1b0307d2c266cd8bbd9ea6dff96dd.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `packages/kit/src/loader/config.ts` (2 hunks)
* `packages/nuxt/src/core/nuxt.ts` (3 hunks)
* `packages/nuxt/src/core/utils/index.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/load-nuxt.test.ts` (2 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (3)</summary><blockquote>

<details>
<summary>packages/kit/src/resolve.ts (1)</summary>

* `resolveAlias` (74-77)

</details>
<details>
<summary>packages/kit/src/internal/esm.ts (1)</summary>

* `directoryToURL` (13-15)

</details>
<details>
<summary>packages/nuxt/src/core/utils/index.ts (1)</summary>

* `unique` (4-6)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/kit/src/loader/config.ts</summary>

[error] 51-51: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: codeql (javascript-typescript)
* GitHub Check: build
* GitHub Check: code

</details>

<details>
<summary>🔇 Additional comments (13)</summary><blockquote>

<details>
<summary>packages/kit/src/loader/config.ts (4)</summary>

`9-9`: **Update to defu import for extended functionality.**

The change imports `createDefu` in addition to the existing `defu` import. This extension enables custom merging strategies for configuration values.

---

`20-32`: **Well-implemented custom merger function for array handling.**

This new custom merger function addresses the core issue with array values in configuration by:
1. Concatenating arrays when merging configurations from different layers
2. Supporting function-based overrides that can modify or replace array values

This implementation elegantly solves issue #25719 mentioned in the PR objectives, allowing users to completely override array values by returning an empty array.

---

`39-41`: **Improved global variable handling.**

Using a local variable before defining and deleting the global function improves code clarity and makes the intent more explicit.

---

`48-48`: **Added custom merger function to loadConfig with clear TODO.**

The merger function is properly integrated into the configuration loading process. The TODO comment clearly indicates the need for type improvements in the c12 library.

</details>
<details>
<summary>packages/nuxt/test/load-nuxt.test.ts (3)</summary>

`63-63`: **Appropriately updated test expectations to include duplicate.css.**

This change correctly updates the test expectations to match the new behavior where duplicate CSS entries are preserved in the initial loading but later deduplicated using the `unique` function in `initNuxt`.

---

`111-126`: **Added test to verify correct module order from layers.**

This test ensures that modules from layers are correctly ordered in the final configuration, validating the change to module registration logic in the `initNuxt` function. The test correctly verifies that the modules appear in the expected order: layer, custom module, project, and css.

---

`128-138`: **Added test to verify array value overrides.**

This test validates the new ability to override array values in the configuration by using functions, specifically checking that the `array` property in the configuration has been properly overridden with the value from the project layer.

</details>
<details>
<summary>packages/nuxt/src/core/nuxt.ts (3)</summary>

`56-56`: **Added import for the unique function.**

Importing the `unique` function for deduplicating CSS entries is appropriate and ensures proper code organization.

---

`489-516`: **Improved module registration logic.**

The restructured code properly handles module registration in the correct order:
1. First processes modules from reversed layers to maintain proper precedence
2. Resolves module paths correctly
3. Adds modules to the specifiedModules set to prevent duplication

This addresses the core issue mentioned in the PR objectives regarding the incorrect order of array values in configuration.

---

`661-661`: **Added deduplication of CSS entries.**

Using the `unique` function to deduplicate CSS entries after all modules have been processed ensures that the final CSS list is clean while still maintaining the correct order of entries from layers.

</details>
<details>
<summary>packages/nuxt/test/layers-fixture/nuxt.config.ts (3)</summary>

`4-5`: **Added named functions for better readability.**

Naming the functions `project` and `css` improves code readability and makes it clear what each module function is responsible for.

---

`11-11`: **Added function that returns an array for testing override functionality.**

This implementation demonstrates the new ability to override array values by returning a function that produces a new array. This is a key feature that addresses the PR objectives for allowing complete overrides of array values.

---

`14-18`: **Added type definition for the new array property.**

The type declaration properly extends the NuxtConfig interface to include the new array property, which can be either an array of strings or a function returning an array of strings. This ensures proper TypeScript support for the new feature.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-23T16:22:29Z
user: login: danielroe
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T09:45:48Z
user: login: danielroe
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T09:47:42Z
user: login: aadamcik
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T09:22:57Z
user: login: aadamcik
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T09:26:34Z
user: login: danielroe
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T10:23:30Z
user: login: danielroe
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-26T10:47:58Z
user: login: aadamcik
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T11:30:02Z
user: login: aadamcik
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T11:30:14Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>packages/kit/src/loader/config.ts (2)</summary><blockquote>

`30-30`: **Consider using the new merger here as well.**

You're using the standard `defu` for merging `opts.overrides` instead of the custom `merger` function you've created. This might lead to inconsistent merging behavior.


```diff
-  opts.overrides = defu(opts.overrides, { _extends: localLayers })
+  opts.overrides = merger(opts.overrides, { _extends: localLayers })
```

---

`44-44`: **Potential performance issue with delete operator.**

Using the `delete` operator can impact performance as noted by the static analysis tool. Consider assigning undefined instead.


```diff
-  delete globalSelf.defineNuxtConfig
+  globalSelf.defineNuxtConfig = undefined
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 2a68d20e3cb39fd49250e5f2cabf33e01bfa91af and c19e70216ffaf2b2dfc7413f1268b97a36716efb.

</details>

<details>
<summary>📒 Files selected for processing (7)</summary>

* `packages/kit/src/loader/config.ts` (2 hunks)
* `packages/nuxt/src/core/nuxt.ts` (2 hunks)
* `packages/nuxt/test/layers-fixture/custom/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/load-nuxt.test.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (5)</summary>

* packages/nuxt/test/layers-fixture/custom/module.ts
* packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts
* packages/nuxt/test/layers-fixture/custom/nuxt.config.ts
* packages/nuxt/test/load-nuxt.test.ts
* packages/nuxt/test/layers-fixture/nuxt.config.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (2)</summary><blockquote>

<details>
<summary>packages/kit/src/resolve.ts (1)</summary>

* `resolveAlias` (74-77)

</details>
<details>
<summary>packages/kit/src/internal/esm.ts (1)</summary>

* `directoryToURL` (13-15)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/kit/src/loader/config.ts</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: build

</details>

<details>
<summary>🔇 Additional comments (6)</summary><blockquote>

<details>
<summary>packages/kit/src/loader/config.ts (4)</summary>

`9-9`: **Good addition of the createDefu import.**

The inclusion of `createDefu` allows for creating a custom merging strategy for configuration values.

---

`20-25`: **Well-implemented array concatenation merger.**

This custom merger function elegantly solves the issue mentioned in the PR objectives regarding the order of array values in configuration. When both the existing value and the new value are arrays, they are concatenated, preserving their order.

---

`32-33`: **Good practice to use a local variable.**

Creating a local `globalSelf` variable improves code clarity and makes it easier to understand the scope of operations.

---

`41-41`: **TODO comment for future improvement.**

The TODO comment appropriately flags a type issue with c12 that should be addressed in the future. This is good practice to document known issues.

</details>
<details>
<summary>packages/nuxt/src/core/nuxt.ts (2)</summary>

`488-502`: **Well-structured module registration approach.**

The new approach organizes module registration by iterating over layers in reverse order, which ensures proper precedence. This implementation aligns with the PR objective of fixing the order of values in config when utilizing layers.

---

`659-661`: <details>
<summary>✅ Verification successful</summary>

**CSS deduplication logic changed.**

Your implementation now keeps the first occurrence of duplicate CSS entries rather than the last one. This differs from the previous behaviour where CSS added explicitly in a project had priority (as mentioned in previous comments).


Based on past review comments, this change in behaviour was discussed and appears to be intentional, but you should verify that this is the desired outcome for all use cases. Run this script to compare the order of CSS entries with the new implementation:

---

🏁 Script executed:

```shell
#!/bin/bash
# Verify CSS deduplication behavior with the new implementation

# Look for tests that might be affected by this change
rg -A 5 "options.css" packages/nuxt/test/

# Check if there are any snapshots containing CSS entries
rg -l "css:" packages/nuxt/test/
```

Length of output: 1075

---



</details>

**CSS Deduplication Behaviour Confirmed**

The updated deduplication logic has been verified against the test snapshots. The tests in `packages/nuxt/test/load-nuxt.test.ts` (and related layer fixtures) now expect the array to retain the first occurrence of duplicate CSS entries, which aligns with the new implementation. No further changes are required.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T11:32:27Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>packages/nuxt/test/load-nuxt.test.ts (1)</summary><blockquote>

`111-126`: **New test case ensures module order preservation**

This test case correctly verifies that module ordering is maintained when loading Nuxt from a layered configuration, which aligns with the PR's objective of fixing the order of array values in the configuration.

However, I noticed that the inline snapshot contains an absolute path:
```
"/home/runner/work/nuxt/nuxt/packages/nuxt/test/layers-fixture/custom/module"
```

This may cause test failures if run in different environments where the absolute path structure differs.

Consider normalising this path in the test assertions to make it environment-independent:

```diff
- const modules = nuxt.options.modules.map(item => typeof item === 'function' ? item.name : item)
+ const modules = nuxt.options.modules.map(item => {
+   if (typeof item === 'function') return item.name
+   // Convert absolute paths to relative or normalised format
+   if (typeof item === 'string' && item.includes('/layers-fixture/')) {
+     return item.split('/layers-fixture/')[1]
+   }
+   return item
+ })
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between c19e70216ffaf2b2dfc7413f1268b97a36716efb and 13baf7f4ade77e485e4f80484aaf4dcaafa4f295.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `packages/nuxt/test/layers-fixture/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/load-nuxt.test.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* packages/nuxt/test/layers-fixture/nuxt.config.ts

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: build
* GitHub Check: codeql (javascript-typescript)
* GitHub Check: code

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T11:38:05Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>packages/kit/src/loader/config.ts (1)</summary><blockquote>

`32-44`: **Consider replacing the delete operator with an undefined assignment.**

The static analysis tool flagged performance concerns with the `delete` operator. While this is unlikely to be a bottleneck as it's only called once during initialisation, it might be worth considering the recommended fix.

```diff
- delete globalSelf.defineNuxtConfig
+ globalSelf.defineNuxtConfig = undefined
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 13baf7f4ade77e485e4f80484aaf4dcaafa4f295 and b505495f86f74120b1b6876330edc89a37a38170.

</details>

<details>
<summary>📒 Files selected for processing (7)</summary>

* `packages/kit/src/loader/config.ts` (2 hunks)
* `packages/nuxt/src/core/nuxt.ts` (2 hunks)
* `packages/nuxt/test/layers-fixture/custom/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/load-nuxt.test.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (4)</summary>

* packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts
* packages/nuxt/test/layers-fixture/custom/module.ts
* packages/nuxt/test/layers-fixture/custom/nuxt.config.ts
* packages/nuxt/test/layers-fixture/nuxt.config.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/kit/src/loader/config.ts</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: build
* GitHub Check: code

</details>

<details>
<summary>🔇 Additional comments (7)</summary><blockquote>

<details>
<summary>packages/nuxt/test/load-nuxt.test.ts (1)</summary>

`111-126`: **Good test addition to ensure module order is preserved.**

This test ensures that modules from layers are registered in the expected order after loading a Nuxt instance. It properly validates the changes made to the module registration logic in `packages/nuxt/src/core/nuxt.ts` where modules are now processed in reverse order from the layers.

</details>
<details>
<summary>packages/kit/src/loader/config.ts (4)</summary>

`9-9`: **Good update to include createDefu for enhanced merging logic.**

The addition of `createDefu` from the defu library is a good choice for implementing custom array concatenation behaviour for the configuration merger.

---

`20-25`: **Well implemented array concatenation logic.**

This new `merger` function provides a clean solution for the PR's objective of fixing array value order in configurations. It checks if both values are arrays and concatenates them, preserving the order from each layer.

---

`30-30`: **Using standard defu for this override is correct.**

For the `_extends` property, using the standard `defu` function instead of the custom `merger` is appropriate since we don't want to concatenate arrays in this specific case.

---

`41-41`: **This TODO comment is reasonable for now.**

The comment acknowledges that there's a type issue in c12 that should be fixed, and the current cast to `any` is a temporary workaround. It's good to document this for future cleanup.

</details>
<details>
<summary>packages/nuxt/src/core/nuxt.ts (2)</summary>

`488-502`: **Great implementation of layer-based module loading.**

This new approach iterates through layers in reverse order and registers modules from each layer, ensuring that the order of modules is preserved according to the layer structure. This fixes the issue mentioned in the PR objectives about incorrect order of array values in configuration.

---

`659-662`: **Well-implemented CSS deduplication logic.**

The CSS deduplication logic correctly filters out duplicates while preserving the order, ensuring that the first occurrence of each CSS entry is kept while subsequent duplicates are removed. This aligns with the layer CSS test changes.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T15:54:57Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>packages/kit/src/loader/config.ts (1)</summary><blockquote>

`44-44`: **Consider replacing delete operator for better performance.**

The `delete` operator can impact performance as noted by the static analysis tool. Consider using an undefined assignment instead.

```diff
-  delete globalSelf.defineNuxtConfig
+  globalSelf.defineNuxtConfig = undefined
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between a36054bed5a6b60147838ea7f81fbcb0969a5da5 and 19361dd67bfd2289d7109178804a07ce29a0638b.

</details>

<details>
<summary>📒 Files selected for processing (7)</summary>

* `packages/kit/src/loader/config.ts` (2 hunks)
* `packages/nuxt/src/core/nuxt.ts` (2 hunks)
* `packages/nuxt/test/layers-fixture/custom/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/load-nuxt.test.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (5)</summary>

* packages/nuxt/test/layers-fixture/custom/module.ts
* packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts
* packages/nuxt/test/layers-fixture/custom/nuxt.config.ts
* packages/nuxt/test/layers-fixture/nuxt.config.ts
* packages/nuxt/test/load-nuxt.test.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/kit/src/loader/config.ts</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: build
* GitHub Check: code

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (2)</summary>

`488-502`: **Great improvement for module order handling!**

This change ensures correct ordering of modules from different layers by iterating through layers in reverse order, which aligns perfectly with the PR objective of fixing the order of values in configuration when using layers.

---

`659-662`: **Effective implementation of CSS deduplication.**

The updated approach to remove duplicate CSS entries maintains the order while ensuring only the first occurrence of each value is preserved. This is consistent with the discussion in the PR comments about handling CSS duplicates.

</details>
<details>
<summary>packages/kit/src/loader/config.ts (1)</summary>

`20-25`: **Well-implemented array merging strategy.**

The new `merger` function elegantly handles array concatenation for configuration values, which is crucial for maintaining the correct order of arrays when merging configurations from different layers.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T13:35:11Z
user: login: danielroe
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-28T16:58:31Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>♻️ Duplicate comments (1)</summary><blockquote>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (1)</summary><blockquote>

`620-622`: _🛠️ Refactor suggestion_

**Ensure CSS order prioritises project CSS over layer CSS.**

The CSS deduplication logic is using the first occurrence of each value, but based on previous discussions, project CSS should have priority over layer CSS, meaning the last occurrence should be preserved.


```diff
-  nuxt.options.css = nuxt.options.css
-    .filter((value, index, array) => !array.includes(value, index + 1))
+  nuxt.options.css = nuxt.options.css
+    .filter((value, index, array) => array.lastIndexOf(value) === index)
```

This change will keep the last occurrence of each CSS entry, giving priority to project CSS over layer CSS.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>packages/kit/src/loader/config.ts (2)</summary><blockquote>

`30-30`: **Ensure consistent merging strategy.**

For consistency, consider using the new `merger` function here instead of `defu`.


```diff
-  opts.overrides = defu(opts.overrides, { _extends: localLayers })
+  opts.overrides = merger(opts.overrides, { _extends: localLayers })
```

---

`44-44`: **Consider using undefined assignment instead of delete operator.**

The delete operator can impact performance according to the static analysis tool.


```diff
-  delete globalSelf.defineNuxtConfig
+  globalSelf.defineNuxtConfig = undefined
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 19361dd67bfd2289d7109178804a07ce29a0638b and f5b25a81cc3b6c4f88bb7b0e0f7cdfa2b4f9a94d.

</details>

<details>
<summary>📒 Files selected for processing (12)</summary>

* `packages/kit/src/loader/config.ts` (2 hunks)
* `packages/nuxt/src/core/nuxt.ts` (4 hunks)
* `packages/nuxt/test/layers-fixture/custom/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/modules/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/modules/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/modules/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/load-nuxt.test.ts` (1 hunks)

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (3)</summary>

* packages/nuxt/test/layers-fixture/module.ts
* packages/nuxt/test/layers-fixture/modules/module.ts
* packages/nuxt/test/layers-fixture/layers/auto/module.ts

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (4)</summary>

* packages/nuxt/test/layers-fixture/custom/nuxt.config.ts
* packages/nuxt/test/load-nuxt.test.ts
* packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts
* packages/nuxt/test/layers-fixture/nuxt.config.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (3)</summary><blockquote>

<details>
<summary>packages/kit/src/index.ts (4)</summary>

* `resolveModule` (35-35)
* `resolveAlias` (28-28)
* `directoryToURL` (35-35)
* `resolveFiles` (28-28)

</details>
<details>
<summary>packages/kit/src/internal/esm.ts (2)</summary>

* `resolveModule` (34-39)
* `directoryToURL` (13-15)

</details>
<details>
<summary>packages/kit/src/resolve.ts (2)</summary>

* `resolveAlias` (74-77)
* `resolveFiles` (238-247)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/kit/src/loader/config.ts</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: build
* GitHub Check: code

</details>

<details>
<summary>🔇 Additional comments (12)</summary><blockquote>

<details>
<summary>packages/nuxt/test/layers-fixture/layers/auto/modules/module.ts (1)</summary>

`1-1`: **Looks good - appropriate test module structure.**

This empty module function follows the expected pattern for Nuxt module testing fixtures. The clear naming convention (`autoLayerAutoModule`) appropriately indicates its purpose within the layer testing context.

</details>
<details>
<summary>packages/nuxt/test/layers-fixture/custom/module.ts (1)</summary>

`1-1`: **Module implementation looks good**

The function is well-named and follows the proper export syntax for a Nuxt module. The empty implementation is perfectly acceptable for a test fixture module, as it appears to be used primarily for testing module registration and ordering logic rather than actual functionality.

</details>
<details>
<summary>packages/nuxt/test/layers-fixture/custom/modules/module.ts (1)</summary>

`1-1`: **Auto-module implementation looks good**

The function naming with "Auto" in `customLayerAutoModule` suggests this module is designed for automatic discovery and loading when placed in the `modules` directory. This follows Nuxt module conventions and is appropriately implemented with an empty function body for testing purposes.

</details>
<details>
<summary>packages/nuxt/src/core/nuxt.ts (4)</summary>

`484-487`: **Great refactoring to use the new resolveModules function.**

This changes consolidates module resolution into a dedicated function, making the code more maintainable. The destructuring assignment makes it clear what parts of the result are being used.

---

`609-611`: **Clean iteration over resolved modules.**

This change eliminates the previous array iteration complexity and works well with the new structure returned by `resolveModules`.

---

`941-970`: **Well-implemented module resolution function.**

This utility function properly resolves a module definition to a module and options pair, handling both string identifiers and direct module references. It correctly uses `resolveAlias` and `resolveModulePath` to find the actual module path.

---

`972-1020`: **Great implementation of module resolution logic.**

The `resolveModules` function properly handles the order of module resolution:

1. Processes layers in reverse order so that project modules have priority
2. Registers modules defined in each layer's config
3. Registers modules from layer directories 
4. Handles private modules and modules added after loading config

This implementation helps fix the issue with the incorrect order of array values in the configuration when utilizing layers.

</details>
<details>
<summary>packages/kit/src/loader/config.ts (5)</summary>

`9-9`: **Good addition of createDefu import.**

Adding the `createDefu` import is necessary for creating the custom merger function.

---

`20-25`: **Excellent addition of custom array merging strategy.**

The `merger` function elegantly handles array concatenation when both the target and source values are arrays. This is important for preserving the order of configuration values across layers.

---

`32-33`: **Cleaner global context reference.**

Creating a local `globalSelf` variable improves code readability and consistency.

---

`38-39`: **Correctly configured extension keys.**

The extend configuration with multiple extension keys allows for flexible configuration inheritance.

---

`41-42`: **Successfully integrated custom merger.**

The custom merger is now applied to the configuration loading process. The TODO comment appropriately flags a type issue to be addressed in the future.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-29T11:32:15Z
user: login: aadamcik
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-29T11:44:32Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>packages/kit/src/loader/config.ts (1)</summary><blockquote>

`32-33`: **Better approach for global object handling.**

Using a local variable for the global object improves code clarity and maintainability. However, there's a linting warning about using the delete operator which could impact performance.

Consider using an assignment to undefined instead of delete for better performance:

```diff
-  const globalSelf = globalThis as any
-  globalSelf.defineNuxtConfig = (c: any) => c
-  // ... code ...
-  delete globalSelf.defineNuxtConfig
+  const globalSelf = globalThis as any
+  globalSelf.defineNuxtConfig = (c: any) => c
+  // ... code ...
+  globalSelf.defineNuxtConfig = undefined
```


Also applies to: 44-44

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1236fb014c50bde6c51fbb1e79f9c482cd14d3dc and 1946dba8b11e61c4a817d0ad45897a5104dd9ab3.

</details>

<details>
<summary>📒 Files selected for processing (13)</summary>

* `packages/kit/src/loader/config.ts` (2 hunks)
* `packages/nuxt/src/core/nuxt.ts` (4 hunks)
* `packages/nuxt/test/layers-fixture/custom/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/modules/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/custom/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/modules/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/modules/module.ts` (1 hunks)
* `packages/nuxt/test/layers-fixture/nuxt.config.ts` (1 hunks)
* `packages/nuxt/test/load-nuxt.test.ts` (2 hunks)
* `packages/nuxt/test/shared-dir-config.test.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (11)</summary>

* packages/nuxt/test/layers-fixture/module.ts
* packages/nuxt/test/layers-fixture/modules/module.ts
* packages/nuxt/test/layers-fixture/layers/auto/module.ts
* packages/nuxt/test/layers-fixture/custom/module.ts
* packages/nuxt/test/layers-fixture/layers/auto/modules/module.ts
* packages/nuxt/test/layers-fixture/custom/modules/module.ts
* packages/nuxt/test/load-nuxt.test.ts
* packages/nuxt/test/layers-fixture/custom/nuxt.config.ts
* packages/nuxt/test/shared-dir-config.test.ts
* packages/nuxt/test/layers-fixture/nuxt.config.ts
* packages/nuxt/test/layers-fixture/layers/auto/nuxt.config.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (3)</summary><blockquote>

<details>
<summary>packages/kit/src/index.ts (4)</summary>

* `resolveModule` (35-35)
* `resolveAlias` (28-28)
* `directoryToURL` (35-35)
* `resolveFiles` (28-28)

</details>
<details>
<summary>packages/kit/src/internal/esm.ts (2)</summary>

* `resolveModule` (34-39)
* `directoryToURL` (13-15)

</details>
<details>
<summary>packages/kit/src/resolve.ts (2)</summary>

* `resolveAlias` (74-77)
* `resolveFiles` (238-247)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/kit/src/loader/config.ts</summary>

[error] 44-44: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.


(lint/performance/noDelete)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: codeql (javascript-typescript)
* GitHub Check: build
* GitHub Check: code

</details>

<details>
<summary>🔇 Additional comments (9)</summary><blockquote>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (5)</summary>

`484-487`: **Good refactoring to use the new resolveModules function.**

The refactoring improves code structure by separating module resolution logic into a dedicated function. This makes the code more maintainable and easier to understand.

---

`609-611`: **Improved module installation logic.**

The iteration over modules is now clearer and more straightforward, using a destructured map entry approach.

---

`619-622`: **CSS handling keeps first occurrence instead of last.**

The filtering logic keeps the first occurrence of duplicate CSS entries, which changes the previous behaviour where project CSS would override layer CSS. This appears intentional based on the PR discussion.

---

`941-970`: **Well-implemented resolveModule function.**

The new function handles various module definition formats and properly resolves module paths. The approach is robust and accounts for different module formats and resolution scenarios.

---

`972-1020`: **Thorough implementation of resolveModules function.**

This function handles modules from multiple sources:
1. Modules defined in layer configurations
2. Modules from layer directories
3. Private modules and modules added after loading config

The module resolution happens in a logical order, ensuring that the correct precedence is maintained.

</details>
<details>
<summary>packages/kit/src/loader/config.ts (4)</summary>

`9-9`: **Added import for createDefu.**

This import enables the creation of a custom merge strategy for configuration objects.

---

`20-25`: **Good implementation of array concatenation merger.**

The custom merger function ensures that when both values are arrays, they are concatenated rather than replaced. This addresses the core issue of preserving array values in configuration when using layers.

---

`30-30`: **Improved options overrides handling with defu.**

Using defu to merge the overrides with existing options ensures that all properties are properly combined.

---

`41-41`: **Using custom merger for config loading.**

The merger is correctly applied to the loadConfig call, enabling array concatenation in configuration loading. The TODO comment about fixing the type in c12 is appropriate.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-29T11:45:30Z
user: login: danielroe
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-31T08:17:51Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (1)</summary><blockquote>

`970-1027`: **Comprehensive module resolution with proper layer ordering.**

The `resolveModules` function correctly processes layers in reverse order, ensuring project-level modules take precedence. It also handles both explicitly defined modules in config and automatically discovered modules from the layers' module directories.

One note: The function could potentially benefit from some error handling for edge cases where module resolution fails.


Consider adding error handling for cases where module resolution might fail:

```diff
 async function resolveModules (nuxt: Nuxt) {
   const modules = new Map<string | NuxtModule, Record<string, any>>()
   const paths = new Set<string>()
   const resolvedModulePaths = new Set<string>()

   // Loop layers in reverse order, so that the extends are loaded first and project is the last
   const configs = nuxt.options._layers.map(layer => layer.config).reverse()
   for (const config of configs) {
     // First register modules defined in layer's config
     const definedModules = config.modules ?? []
     for (const module of definedModules) {
-      const resolvedModule = resolveModule(module, nuxt)
+      try {
+        const resolvedModule = resolveModule(module, nuxt)
+        if (resolvedModule && (!resolvedModule.resolvedPath || !resolvedModulePaths.has(resolvedModule.resolvedPath))) {
+          modules.set(resolvedModule.module, resolvedModule.options)
+          const path = resolvedModule.resolvedPath || typeof resolvedModule.module
+          if (typeof path === 'string') {
+            resolvedModulePaths.add(path)
+          }
+        }
+      } catch (error) {
+        console.warn(`Failed to resolve module: ${typeof module === 'string' ? module : 'non-string module'}`, error)
+      }
-      if (resolvedModule && (!resolvedModule.resolvedPath || !resolvedModulePaths.has(resolvedModule.resolvedPath))) {
-        modules.set(resolvedModule.module, resolvedModule.options)
-        const path = resolvedModule.resolvedPath || typeof resolvedModule.module
-        if (typeof path === 'string') {
-          resolvedModulePaths.add(path)
-        }
-      }
     }
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1946dba8b11e61c4a817d0ad45897a5104dd9ab3 and 40d5cb71854f8efc9f493068c26d14922d5799ba.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `packages/nuxt/src/core/nuxt.ts` (4 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (4)</summary><blockquote>

<details>
<summary>packages/kit/src/index.ts (3)</summary>

* `resolveModule` (35-35)
* `resolveAlias` (28-28)
* `resolveFiles` (28-28)

</details>
<details>
<summary>packages/kit/src/internal/esm.ts (1)</summary>

* `resolveModule` (34-39)

</details>
<details>
<summary>packages/schema/src/types/nuxt.ts (1)</summary>

* `Nuxt` (89-116)

</details>
<details>
<summary>packages/kit/src/resolve.ts (2)</summary>

* `resolveAlias` (74-77)
* `resolveFiles` (238-247)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: build
* GitHub Check: code

</details>

<details>
<summary>🔇 Additional comments (4)</summary><blockquote>

<details>
<summary>packages/nuxt/src/core/nuxt.ts (4)</summary>

`484-484`: **Clean refactoring to use the new resolveModules function.**

The code now uses a better structured approach by extracting module resolution logic into a dedicated function, making the code more maintainable and easier to reason about.

---

`606-608`: **Simpler module installation loops through the resolved modules.**

This iteration approach is cleaner than the previous implementation, as it directly loops through the structured data returned by `resolveModules`. This makes the code more concise and easier to follow.

---

`617-619`: **New CSS deduplication logic to maintain order.**

The new code maintains CSS order by keeping the first occurrence of any CSS entry and filtering out duplicates that appear later in the array. This addresses the original issue where array-type configurations needed to be merged in the correct order.

---

`938-968`: **Well-structured resolveModule function with proper module path resolution.**

This function handles different types of module definitions (strings, objects, arrays) and provides a standardized output format. The use of `resolveAlias` and `resolveModulePath` with appropriate options ensures robust module resolution across various scenarios.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T10:08:02Z
user: login: danielroe
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-31T10:18:49Z

Review comments:
diff_hunk: @@ -655,6 +657,9 @@ async function initNuxt (nuxt: Nuxt) {
 
   await nuxt.callHook('modules:done')
 
+  // remove duplicate css after modules are done
+  nuxt.options.css = unique(nuxt.options.css)
path: packages/nuxt/src/core/nuxt.ts
user: login: danielroe
body: is there a reason you removed L819-832? these were necessary to ensure not just that the css was de-duplicated, but that it was added in the correct order.

(you can see the test snapshot now mismatches in packages/nuxt/test/load-nuxt.test.ts)
created_at: 2025-03-25T09:45:48Z
author_association: MEMBER
diff_hunk: @@ -17,22 +17,38 @@ export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig
   overrides?: Exclude<LoadConfigOptions<NuxtConfig>['overrides'], Promise<any> | Function>
 }
 
+const merger = createDefu((obj, key, value) => {
+  if (Array.isArray(obj[key])) {
+    if (Array.isArray(value)) {
+      obj[key] = obj[key].concat(value)
+      return true
+    }
+
+    if (typeof value === 'function') {
+      obj[key] = value(obj[key])
+      return true
+    }
path: packages/kit/src/loader/config.ts
user: login: danielroe
body: I am not sure this is always safe as some options actually take functions, for example in `vite.build`.
created_at: 2025-03-25T09:47:42Z
author_association: MEMBER
diff_hunk: @@ -655,6 +657,9 @@ async function initNuxt (nuxt: Nuxt) {
 
   await nuxt.callHook('modules:done')
 
+  // remove duplicate css after modules are done
+  nuxt.options.css = unique(nuxt.options.css)
path: packages/nuxt/src/core/nuxt.ts
user: login: aadamcik
body: This is now handled by the merger function in `packages/kit/src/loader/config.ts`, so the code is no longer necessary.

I changed the snapshot because I think the order was wrong before. In case of duplicates, it would use the later one, now it uses the first occurrence of duplicate.
If you believe it was correct before, I'll just update the unique function, to use the latest occurrence.
created_at: 2025-03-26T09:22:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,22 +17,38 @@ export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig
   overrides?: Exclude<LoadConfigOptions<NuxtConfig>['overrides'], Promise<any> | Function>
 }
 
+const merger = createDefu((obj, key, value) => {
+  if (Array.isArray(obj[key])) {
+    if (Array.isArray(value)) {
+      obj[key] = obj[key].concat(value)
+      return true
+    }
+
+    if (typeof value === 'function') {
+      obj[key] = value(obj[key])
+      return true
+    }
path: packages/kit/src/loader/config.ts
user: login: aadamcik
body: It will only execute the function if previous value from layer was array. But if you prefer, I could make this configurable, so you have to explicitly set which props to override. Or I could remove this functionality from the PR and create a new one to discuss it in more detail. Let me know.
created_at: 2025-03-26T09:26:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -655,6 +657,9 @@ async function initNuxt (nuxt: Nuxt) {
 
   await nuxt.callHook('modules:done')
 
+  // remove duplicate css after modules are done
+  nuxt.options.css = unique(nuxt.options.css)
path: packages/nuxt/src/core/nuxt.ts
user: login: danielroe
body: it was correct before (but only for CSS) - the issue that was being addressed by that code is that CSS added explicitly in a project needs to be later in the array so it has priority.

it wouldn't be true for modules or other array items, though
created_at: 2025-03-26T10:23:29Z
author_association: MEMBER
diff_hunk: @@ -17,22 +17,38 @@ export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig
   overrides?: Exclude<LoadConfigOptions<NuxtConfig>['overrides'], Promise<any> | Function>
 }
 
+const merger = createDefu((obj, key, value) => {
+  if (Array.isArray(obj[key])) {
+    if (Array.isArray(value)) {
+      obj[key] = obj[key].concat(value)
+      return true
+    }
+
+    if (typeof value === 'function') {
+      obj[key] = value(obj[key])
+      return true
+    }
path: packages/kit/src/loader/config.ts
user: login: danielroe
body: let's split this functionality out into a new one with some unit tests to ensure we cover all cases. I definitely think it's worth allowing this kind of thing but we need to think about how to do it.

we also need to update the types so nuxt config accepts these functions directly passed into the configuration.

The only problematic example that immediately occurs to me is something like rollup's external option which can be either an array or a function. (And we do try to discourage non-serialisable options being passed in to nuxt configuration.) But I can't rule out that there might be other such situations, particularly in configuration that we don't 'control', like nitro, vite, esbuild, rollup, etc., which is why hitherto we've restricted custom array merging to `app.config`.
created_at: 2025-03-26T10:47:58Z
author_association: MEMBER
diff_hunk: @@ -655,6 +657,9 @@ async function initNuxt (nuxt: Nuxt) {
 
   await nuxt.callHook('modules:done')
 
+  // remove duplicate css after modules are done
+  nuxt.options.css = unique(nuxt.options.css)
path: packages/nuxt/src/core/nuxt.ts
user: login: aadamcik
body: Updated
created_at: 2025-03-26T11:30:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -17,22 +17,38 @@ export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig
   overrides?: Exclude<LoadConfigOptions<NuxtConfig>['overrides'], Promise<any> | Function>
 }
 
+const merger = createDefu((obj, key, value) => {
+  if (Array.isArray(obj[key])) {
+    if (Array.isArray(value)) {
+      obj[key] = obj[key].concat(value)
+      return true
+    }
+
+    if (typeof value === 'function') {
+      obj[key] = value(obj[key])
+      return true
+    }
path: packages/kit/src/loader/config.ts
user: login: aadamcik
body: Updated
created_at: 2025-03-26T11:30:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,6 +107,23 @@ describe('loadNuxt', () => {
 
     expect(loggerWarn).not.toHaveBeenCalled()
   })
+
+  it('ensures layer modules remains in order', async () => {
+    const layerFixtureDir = withoutTrailingSlash(normalize(fileURLToPath(new URL('./layers-fixture', import.meta.url))))
+    const nuxt = await loadNuxt({ cwd: layerFixtureDir })
+    await nuxt.close()
+
+    const modules = nuxt.options.modules.map(item => typeof item === 'function' ? item.name : item)
+
+    expect(modules).toMatchInlineSnapshot(`
+      [
+        "layer",
path: packages/nuxt/test/load-nuxt.test.ts
user: login: danielroe
body: I think auto-registered layers should be last because they are in the user's project.

so while we are reordering, we should probably ensure they are 'after' layers in `extends`, etc.
created_at: 2025-03-28T16:58:30Z
author_association: MEMBER
diff_hunk: @@ -107,6 +107,23 @@ describe('loadNuxt', () => {
 
     expect(loggerWarn).not.toHaveBeenCalled()
   })
+
+  it('ensures layer modules remains in order', async () => {
+    const layerFixtureDir = withoutTrailingSlash(normalize(fileURLToPath(new URL('./layers-fixture', import.meta.url))))
+    const nuxt = await loadNuxt({ cwd: layerFixtureDir })
+    await nuxt.close()
+
+    const modules = nuxt.options.modules.map(item => typeof item === 'function' ? item.name : item)
+
+    expect(modules).toMatchInlineSnapshot(`
+      [
+        "layer",
path: packages/nuxt/test/load-nuxt.test.ts
user: login: aadamcik
body: I updated the logic, so that auto-registered layers are loaded after the layers in `extends`.

This also affects 2 things:

1. Order of CSS, see updated test.

Before:
```
"auto.css", // auto-registered layer
"custom.css", // layer from extends
```
After:
```
"custom.css", // layer from extends
"auto.css", // auto-registered layer
```

2. Order of imports, see updated test.
created_at: 2025-03-29T11:44:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,6 +107,23 @@ describe('loadNuxt', () => {
 
     expect(loggerWarn).not.toHaveBeenCalled()
   })
+
+  it('ensures layer modules remains in order', async () => {
+    const layerFixtureDir = withoutTrailingSlash(normalize(fileURLToPath(new URL('./layers-fixture', import.meta.url))))
+    const nuxt = await loadNuxt({ cwd: layerFixtureDir })
+    await nuxt.close()
+
+    const modules = nuxt.options.modules.map(item => typeof item === 'function' ? item.name : item)
+
+    expect(modules).toMatchInlineSnapshot(`
+      [
+        "layer",
path: packages/nuxt/test/load-nuxt.test.ts
user: login: danielroe
body: thank you!
created_at: 2025-03-31T08:17:50Z
author_association: MEMBER

PR comments:
user: login: bolt-new-by-stackblitz[bot]
created_at: 2025-03-23T16:19:35Z
body: <a href="https://stackblitz.com/~/github.com/nuxt/nuxt/pull/31507"><img src="https://developer.stackblitz.com/img/review_pr_small.svg" alt="Review PR in StackBlitz Codeflow" align="left" width="103" height="20"></a> _Run & review this pull request in [StackBlitz Codeflow](https://stackblitz.com/~/github.com/nuxt/nuxt/pull/31507)._

author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-03-23T16:22:26Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

The changes update the configuration and module handling logic in the Nuxt and kit packages. An enhanced merging strategy is introduced via a new `merger` function that handles array concatenation, which is then utilised within the configuration loading process. Adjustments to module registration now rely on a new `resolveModules` function that simplifies the logic for module registration and CSS handling, ensuring only unique CSS entries are retained. Additionally, new module functions are introduced in test fixtures and configuration files, including new entries within the `modules` arrays to improve modularity. Test cases have been extended to verify that the order of modules is preserved during the loading process. These updates affect both the internal configuration processing and the testing suite, providing a revised structure for module and CSS handling during Nuxt initialisation.

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=nuxt/nuxt&utm_content=31507):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: pkg-pr-new[bot]
created_at: 2025-03-23T16:27:04Z
body: 
[Open in Stackblitz](https://pkg.pr.new/template/93529d03-b62e-4020-9e5f-42b6fb855985)


<details><summary><b>@nuxt/kit</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/kit@31507
```

</p></details>
      
    

<details><summary><b>nuxt</b></summary><p>

```
npm i https://pkg.pr.new/nuxt@31507
```

</p></details>
      
    

<details><summary><b>@nuxt/schema</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/schema@31507
```

</p></details>
      
    

<details><summary><b>@nuxt/rspack-builder</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/rspack-builder@31507
```

</p></details>
      
    

<details><summary><b>@nuxt/vite-builder</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/vite-builder@31507
```

</p></details>
      
    

<details><summary><b>@nuxt/webpack-builder</b></summary><p>

```
npm i https://pkg.pr.new/@nuxt/webpack-builder@31507
```

</p></details>
      
    

_commit: <a href="https://github.com/nuxt/nuxt/runs/39688905721"><code>40d5cb7</code></a>_

author_association: NONE
user: login: codspeed-hq[bot]
created_at: 2025-03-23T16:36:33Z
body: <!-- __CODSPEED_PERFORMANCE_REPORT_COMMENT__ -->
<!-- __CODSPEED_INSTRUMENTATION_PERFORMANCE_REPORT_COMMENT__ -->

## [CodSpeed Performance Report](https://codspeed.io/nuxt/nuxt/branches/adamcikado%3Afix%2Fconfig-order)

### Merging #31507 will **not alter performance**

<sub>Comparing <code>adamcikado:fix/config-order</code> (40d5cb7) with <code>main</code> (604e45e)</sub>



### Summary

`✅ 10` untouched benchmarks  




author_association: NONE
user: login: danielroe
created_at: 2025-03-31T10:19:39Z
body: Thanks for this nice PR ❤️ 

We rely on the path to generate types (which is why types were breaking in the fixture), so we can't fully resolve the path before hitting `installModule`, but I think there's an opportunity to split out the types from path resolution, for a slight perf enhancement, in another PR, if you're interested.
author_association: MEMBER
user: login: danielroe
created_at: 2025-04-01T08:52:57Z
body: as it's possible people are relying on the previous order (flagged up in an ecosystem-ci run on nuxt-modules/i18n), we're not including this in v3.16.2 release until we have a better signal on how likely it is this would affect people.
author_association: MEMBER