Skip to content

fix(nuxt): improve page meta extraction + performance - #35869

Merged
danielroe merged 8 commits into
mainfrom
fix/page-meta-extraction
Jul 29, 2026
Merged

fix(nuxt): improve page meta extraction + performance#35869
danielroe merged 8 commits into
mainfrom
fix/page-meta-extraction

Conversation

@danielroe

Copy link
Copy Markdown
Member

🔗 Linked issue

📚 Description

I started work on this originally as a performance improvement - to prevent having to pull in every single page (via macro transform) to render any page (the imports were always being rendered in #build/routes.mjs)

along the way, I discovered some correctness issues (for example, divergence between our static analysis and plugin transform), as well as some opportunities to give users better errors (e.g. detecting a definePageMeta macro inside a conditional, which can only indicate they have misunderstood the concept

@github-actions github-actions Bot added 5.x 🐛 bug Something isn't working as expected labels Jul 28, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jul 28, 2026

Copy link
Copy Markdown

Open in StackBlitz

@nuxt/kit

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

@nuxt/nitro-server

npm i https://pkg.pr.new/@nuxt/nitro-server@35869

nuxt

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

@nuxt/rspack-builder

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

@nuxt/schema

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

@nuxt/vite-builder

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

@nuxt/webpack-builder

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

commit: 2a07e81

@danielroe
danielroe requested a review from cernymatej July 28, 2026 11:49
@coderabbitai

This comment has been minimized.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/nuxt/test/page-metadata.test.ts (1)

1242-1322: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider covering the dynamic classification in the agreement suite.

The suite covers extract, reshape, runtime and the non-object-literal case, but not dynamic — an extraction key whose value is not statically serialisable (e.g. definePageMeta({ name: someVar })). That is the case where the transform must keep the property while getRouteMeta marks name dynamic, so the two sides drifting there would be silent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxt/test/page-metadata.test.ts` around lines 1242 - 1322, Extend
the “agreement with extracted route meta” suite with a test for a statically
non-serialisable extracted value, such as definePageMeta({ name: someVar }).
Assert macroModule keeps the property and getRouteMeta marks name as dynamic,
covering the dynamic classification alongside the existing extract, reshape,
runtime, and non-object-literal cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/nuxt/src/pages/plugins/page-meta.ts`:
- Around line 262-282: The reshape handling around
classification.node.properties currently omits the entire layout property after
mapping only name and props, silently dropping unknown sub-properties. Before
calling omitProp, detect any unrecognised or unmappable layout sub-property and
bail out of the reshape handling so the original layout value is preserved; keep
the existing mappings for name and props unchanged.

In `@packages/nuxt/src/pages/utils.ts`:
- Around line 385-398: Update the duplicate-key handling in the classification
loop around classifyPageMetaProperty so classified uses last-wins semantics:
assign or replace the existing entry for each extract or dynamic key instead of
retaining the first occurrence. Keep the existing runtime-property handling
unchanged and align the result with JavaScript object evaluation and
isSerializable.

---

Nitpick comments:
In `@packages/nuxt/test/page-metadata.test.ts`:
- Around line 1242-1322: Extend the “agreement with extracted route meta” suite
with a test for a statically non-serialisable extracted value, such as
definePageMeta({ name: someVar }). Assert macroModule keeps the property and
getRouteMeta marks name as dynamic, covering the dynamic classification
alongside the existing extract, reshape, runtime, and non-object-literal cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 166fa4f1-7541-4f8e-b2db-a93923b7bf2b

📥 Commits

Reviewing files that changed from the base of the PR and between df18c4a and f74ca43.

📒 Files selected for processing (6)
  • packages/kit/src/diagnostics/pages.ts
  • packages/nuxt/src/pages/module.ts
  • packages/nuxt/src/pages/plugins/page-meta.ts
  • packages/nuxt/src/pages/utils.ts
  • packages/nuxt/test/is-serializable.test.ts
  • packages/nuxt/test/page-metadata.test.ts

Comment on lines +262 to +282
if (classification.kind !== 'reshape') {
continue
}

for (const layoutProp of classification.node.properties) {
if (layoutProp.type !== 'Property' || layoutProp.key.type !== 'Identifier') {
continue
}
} else if (prop.key.name === 'layout' && prop.value.type === 'ObjectExpression') {
for (const layoutProp of prop.value.properties) {
if (layoutProp.type !== 'Property' || layoutProp.key.type !== 'Identifier') {
continue
}
if (layoutProp.key.name === 'name') {
m.appendLeft(
prop.start - meta.start,
`layout: ${code.slice(layoutProp.value.start, layoutProp.value.end)},\n`,
)
} else if (layoutProp.key.name === 'props') {
m.appendLeft(
prop.start - meta.start,
`layoutProps: ${code.slice(layoutProp.value.start, layoutProp.value.end)},\n`,
)
}
if (layoutProp.key.name === 'name') {
m.appendLeft(
prop.start - meta.start,
`layout: ${code.slice(layoutProp.value.start, layoutProp.value.end)},\n`,
)
} else if (layoutProp.key.name === 'props') {
m.appendLeft(
prop.start - meta.start,
`layoutProps: ${code.slice(layoutProp.value.start, layoutProp.value.end)},\n`,
)
}
omitProp(prop, i)
}
omitProp(prop, i)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Look for existing coverage/handling of non name/props keys in an object `layout`
rg -nP -C4 'layoutProps' --type=ts

Repository: nuxt/nuxt

Length of output: 147


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="packages/nuxt/src/pages/plugins/page-meta.ts"
if [ -f "$file" ]; then
  echo "=== file exists and line count ==="
  wc -l "$file"
  echo "=== outline ==="
  ast-grep outline "$file" --match pageMeta | sed -n '1,120p' || true
  echo "=== relevant lines 220-310 ==="
  sed -n '220,310p' "$file" | nl -ba -v220
  echo "=== omitProp definitions/usages ==="
  rg -n "function omitProp|const omitProp|omitProp\\(" "$file" -C 5
else
  echo "missing $file"
fi

echo "=== git diff stat/name-only ==="
git diff --stat -- packages/nuxt/src/pages/plugins/page-meta.ts || true
git diff -- packages/nuxt/src/pages/plugins/page-meta.ts | sed -n '1,220p' || true

Repository: nuxt/nuxt

Length of output: 378


🏁 Script executed:

#!/bin/bash
set -euo pipefail
file="packages/nuxt/src/pages/plugins/page-meta.ts"

echo "=== relevant lines 220-310 ==="
sed -n '220,310p' "$file"

echo "=== omitProp definitions/usages ==="
grep -n "omitProp\|function omitProp\|const omitProp" "$file" -C 5 || true

echo "=== layout reshape handling around properties ==="
grep -n "layoutProp\|reshape\|classification\\.node\\.properties\|layoutProps" "$file" -C 3 || true

echo "=== git diff stat/name-only ==="
git diff --stat -- "$file" || true
git diff -- "$file" | sed -n '1,260p' || true

Repository: nuxt/nuxt

Length of output: 6661


🏁 Script executed:

#!/bin/bash
set -euo pipefail
file="packages/nuxt/src/pages/plugins/page-meta.ts"

echo "=== classifyPageMetaProperty definition/usages ==="
grep -n "classifyPageMetaProperty\|reshape" "$file" -C 8 || true
sed -n '1,120p' "$file"

echo "=== repository references for definePageMeta layout object keys / layoutProps ==="
rg -n "definePageMeta|definePageMeta\\(|layoutProps|layoutProps:" . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | head -200 || true

Repository: nuxt/nuxt

Length of output: 31147


Preserve unknown layout sub-properties instead of dropping them.

The loop only maps identifier-keyed name and props; any other property in layout: { ... } is ignored before omitProp(prop, i) removes the whole property. Return from the reshape handler for unrecognised properties, or at least bail out when any sub-property cannot be mapped so the value is not silently dropped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxt/src/pages/plugins/page-meta.ts` around lines 262 - 282, The
reshape handling around classification.node.properties currently omits the
entire layout property after mapping only name and props, silently dropping
unknown sub-properties. Before calling omitProp, detect any unrecognised or
unmappable layout sub-property and bail out of the reshape handling so the
original layout value is preserved; keep the existing mappings for name and
props unchanged.

Comment thread packages/nuxt/src/pages/utils.ts
@codspeed-hq

codspeed-hq Bot commented Jul 28, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 21 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing fix/page-meta-extraction (2a07e81) with main (39aa997)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@danielroe
danielroe added this pull request to the merge queue Jul 28, 2026
@danielroe
danielroe removed this pull request from the merge queue due to a manual request Jul 28, 2026
@danielroe
danielroe added this pull request to the merge queue Jul 29, 2026
Merged via the queue into main with commit d0f4ecb Jul 29, 2026
55 of 57 checks passed
@danielroe
danielroe deleted the fix/page-meta-extraction branch July 29, 2026 08:36
@github-actions github-actions Bot mentioned this pull request Jul 28, 2026
5 tasks
@github-actions github-actions Bot mentioned this pull request Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

5.x 🐛 bug Something isn't working as expected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant