Skip to content

fix(metadata): prevent layout title template from applying to the same route-layer page - #3071

Open
NriotHrreion wants to merge 2 commits into
cloudflare:mainfrom
NriotHrreion:fix/issue-3065-same-layer-title-template
Open

fix(metadata): prevent layout title template from applying to the same route-layer page#3071
NriotHrreion wants to merge 2 commits into
cloudflare:mainfrom
NriotHrreion:fix/issue-3065-same-layer-title-template

Conversation

@NriotHrreion

@NriotHrreion NriotHrreion commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Closes #3065

Overview

This PR fixes an App Router metadata compatibility issue where vinext applied a leaf layout's title.template to a page on the same route-tree layer. Next.js only propagates that template to deeper child routes.

This restores SSR output parity with Next.js, avoiding related SEO and accessibility regressions.

What changed

Added a field stashesTitleTemplate in MetadataMergeEntry to mark the entries on the same route-tree layer, preventing them from applying the layout's title template.

In packages/vinext/src/server/app-page-head.ts, filter the same route-layer pages.

const metadataEntries: MetadataMergeEntry[] = [
  ...layoutMetadataResults.flatMap((metadata, index) => {
    if (!metadata) return [];

    const isSameLayerAsPage =
      hasPrimaryPageLayer && layoutInputs[index]?.treePosition === routeSegments.length;
    return [
      {
        metadata,
        ...(isSameLayerAsPage ? { stashesTitleTemplate: false } : {}),
      },
    ];
  }),
  // ...other entries
];

Testing

  • pnpm test tests/app-page-head.test.ts tests/nextjs-compat/metadata.test.ts
  • playwright test tests/e2e/app-router/nextjs-compat/metadata.spec.ts --project=app-router

@pkg-pr-new

pkg-pr-new Bot commented Aug 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@3071
npm i https://pkg.pr.new/create-vinext-app@3071
npm i https://pkg.pr.new/@vinext/types@3071
npm i https://pkg.pr.new/vinext@3071

commit: b825d90

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a4ba4e96e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +786 to +787
const isSameLayerAsPage =
hasPrimaryPageLayer && layoutInputs[index]?.treePosition === routeSegments.length;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Suppress same-layer templates in parallel route branches

When the primary page has no title and an active parallel slot supplies the title, this check only marks layouts from the primary layoutInputs. A slot whose leaf layout and page share a tree position is flattened from resolveParallelRouteMetadata without stashesTitleTemplate: false, so the slot layout still wraps its same-layer page title—for example, producing Slot page | Slot instead of Slot page. Apply the same layer-aware suppression while constructing parallel-route merge entries as well.

AGENTS.md reference: AGENTS.md:L84-L86

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared b825d90 against base 20fdac4 using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 0 regressed · 6 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 141.4 KB 141.4 KB ⚫ +0.0%
Client entry size (gzip) vinext 128.8 KB 128.8 KB ⚫ +0.0%
Dev server cold start vinext 3.19 s 3.15 s ⚫ -1.1%
Production build time vinext 3.66 s 3.64 s ⚫ -0.3%
RSC entry closure size (gzip) vinext 115.6 KB 115.7 KB ⚫ +0.1%
Server bundle size (gzip) vinext 196.8 KB 196.9 KB ⚫ +0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Metadata: parent title.template is applied to a page-level string title (Next treats it as absolute)

1 participant