Skip to content

Conversation

danielroe
Copy link
Member

🔗 Linked issue

resolves #33017

📚 Description

this addresses unintuitive behaviour, where alphabetically earlier (A) layers in ~~/layers were overriding 'later' (Z) layers.

in a way this was consistent with 'earlier' layers in the extends array overriding later ones, but at the same time this is confusing and we should probably have Z override A.

I've also updated the docs.

Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@danielroe danielroe self-assigned this Aug 21, 2025
@danielroe danielroe requested review from a team, antfu and huang-julien and removed request for a team August 21, 2025 15:47
@danielroe danielroe moved this to Discussing in Team Board Aug 21, 2025
@github-actions github-actions bot added the 4.x label Aug 21, 2025
Copy link

coderabbitai bot commented Aug 21, 2025

Walkthrough

  • Documentation: Adds “Layer Priority” sections to two docs pages, defining priority across extends, auto-scanned local layers (reverse alphabetical), and the project, with a nuxt.config.ts example.
  • Core change: In loadNuxtConfig, detected localLayers are normalised and sorted in descending alphabetical order; glob options formatting adjusted without behavioural change.
  • Tests/fixtures: Adds minimal nuxt.config.ts files for new layer fixtures (a, b, d). Updates a fixture’s extends order (b then a). Adjusts alias snapshot to include layers c and d, removing test. Adds a test asserting expected local layer order.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/local-layer-order

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (10)
packages/kit/test/layer-fixture/custom-layers/a/nuxt.config.ts (1)

1-1: Use defineNuxtConfig for fixture consistency and type inference

Other fixtures (e.g. layers/d/nuxt.config.ts) use defineNuxtConfig({}). Adopting the same here keeps fixtures consistent and enables Nuxt’s config typing.

-export default {}
+export default defineNuxtConfig({})
packages/kit/src/loader/config.ts (1)

29-34: Make local layer ordering fully deterministic across locales and case

Using localeCompare without options can produce locale-dependent orderings and different results for mixed case or diacritics. Since layer directory names are file-system identifiers, a simple, locale-agnostic compare is safer. Also, consider a more robust trailing-slash removal.

-  const localLayers = (await glob('layers/*', {
-    onlyDirectories: true, cwd: opts.cwd || process.cwd(),
-  }))
-    .map((d: string) => d.endsWith('/') ? d.substring(0, d.length - 1) : d)
-    .sort((a, b) => b.localeCompare(a))
+  const localLayers = (await glob('layers/*', {
+    onlyDirectories: true,
+    cwd: opts.cwd || process.cwd(),
+  }))
+    // Ensure consistent form like `layers/foo` (no trailing slash)
+    .map((d: string) => d.replace(/\/+$/, ''))
+    // Stable, locale-agnostic, case-insensitive descending order (Z before A)
+    .sort((a, b) => {
+      const aa = a.toLowerCase()
+      const bb = b.toLowerCase()
+      if (aa === bb) { return 0 }
+      return aa > bb ? -1 : 1
+    })

If you’d prefer using a utility, withoutTrailingSlash (from ufo) could replace the regex, but the current import set already includes ufo only for withTrailingSlash. Keeping this self-contained avoids extra imports.

docs/2.guide/3.going-further/7.layers.md (1)

73-76: Clarify “alphabetical order” wording to “descending alphabetical order”

“Alphabetical order (Z overrides A)” is contradictory. Say “descending alphabetical order (Z overrides A)” to remove ambiguity.

-2. **Auto-scanned local layers** from `~~/layers` directory in alphabetical order (Z overrides A)
+2. **Auto-scanned local layers** from `~~/layers` directory in descending alphabetical order (Z overrides A)
docs/1.getting-started/14.layers.md (2)

82-84: Clarify “alphabetical order” wording to “descending alphabetical order”

Match the implementation: local layers are sorted so Z overrides A.

-2. **Auto-scanned local layers** from `~~/layers` directory in alphabetical order (Z overrides A)  
+2. **Auto-scanned local layers** from `~~/layers` directory in descending alphabetical order (Z overrides A)

86-95: Reinforce project priority in the example

To avoid misinterpretation, mirror the narrative that the project has the highest priority by explicitly stating the effective order (left to right overrides).

 export default defineNuxtConfig({
   extends: [
-    '../base',                     // Highest priority (among extends)
-    '@my-themes/awesome',          // Medium priority
-    'github:my-themes/awesome#v1', // Lower priority
+    '../base',                     // Highest priority among extends
+    '@my-themes/awesome',          // Then this
+    'github:my-themes/awesome#v1', // Then this
   ]
-  // Your project has the highest priority
+  // Your project has the highest priority overall (it overrides any layer)
 })

Optionally add a one-liner right after the block:

