Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
/nuxtPublic

feat(nuxt): experimental page component name normalisation#33513

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
huang-julien wants to merge7 commits intomain
base:main
Choose a base branch
Loading
fromfeat/33254

Conversation

@huang-julien
Copy link
Member

📚 Description

resolves#33254

this PR adds an experimental feature to normalize page components names using the route name.

danielroe, cernymatej, Mini-ghost, and OrbisK reacted with heart emoji
@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz CodeflowRun & review this pull request inStackBlitz Codeflow.

@pkg-pr-new
Copy link

pkg-pr-newbot commentedOct 18, 2025
edited
Loading

Open in StackBlitz

@nuxt/kit

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

@nuxt/nitro-server

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

nuxt

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

@nuxt/rspack-builder

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

@nuxt/schema

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

@nuxt/vite-builder

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

@nuxt/webpack-builder

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

commit:32cd0bf

@codspeed-hq
Copy link

codspeed-hqbot commentedOct 18, 2025
edited
Loading

CodSpeed Performance Report

Merging#33513 willnot alter performance

Comparingfeat/33254 (32cd0bf) withmain (f171385)

Summary

✅ 10 untouched

@huang-julienhuang-julien marked this pull request as ready for reviewOctober 20, 2025 19:13
@coderabbitai
Copy link

Walkthrough

This pull request introduces a new experimental featurenormalizePageNames that ensures page component names match their route names. The implementation adds logic to the pages utility module to conditionally attach a__name property to page components when the feature flag is enabled. Configuration types and defaults are added to the schema package. Supporting tests are included to verify both synchronous and asynchronous import scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The changes span multiple packages with consistent patterns: a new experimental configuration option with schema definitions, conditional logic to augment component metadata, and dedicated tests for the new feature. The implementation logic is relatively straightforward (wrapping imports with Object.assign or promise chains), but review requires verification that the conditional logic correctly handles both sync and async import paths, proper integration with the experimental flag, and validation that test coverage adequately reflects the new behaviour. The heterogeneity is moderate—whilst most changes follow the same pattern (adding the flag and implementation), the different import method handling adds some complexity.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run@coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check nameStatusExplanation
Title Check✅ PassedThe title "feat(nuxt): experimental page component name normalisation" clearly describes the main change in the pull request — the introduction of an experimental feature for normalizing page component names using route names. It follows conventional commit conventions, is concise and specific, and directly corresponds to the core functionality being added across the modified files (schema updates, utility logic, and test coverage).
Linked Issues Check✅ PassedThe linked issue#33254 requests automatic use of route names as page component names to enable keep-alive functionality with name-based references. The implementation satisfies this requirement by introducing a new experimental flagnormalizePageNames in the schema [packages/schema/src/config/experimental.ts and packages/schema/src/types/schema.ts], implementing logic in utils.ts to attach__name properties to page components via Object.assign (for sync imports) and then() chaining (for async imports) when the flag is enabled, and providing comprehensive test coverage [packages/nuxt/test/pages.test.ts] validating both sync and async import scenarios.
Out of Scope Changes Check✅ PassedAll modifications are directly aligned with implementing the experimental page component name normalisation feature. Changes include the core logic in packages/nuxt/src/pages/utils.ts to attach component names, schema configuration in packages/schema/src/config/experimental.ts and packages/schema/src/types/schema.ts to define the experimental flag, and test files in packages/nuxt/test/ to validate the functionality. No changes appear to be tangential or unrelated to the stated objectives.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branchfeat/33254

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between934dc00 andef39e42.

