Skip to content

fix(start): strip trailing slash from prerenderable paths#7070

Open
restareaByWeezy wants to merge 1 commit intoTanStack:mainfrom
restareaByWeezy:fix/6978-dedupe-prerender-trailing-slash
Open

fix(start): strip trailing slash from prerenderable paths#7070
restareaByWeezy wants to merge 1 commit intoTanStack:mainfrom
restareaByWeezy:fix/6978-dedupe-prerender-trailing-slash

Conversation

@restareaByWeezy
Copy link
Copy Markdown

@restareaByWeezy restareaByWeezy commented Mar 30, 2026

Fixes #6978

When using nested index routes like blog/index.tsx, the prerender path discovery generates /blog/ (with trailing slash) via inferFullPath, which intentionally preserves trailing slashes for index routes. But when the crawler picks up links from rendered HTML, it gets /blog (no trailing slash). The seen Set in addCrawlPageTask uses exact string matching, so both pass dedup and end up as separate entries in the sitemap.

The fix strips the trailing slash from inferFullPath output in getPrerenderablePaths before adding to the Set. This way discovered paths match crawled paths and the dedup works correctly. Root path / is kept as-is.

This is consistent with how inferTo (same package, unexported) already handles paths -- it calls inferFullPath then strips the trailing slash, since prerender paths are URLs rather than type identifiers.

Tested against the reproduction repo from the issue (https://github.com/dotnize/start-static-test). Before this change, /blog and /blog/ are crawled separately. After, only /blog is crawled.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Fixed path normalization in the prerender process to ensure consistent route path handling. Non-root routes now have trailing slashes removed for consistency, while the root path remains unchanged, improving path storage reliability.

inferFullPath preserves trailing slashes for index routes (e.g. /blog/)
but the link crawler extracts paths without them (/blog). The seen Set
treats these as distinct strings, so both get crawled and land in the
sitemap as duplicates.

Strip the trailing slash right after inferFullPath in
getPrerenderablePaths so discovered paths match crawled ones.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d73841b-2061-4fcc-8e71-ea7af1ae9af9

📥 Commits

Reviewing files that changed from the base of the PR and between 30835cb and d4166bc.

📒 Files selected for processing (1)
  • packages/start-plugin-core/src/start-router-plugin/generator-plugins/prerender-routes-plugin.ts

📝 Walkthrough

Walkthrough

The prerender routes plugin now normalizes collected inferred route paths by removing trailing slashes from non-root paths, ensuring consistent path storage without terminal slashes in the prerender list.

Changes

Cohort / File(s) Summary
Prerender Path Normalization
packages/start-plugin-core/src/start-router-plugin/generator-plugins/prerender-routes-plugin.ts
Added path normalization logic that removes trailing slashes from non-root paths before storing them in the prerender list. Root path '/' is preserved as-is. This ensures consistent path representation without duplicate slash variants.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰✨ A trailing slash bid us adieu,
Now paths dance with consistency true,
No doubles shall bloom in the prerender way,
Just cleaner routes brightening the day! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: stripping trailing slashes from prerenderable paths, which directly addresses the bug fix.
Linked Issues check ✅ Passed The code change strips trailing slashes from prerenderable paths (except root /), directly addressing the root cause in issue #6978 where nested index routes produced duplicate entries differing only by trailing slash.
Out of Scope Changes check ✅ Passed The change is narrowly scoped to normalizing prerenderable paths in getPrerenderablePaths, directly related to fixing the duplicate trailing-slash issue and fully within the scope of issue #6978.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

@github-actions
Copy link
Copy Markdown
Contributor

Bundle Size Benchmarks

  • Commit: 30835cb8e935
  • Measured at: 2026-03-30T09:55:43.961Z
  • Baseline source: history:30835cb8e935
  • Dashboard: bundle-size history
Scenario Current (gzip) Delta vs baseline Raw Brotli Trend
react-router.minimal 87.47 KiB 0 B (0.00%) 275.68 KiB 75.93 KiB █▄▄▂▂▂▂▁▁▁▁
react-router.full 90.76 KiB 0 B (0.00%) 286.86 KiB 78.87 KiB █▃▃▂▂▂▂▁▁▁▁
solid-router.minimal 35.51 KiB 0 B (0.00%) 107.04 KiB 31.87 KiB ███▃▃▃▃▁▁▁▁
solid-router.full 39.99 KiB 0 B (0.00%) 120.58 KiB 35.89 KiB ███▆▆▆▆▁▁▁▁
vue-router.minimal 53.36 KiB 0 B (0.00%) 152.97 KiB 47.88 KiB █▂▂▂▂▂▂▁▁▁▁
vue-router.full 58.22 KiB 0 B (0.00%) 168.43 KiB 52.08 KiB █▃▃▂▂▂▂▁▁▁▁
react-start.minimal 102.00 KiB 0 B (0.00%) 323.92 KiB 88.17 KiB █▃▃▂▂▂▂▁▁▁▁
react-start.full 105.36 KiB 0 B (0.00%) 334.27 KiB 91.01 KiB █▃▃▂▂▂▂▁▁▁▁
solid-start.minimal 49.61 KiB 0 B (0.00%) 153.29 KiB 43.75 KiB ███▄▄▄▄▁▁▁▁
solid-start.full 55.10 KiB 0 B (0.00%) 169.53 KiB 48.46 KiB ███▅▅▅▅▁▁▁▁

Trend sparkline is historical gzip bytes ending with this PR measurement; lower is better.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Static prerendering: Duplicate crawled/sitemap entries for nested index pages

1 participant