Skip to content

Conversation

@Dubzer
Copy link

@Dubzer Dubzer commented Nov 15, 2025

resolves #5868

Summary by CodeRabbit

  • Bug Fixes
    • Improved server-side rendering stability for HTML injection to handle edge cases more reliably across React Router and Solid Router packages.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 15, 2025

Walkthrough

Two SSR rendering modules updated to use a replacer function callback instead of direct string replacement when injecting HTML into the </body> tag, preventing unintended $ character interpolation in replacement strings.

Changes

Cohort / File(s) Summary
SSR HTML tail injection refactor
packages/react-router/src/ssr/renderRouterToString.tsx, packages/solid-router/src/ssr/renderRouterToString.tsx
Changed html.replace('</body>', \${injectedHtml}`)to use a replacer function callback:html.replace('', () => `${injectedHtml}`)to avoid$` character interpolation issues

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Suggested labels

package: solid-router

Suggested reviewers

  • birkskyum

Poem

🐰 A rabbit's tail once split in two,
When dollar signs came sneaking through,
But now a function stands so tall,
To guard the body tag from all! 🏷️

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title addresses the root cause (handling $& in string replacement) identified in issue #5868, where defaultRenderHandler adds multiple </body> tags due to improper string replacement interpolation.
Linked Issues check ✅ Passed The PR changes correctly resolve issue #5868 by replacing string-based replacement with a callback function to prevent $& interpolation in the injected HTML, eliminating duplicate </body> tags.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the string replacement issue in renderRouterToString files (React and Solid routers), directly addressing the reported bug with no extraneous modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ccf5483 and 8f80654.

📒 Files selected for processing (2)
  • packages/react-router/src/ssr/renderRouterToString.tsx (1 hunks)
  • packages/solid-router/src/ssr/renderRouterToString.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/solid-router/src/ssr/renderRouterToString.tsx
  • packages/react-router/src/ssr/renderRouterToString.tsx
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/solid-router/src/ssr/renderRouterToString.tsx
🔇 Additional comments (2)
packages/solid-router/src/ssr/renderRouterToString.tsx (1)

32-32: Excellent fix for special replacement pattern handling.

The function callback prevents JavaScript's String.replace() from interpreting special patterns in injectedHtml. When the second argument is a string, replace() treats sequences like $& (matched substring), $`` (text before match), $'(text after match), and$$(literal$) as replacement patterns. If injectedHtmlcontains any of these—such as syntax-highlighted code with$&—they would be expanded, potentially duplicating the ` tag or injecting unintended content. Wrapping the replacement in a function ensures it's treated as a literal string.

packages/react-router/src/ssr/renderRouterToString.tsx (1)

20-20: Excellent fix, consistent with Solid Router.

This applies the same special replacement pattern protection as packages/solid-router/src/ssr/renderRouterToString.tsx (line 32). The function callback ensures injectedHtml is treated as a literal string, preventing JavaScript's replace() from interpreting patterns like $&, $``, or $$` that could corrupt the SSR HTML output.


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.

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.

defaultRenderHandler adds multiple </body> tags

1 participant