📒 Files selected for processing (5)
  • packages/nuxt/src/pages/utils.ts (3 hunks)
  • packages/nuxt/test/page-metadata.test.ts (1 hunks)
  • packages/nuxt/test/pages.test.ts (2 hunks)
  • packages/schema/src/config/experimental.ts (1 hunks)
  • packages/schema/src/types/schema.ts (1 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/schema/src/types/schema.ts
  • packages/nuxt/src/pages/utils.ts
  • packages/schema/src/config/experimental.ts
  • packages/nuxt/test/pages.test.ts
  • packages/nuxt/test/page-metadata.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

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

Write unit tests for core functionality usingvitest

Files:

  • packages/nuxt/test/pages.test.ts
  • packages/nuxt/test/page-metadata.test.ts
🧠 Learnings (1)
📚 Learning: 2024-12-12T12:36:34.871Z
Learnt from: huang-julienPR: nuxt/nuxt#29366File: packages/nuxt/src/app/components/nuxt-root.vue:16-19Timestamp: 2024-12-12T12:36:34.871ZLearning: In `packages/nuxt/src/app/components/nuxt-root.vue`, when optimizing bundle size by conditionally importing components based on route metadata, prefer using inline conditional imports like:```jsconst IsolatedPage = route?.meta?.isolate ? defineAsyncComponent(() => import('#build/isolated-page.mjs')) : null```instead of wrapping the import in a computed property or importing the component unconditionally.

Applied to files:

  • packages/nuxt/src/pages/utils.ts
🧬 Code graph analysis (2)
packages/nuxt/src/pages/utils.ts (2)
packages/nuxt/src/app/nuxt.ts (1)
  • nuxt (272-272)
packages/kit/src/index.ts (1)
  • useNuxt (28-28)
packages/nuxt/test/pages.test.ts (3)
packages/kit/src/context.ts (1)
  • useNuxt (29-36)
packages/schema/src/types/hooks.ts (1)
  • NuxtPage (28-51)
packages/nuxt/src/pages/utils.ts (1)
  • normalizeRoutes (528-658)
🪛 GitHub Check: CodeQL
packages/nuxt/src/pages/utils.ts

[warning] 598-598: Improper code sanitization
Code construction depends on animproperly sanitized value.

🔇 Additional comments (9)
packages/schema/src/types/schema.ts (1)

1301-1304:LGTM! Clear type definition for the new experimental feature.

The newnormalizePageNames option is well-documented and follows the established pattern ofnormalizeComponentNames.

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

14-28:LGTM! Proper test isolation.

The mock correctly ensures that existing page metadata tests continue to run withnormalizePageNames disabled, maintaining test isolation and backward compatibility.

packages/schema/src/config/experimental.ts (1)

171-171:LGTM! Appropriate default for experimental feature.

The feature is opt-in by default, which is the right approach for an experimental feature that changes component naming behaviour.

packages/nuxt/src/pages/utils.ts (3)

529-529:LGTM! Accessing Nuxt context.

TheuseNuxt() call is necessary to access the experimental configuration flag later in the function.


577-578:LGTM! Cleaner code with derived variable.

ExtractingisSyncImport improves readability and allows reuse in thenormalizePageNames logic below.


594-600:No security concerns found—CodeQL warning is a false positive.

The implementation is secure. ThegenSafeVariableName function from knitwork v1.2.0 converts arbitrary strings to safe JavaScript identifiers, properly handling special characters and reserved words. More importantly,route.name is always safely escaped viaJSON.stringify before being interpolated intometaRoute.name at line 581, and then further interpolated into the component expression at line 598. The resulting code likeObject.assign(index, { __name: indexMeta?.name ?? "index" }) is valid and free from injection risks because both the variable names and string values are appropriately constrained by these safe sources.

packages/nuxt/test/pages.test.ts (3)

8-24:LGTM! Consistent test setup.

The mock setup properly isolates existing tests from the new feature by defaultingnormalizePageNames tofalse.


97-123:LGTM! Comprehensive test for sync imports.

The test correctly:

  • Enables thenormalizePageNames feature via mock
  • Creates a page with_sync: true to trigger synchronous import behaviour
  • Verifies thatObject.assign is used to attach__name

125-149:LGTM! Comprehensive test for async imports.

The test correctly:

  • Enables thenormalizePageNames feature via mock
  • Creates a page without_sync to trigger asynchronous import behaviour
  • Verifies that.then() is chained to attach__name after import resolution

Together with the sync import test, this provides complete coverage of both code paths.


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

❤️ Share

Comment@coderabbitai help to get the list of available commands and usage tips.

:pageImport,
}

if(nuxt.options.experimental.normalizePageNames){
Copy link
Member

Choose a reason for hiding this comment

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

could we maybe split this intonormalizeComponent andnormalizeComponentWithName functions, so we only assign it once, rather than manipulating an existing string?

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

Do you mean anormalizeComponentName at runtime ?

Copy link
Member

Choose a reason for hiding this comment

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

no. I mean, at the moment it's created a few lines above and then changed here

we can instead create it just once, which will tidy up the logic

huang-julien reacted with thumbs up emoji
}