-This means if multiple layers define the same component, configuration, or file, the one with higher priority will be used.
+This means if multiple layers define the same item, the one with higher priority (your project first, then extends order, then local layers Z→A) will be used.
packages/kit/test/layer-fixture/custom-layers/b/nuxt.config.ts (1)

1-1: Fixture is fine; optional consistency tweak with defineNuxtConfig

This minimal layer config is OK for the test. For consistency with other fixtures and better type inference, you could wrap it with defineNuxtConfig.

-export default {}
+export default defineNuxtConfig({})
packages/kit/test/layer-fixture/nuxt.config.ts (1)

2-2: Extends order matches intended precedence; add a clarifying comment

Placing './custom-layers/b' before './custom-layers/a' reflects “first overrides second”. Consider documenting this inline to avoid confusion when reading the fixture.

-  extends: ['./custom-layers/b', './custom-layers/a'],
+  // Earlier entries override later ones
+  extends: ['./custom-layers/b', './custom-layers/a'],
packages/kit/test/load-nuxt-config.spec.ts (3)

13-26: Snapshot looks good; consider reducing brittleness by checking presence rather than full map

Inline snapshots of the entire alias object can become brittle if unrelated aliases are added later. If you only care that local-layer aliases are present and correctly rooted, assert on those keys specifically.

-    expect(config.alias).toMatchInlineSnapshot(`
-      {
-        "#build": "<rootDir>/.nuxt/",
-        "#internal/nuxt/paths": "<rootDir>/.nuxt/paths.mjs",
-        "#layers/c": "<rootDir>/layers/c/",
-        "#layers/d": "<rootDir>/layers/d/",
-        "#layers/layer-fixture": "<rootDir>/",
-        "#shared": "<rootDir>/shared/",
-        "@": "<rootDir>/",
-        "@@": "<rootDir>/",
-        "~": "<rootDir>/",
-        "~~": "<rootDir>/",
-      }
-    `)
+    expect(config.alias).toMatchObject({
+      '#layers/c': '<rootDir>/layers/c/',
+      '#layers/d': '<rootDir>/layers/d/',
+      '#layers/layer-fixture': '<rootDir>/'
+    })

29-36: Rename test and clarify comment to explicitly state descending order and array semantics

“Alphabetical order” can be read as A→Z; here you mean Z→A. Also the bullet points claim “priority list” but the array you assert is the assembled order of config._layers (not necessarily the merge/override precedence). Clarify to avoid reader confusion.

-  it('should respect alphabetical order of local layers', async () => {
+  it('should order local layers in descending alphabetical order (Z before A)', async () => {
@@
-    // priority list
-    // 1. layers in nuxt.config (first overrides second)
-    // 2. then local layers in alphabetical order (Z overrides A)
-    // 3. local project overrides
+    // Assembled order of config._layers (not override precedence):
+    // 1) local project (root)
+    // 2) auto-scanned local layers in descending alphabetical order (Z → A)
+    // 3) layers declared in nuxt.config extends, in declaration order (first overrides second)

36-36: Prefer meta.name where available for stability

Local layers and the project layer have meta.name set; using it reduces coupling to directory naming. Falls back to basename for layers without a meta name (e.g. custom-layers from extends).

-    expect(config._layers.map(l => basename(l.cwd))).toMatchInlineSnapshot(`
+    const layerNames = config._layers.map(l => l.meta?.name ?? basename(l.cwd))
+    expect(layerNames).toMatchInlineSnapshot(`
📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ca84285 and 4e2ad9c.

📒 Files selected for processing (8)
  • docs/1.getting-started/14.layers.md (1 hunks)
  • docs/2.guide/3.going-further/7.layers.md (1 hunks)
  • packages/kit/src/loader/config.ts (1 hunks)
  • packages/kit/test/layer-fixture/custom-layers/a/nuxt.config.ts (1 hunks)
  • packages/kit/test/layer-fixture/custom-layers/b/nuxt.config.ts (1 hunks)
  • packages/kit/test/layer-fixture/layers/d/nuxt.config.ts (1 hunks)
  • packages/kit/test/layer-fixture/nuxt.config.ts (1 hunks)
  • packages/kit/test/load-nuxt-config.spec.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Follow standard TypeScript conventions and best practices

Files:

  • packages/kit/src/loader/config.ts
  • packages/kit/test/layer-fixture/custom-layers/b/nuxt.config.ts
  • packages/kit/test/layer-fixture/custom-layers/a/nuxt.config.ts
  • packages/kit/test/layer-fixture/nuxt.config.ts
  • packages/kit/test/layer-fixture/layers/d/nuxt.config.ts
  • packages/kit/test/load-nuxt-config.spec.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Write unit tests for core functionality using vitest

Files:

  • packages/kit/test/load-nuxt-config.spec.ts
🧠 Learnings (1)
📚 Learning: 2024-11-05T15:22:54.759Z
Learnt from: GalacticHypernova
PR: nuxt/nuxt#26468
File: packages/nuxt/src/components/plugins/loader.ts:24-24
Timestamp: 2024-11-05T15:22:54.759Z
Learning: In `packages/nuxt/src/components/plugins/loader.ts`, the references to `resolve` and `distDir` are legacy code from before Nuxt used the new unplugin VFS and will be removed.

Applied to files:

  • packages/kit/src/loader/config.ts
🧬 Code graph analysis (1)
packages/kit/test/load-nuxt-config.spec.ts (1)
packages/kit/src/loader/config.ts (1)
  • loadNuxtConfig (27-125)
🪛 LanguageTool
docs/1.getting-started/14.layers.md

[uncategorized] ~97-~97: Did you mean “is”?
Context: ...the highest priority }) ``` This means if multiple layers define the same compone...

(IF_IS_PREMIUM)


[uncategorized] ~98-~98: Loose punctuation mark.
Context: ...one with higher priority will be used. ::read-more{to="/docs/guide/going-further...

(UNLIKELY_OPENING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: code
🔇 Additional comments (3)
packages/kit/test/layer-fixture/layers/d/nuxt.config.ts (1)

1-1: LGTM — minimal fixture is correct

The config is intentionally minimal and matches usage in tests. No changes needed.

packages/kit/src/loader/config.ts (1)

29-34: Confirm precedence interaction: _extends (local) vs extends (user-configured)

This change feeds auto-scanned local layers via _extends. With extendKey: ['theme', '_extends', 'extends'], ensure the intended overall priority is: user extends (earlier wins) > auto-scanned local layers (Z before A) > project. If the order of extendKey affects merge precedence (in c12), we should verify it still yields the documented priority after this PR.

You can quickly inspect the resolved _layers order in the test fixture by logging during the test run or by adding a temporary assertion that checks the project layer is first and local layers follow in the expected desc alphabetical order. If helpful, I can propose an additional test asserting the combined order when both extends and local layers are present.

packages/kit/test/load-nuxt-config.spec.ts (1)

4-4: Good call using pathe.basename for cross-platform behaviour

Using pathe avoids Windows path edge cases when deriving layer names from cwd.

})
```

If you also have auto-scanned layers like `~~/layers/a` and `~~/layers/z`, the complete override order would be: `base` > `theme` > `custom` > `z` > `a` > your project.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix priority example: project should appear first in override order

The paragraph says the project has the highest priority, but the example lists it last, which implies the opposite. Place “your project” first (leftmost) if “>” means “overrides”.

-If you also have auto-scanned layers like `~~/layers/a` and `~~/layers/z`, the complete override order would be: `base` > `theme` > `custom` > `z` > `a` > your project.
+If you also have auto-scanned layers like `~~/layers/a` and `~~/layers/z`, the complete override order would be: your project > `base` > `theme` > `custom` > `z` > `a`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
If you also have auto-scanned layers like `~~/layers/a` and `~~/layers/z`, the complete override order would be: `base` > `theme` > `custom` > `z` > `a` > your project.
If you also have auto-scanned layers like `~~/layers/a` and `~~/layers/z`, the complete override order would be: your project > `base` > `theme` > `custom` > `z` > `a`.
🤖 Prompt for AI Agents
In docs/2.guide/3.going-further/7.layers.md around line 90, the example override
order contradicts the text: it claims "your project" has highest priority but
lists it last; update the example so "your project" appears first (leftmost) in
the sequence and ensure the comparator ">" is used consistently to mean
"overrides" (e.g., your project > custom > theme > base > a > z).

Copy link

pkg-pr-new bot commented Aug 21, 2025

Open in StackBlitz

@nuxt/kit

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

nuxt

npm i https://pkg.pr.new/nuxt@33030

@nuxt/rspack-builder

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

@nuxt/schema

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

@nuxt/vite-builder

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

@nuxt/webpack-builder

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

commit: 4e2ad9c

Copy link

codspeed-hq bot commented Aug 21, 2025

CodSpeed Performance Report

Merging #33030 will not alter performance

Comparing fix/local-layer-order (4e2ad9c) with main (ca84285)

Summary

✅ 10 untouched benchmarks

Copy link
Member

@huang-julien huang-julien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@danielroe danielroe changed the title fix(kit): ensure local layers are prioritised correctly fix(kit): ensure local layers are prioritised alphabetically Aug 21, 2025
@danielroe danielroe merged commit 27a80da into main Aug 21, 2025
87 of 90 checks passed
@danielroe danielroe deleted the fix/local-layer-order branch August 21, 2025 17:45
@github-project-automation github-project-automation bot moved this from Discussing to Later in Team Board Aug 21, 2025
@github-actions github-actions bot mentioned this pull request Aug 21, 2025
@github-actions github-actions bot mentioned this pull request Sep 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Later

Development

Successfully merging this pull request may close these issues.

Order of layers in Nuxt 4 is different if the layers folder is not in the app folder

2 participants