letcomponent=page.mode==='server'
?`() => createIslandPage(${route.name})`

Check warning

Code scanning / CodeQL

Improper code sanitization Medium

Code construction depends on an
improperly sanitized value
Loading
.

Copilot Autofix

AI 1 day ago

To fix the improper code sanitization, dangerous characters that may break out of a JavaScript string or script context and allow code injection should be escaped from values inserted into constructed JavaScript code. The best approach is to escape additional risky characters, even afterJSON.stringify, by mapping all characters listed in the prompt'scharMap. This is done by defining anescapeUnsafeChars function that applies the mapping after the value is stringified. The fix should be applied whereserializeRouteValue is used in code interpolation, specifically forroute.name (and possibly other similar cases). TheescapeUnsafeChars helper can be added to this file, and applied in the necessary locations (either withinserializeRouteValue or as a wrapper on its output in line 629 and similar code constructions).

Implementation details:

  • AddescapeUnsafeChars (per the prompt) topackages/nuxt/src/pages/utils.ts.
  • When interpolatingroute.name into a template string (e.g., in line 629), wrap it withescapeUnsafeChars.
  • Ensure minimal changes to functionality: this escapes only the dangerous characters and preserve original semantics.

Suggested changeset1
packages/nuxt/src/pages/utils.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git applydiff --git a/packages/nuxt/src/pages/utils.ts b/packages/nuxt/src/pages/utils.ts--- a/packages/nuxt/src/pages/utils.ts+++ b/packages/nuxt/src/pages/utils.ts@@ -9,7 +9,6 @@ import { filename } from 'pathe/utils' import { hash } from 'ohash' -import { defu } from 'defu' import { klona } from 'klona' import { parseAndWalk } from 'oxc-walker' import { parseSync } from 'oxc-parser'@@ -626,7 +625,7 @@   }    let component = page.mode === 'server'-    ? `() => createIslandPage(${route.name})`+    ? `() => createIslandPage(${escapeUnsafeChars(route.name)})`     : page.mode === 'client'       ? `() => createClientPage(${pageImport})`       : pageImportEOF
@@ -9,7 +9,6 @@
import{filename}from'pathe/utils'
import{hash}from'ohash'

import{defu}from'defu'
import{klona}from'klona'
import{parseAndWalk}from'oxc-walker'
import{parseSync}from'oxc-parser'
@@ -626,7 +625,7 @@
}

letcomponent=page.mode==='server'
?`() => createIslandPage(${route.name})`
?`() => createIslandPage(${escapeUnsafeChars(route.name)})`
:page.mode==='client'
?`() => createClientPage(${pageImport})`
:pageImport
if(isSyncImport){
component=`Object.assign(${pageImportName}, { __name:${metaRouteName} })`
}else{
component=`${component}.then((m) => Object.assign(m.default, { __name:${metaRouteName} }))`

Check warning

Code scanning / CodeQL

Improper code sanitization Medium

Code construction depends on an
improperly sanitized value
Loading
.

Copilot Autofix

AI 1 day ago

General fix:
Whenever generating JavaScript code by interpolating user-controllable data into template strings, you must perform additional escaping on top ofJSON.stringify to neutralize dangerous characters that could break out of the string literal or script context.

Best fix for this code:
Add an escaping function for potentially dangerous unicode and script-breaking characters (as per the background), and use it to sanitize any interpolated JSON strings used in the generated code, specifically in values likemetaRouteName (and any similar fields, as appropriate).

  • Define anescapeUnsafeChars(str: string) function modeled after the example in the background to escape<,>,/, and other dangerous characters.
  • Use this function when interpolating values likemetaRouteName into code, specifically on the assignment tocomponent wheremetaRouteName is interpolated (line 636, 638).
  • Consider exporting the sanitize function or placing it at file scope.
  • Only add the function and calls within shown snippet regions; do not assume code beyond those lines.

Lines to change:

  • InsertescapeUnsafeChars function before usage, within the shown file.
  • On lines 636 and 638 (and any similar string interpolations), wrap the variable injected into code withescapeUnsafeChars(...).

Methods/imports needed:

  • Only the helper function, no external packages required.

Suggested changeset1
packages/nuxt/src/pages/utils.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git applydiff --git a/packages/nuxt/src/pages/utils.ts b/packages/nuxt/src/pages/utils.ts--- a/packages/nuxt/src/pages/utils.ts+++ b/packages/nuxt/src/pages/utils.ts@@ -541,6 +541,28 @@   } } +/**+ * Escape unsafe JavaScript characters for safe insertion into JS source (script context).+ * Escapes <, >, /, \\, null, and other special or line/paragraph separator chars.+ */+const charMap: Record<string, string> = {+  '<': '\\u003C',+  '>': '\\u003E',+  '/': '\\u002F',+  '\\': '\\\\',+  '\b': '\\b',+  '\f': '\\f',+  '\n': '\\n',+  '\r': '\\r',+  '\t': '\\t',+  '\0': '\\0',+  '\u2028': '\\u2028',+  '\u2029': '\\u2029'+}+function escapeUnsafeChars(str: string) {+  return str.replace(/[<>\b\f\n\r\t\0\u2028\u2029/\\]/g, x => charMap[x])+}+ function getRouteFromNuxtPage (page: NuxtPage, metaImports: Set<string>, options: NormalizeRoutesOptions): NormalizedRoute {   const metaFiltered: Record<string, any> = {}   let skipMeta = true@@ -633,9 +655,9 @@    if (nuxt.options.experimental.normalizePageNames) {     if (isSyncImport) {-      component = `Object.assign(${pageImportName}, { __name: ${metaRouteName} })`+      component = `Object.assign(${pageImportName}, { __name: ${escapeUnsafeChars(metaRouteName)} })`     } else {-      component = `${component}.then((m) => Object.assign(m.default, { __name: ${metaRouteName} }))`+      component = `${component}.then((m) => Object.assign(m.default, { __name: ${escapeUnsafeChars(metaRouteName)} }))`     }   } EOF
@@ -541,6 +541,28 @@
}
}

/**
*EscapeunsafeJavaScriptcharactersforsafeinsertionintoJSsource(scriptcontext).
*Escapes<,>,/,\\,null,andotherspecialorline/paragraphseparatorchars.
*/
constcharMap:Record<string,string>={
'<':'\\u003C',
'>':'\\u003E',
'/':'\\u002F',
'\\':'\\\\',
'\b':'\\b',
'\f':'\\f',
'\n':'\\n',
'\r':'\\r',
'\t':'\\t',
'\0':'\\0',
'\u2028':'\\u2028',
'\u2029':'\\u2029'
}
functionescapeUnsafeChars(str:string){
returnstr.replace(/[<>\b\f\n\r\t\0\u2028\u2029/\\]/g,x=>charMap[x])
}

functiongetRouteFromNuxtPage(page:NuxtPage,metaImports:Set<string>,options:NormalizeRoutesOptions):NormalizedRoute{
constmetaFiltered:Record<string,any>={}
letskipMeta=true
@@ -633,9 +655,9 @@

if(nuxt.options.experimental.normalizePageNames){
if(isSyncImport){
component=`Object.assign(${pageImportName}, { __name:${metaRouteName} })`
component=`Object.assign(${pageImportName}, { __name:${escapeUnsafeChars(metaRouteName)} })`
}else{
component=`${component}.then((m) => Object.assign(m.default, { __name:${metaRouteName} }))`
component=`${component}.then((m) => Object.assign(m.default, { __name:${escapeUnsafeChars(metaRouteName)} }))`
}
}

@huang-julienhuang-julien marked this pull request as draftNovember 23, 2025 16:24
@huang-julienhuang-julien marked this pull request as ready for reviewNovember 23, 2025 22:24
@danielroedanielroe added this to the4.3 milestoneDec 16, 2025
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@danielroedanielroedanielroe left review comments

At least 1 approving review is required to merge this pull request.

Assignees

No one assigned

Projects

None yet

Milestone

4.3

Development

Successfully merging this pull request may close these issues.

Use route name as page component's name as default

2 participants

@huang-julien@danielroe

[8]ページ先頭

©2009-2025 Movatter.jp