Skip to content

Document warm SSR cache benchmarking for RSC - #4303

Merged
justin808 merged 5 commits into
mainfrom
jg-codex/rsc-perf-docs-4294
Jul 1, 2026
Merged

Document warm SSR cache benchmarking for RSC#4303
justin808 merged 5 commits into
mainfrom
jg-codex/rsc-perf-docs-4294

Conversation

@justin808

@justin808 justin808 commented Jul 1, 2026

Copy link
Copy Markdown
Member

Closes #4294

Summary

  • Adds RSC benchmarking guidance to the performance benchmarks guide for apps that already use warm React on Rails Pro SSR caches.
  • Documents a cache-state matrix covering cold uncached SSR, warm cached SSR, RSC cold, and RSC warm runs.
  • Adds a static landing-page pattern and warns about asset/head preload parity, Flight payload bytes, lower JS/TBT with worse LCP, and apples-to-oranges cache comparisons.

Validation

  • Security preflight acknowledged and passed for Document warm SSR prerender cache vs RSC performance tradeoffs #4294.
  • git diff --check passed.
  • pnpm exec prettier --check -- docs/oss/core-concepts/performance-benchmarks.md passed after formatting the changed doc.
  • script/check-docs-sidebar origin/main passed.
  • bin/check-links passed with 0 errors.
  • bundle exec rubocop is blocked by unrelated existing offenses under react_on_rails/spike/3313_prism_gemfile_rewriter/.
  • bundle exec rubocop --config react_on_rails/.rubocop.yml react_on_rails passed.
  • Pre-commit and pre-push hooks passed.

Batch Context

Batch: ror-docs-4286-4297-20260701.

Summary by CodeRabbit

  • Documentation
    • Added new guidance for benchmarking React Server Components against warm server-side rendering caches.
    • Included a practical static landing-page example for more fair performance comparisons.
    • Added a cache-state comparison framework covering cold vs warm scenarios and what each measures.
    • Expanded benchmark interpretation guidance, including when RSC may not outperform an already-warm cached SSR baseline.
    • Improved troubleshooting and migration guidance for client reference scoping to prevent missing or delayed client hydration.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 28432b5c-e81e-49c8-bc86-782bcf48e595

📥 Commits

Reviewing files that changed from the base of the PR and between b6278b2 and 137c0fc.

📒 Files selected for processing (2)
  • docs/oss/core-concepts/performance-benchmarks.md
  • llms-full.txt
✅ Files skipped from review due to trivial changes (2)
  • llms-full.txt
  • docs/oss/core-concepts/performance-benchmarks.md

Walkthrough

This PR adds documentation for benchmarking RSC against warm cached SSR and expands RSC troubleshooting guidance around clientReferences scope, manifest discovery, and client-island hydration checks.

Changes

Benchmark documentation additions

Layer / File(s) Summary
Warm cache benchmarking rationale
docs/oss/core-concepts/performance-benchmarks.md, llms-full.txt
Explains that RSC does not automatically outperform warm cached SSR, distinguishing fragment-cache and prerender-cache hits and their effect on first-paint gains.
Static landing-page example and cache-state matrix
docs/oss/core-concepts/performance-benchmarks.md
Adds a cache-optimized ERB example and a matrix describing cold and warm SSR and RSC test setups and measurement goals.
Interpretation checklist for RSC results
docs/oss/core-concepts/performance-benchmarks.md
Adds guidance for when RSC is expected to win versus when cached SSR may already be near-optimal, including metrics and payload considerations.

Client reference scope and troubleshooting guidance

Layer / File(s) Summary
Client reference scope rules
llms-full.txt
Warns against emptying clientReferences globally and clarifies alignment requirements among file suffixes, 'use client', and manifest discovery.
Client reference troubleshooting
llms-full.txt
Adds guidance on empty clientReferences in mixed apps, a new troubleshooting section, and symptom-table rows for missing client islands in the React Client Manifest.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Suggested labels: benchmark

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also adds clientReferences scope and manifest troubleshooting guidance, which is unrelated to the warm SSR cache vs RSC benchmarking issue. Split the clientReferences and manifest updates into a separate PR, or remove them unless they are explicitly part of this change.
✅ 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 is concise and accurately describes the main change: documenting warm SSR cache benchmarking for RSC.
Linked Issues check ✅ Passed The docs add warm SSR vs RSC benchmarking guidance, a static landing-page example, and a cache-state matrix matching the linked issue's core requirements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg-codex/rsc-perf-docs-4294

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.

@claude

claude Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review

This PR adds a docs-only section to performance-benchmarks.md covering how to benchmark RSC against an already-warm React on Rails Pro SSR/fragment cache: a cache-state matrix (cold/warm × SSR/RSC), a static-landing-page example using cached_react_component_hash, and guidance on avoiding apples-to-oranges comparisons (asset/head parity, Flight payload bytes, TBT vs. LCP tradeoffs).

I verified the technical claims against the actual Pro implementation rather than taking them at face value:

  • Fragment-cache hit skips prop assembly/serialization/JS eval (lines 98-99): confirmed — Cache.fetch_react_component in react_on_rails_pro/lib/react_on_rails_pro/cache.rb never invokes the block (which builds and yields props) on a cache hit.
  • Prerender-cache hit still assembles/serializes props but reuses the render result (lines 99-101): confirmed — ProRendering.render_with_cache in react_on_rails_pro/lib/react_on_rails_pro/server_rendering_pool/pro_rendering.rb receives already-serialized js_code and only caches the JS execution step.
  • RORP_CACHE_HIT, config.prerender_caching, cached_react_component_hash, auto_load_bundle, append_javascript_pack_tag/preload_pack_asset all exist and are used correctly.
  • The two new anchor links (caching.md#level-1-prerender-caching, #level-2-fragment-caching) match the actual headings in caching.md.

No correctness, security, or performance issues — this is a documentation-only change with no code/logic modified. Claims are well-hedged and consistent with the rest of the doc's cautious tone (e.g., explicitly warning that a warm-cache "tie" shouldn't be framed as an RSC failure). Nothing to flag.

@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: b6278b2cd4

ℹ️ 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 thread docs/oss/core-concepts/performance-benchmarks.md
Comment thread docs/oss/core-concepts/performance-benchmarks.md Outdated
Comment thread docs/oss/core-concepts/performance-benchmarks.md
Comment thread docs/oss/core-concepts/performance-benchmarks.md Outdated
Comment thread docs/oss/core-concepts/performance-benchmarks.md
@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown

Greptile Summary

Adds a "Benchmarking RSC Against Warm SSR Caches" section to the performance benchmarks guide, targeted at teams that already have React on Rails Pro warm SSR caches and want a fair methodology for comparing RSC conversions.

  • Introduces a cache-state matrix (cold/warm × SSR/RSC) with preparation steps and what each variant answers, plus guidance on reading RSC wins vs. non-wins and Flight payload accounting.
  • Includes a representative ERB snippet of a fragment-cached landing page to anchor the discussion — but the snippet assigns cached_react_component_hash's return value to rendered without ever outputting it, so the example is incomplete and would produce no component HTML if copied verbatim.

Confidence Score: 3/5

Documentation-only change with no runtime risk, but the ERB code example is demonstrably incomplete and would mislead developers who copy it.

The ERB snippet assigns the cached_react_component_hash return value to rendered but never outputs rendered["html"] or the console-replay script. Every other usage example in the repo shows the output step immediately after the block, making this a real defect in the example rather than an intentional abbreviation.

docs/oss/core-concepts/performance-benchmarks.md — the Static landing-page pattern ERB snippet needs the rendered output lines added to match canonical usage.

Important Files Changed

Filename Overview
docs/oss/core-concepts/performance-benchmarks.md Adds an 87-line Benchmarking RSC Against Warm SSR Caches section with cache-state matrix, ERB pattern, and guidance on reading results — but the ERB snippet assigns rendered from cached_react_component_hash without ever outputting it, which would produce a blank component slot if copied verbatim.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Start RSC benchmark] --> B{Existing page uses fragment/prerender cache?}
    B -- No --> C[SSR cold baseline is sufficient]
    B -- Yes --> D[Establish warm cache baseline / log RORP_CACHE_HIT]
    D --> E[Run cache-state matrix]
    E --> E1[Cold uncached SSR]
    E --> E2[Warm cached SSR]
    E --> E3[RSC cold]
    E --> E4[RSC warm]
    E1 & E2 & E3 & E4 --> F[Compare same build/data/CDN/throttle]
    F --> G{RSC shows win?}
    G -- LCP improved --> H[Check asset/head parity: CSS fonts LCP image]
    G -- JS bytes down but LCP worse --> I[Likely CSS font or LCP resource delay]
    G -- First-paint tie --> J[Still valuable for maintainability lower TBT]
    H & I & J --> K[Pair JS bytes with HTML transfer + Flight payload bytes]
    K --> L[Publish labeled results per cache state]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Start RSC benchmark] --> B{Existing page uses fragment/prerender cache?}
    B -- No --> C[SSR cold baseline is sufficient]
    B -- Yes --> D[Establish warm cache baseline / log RORP_CACHE_HIT]
    D --> E[Run cache-state matrix]
    E --> E1[Cold uncached SSR]
    E --> E2[Warm cached SSR]
    E --> E3[RSC cold]
    E --> E4[RSC warm]
    E1 & E2 & E3 & E4 --> F[Compare same build/data/CDN/throttle]
    F --> G{RSC shows win?}
    G -- LCP improved --> H[Check asset/head parity: CSS fonts LCP image]
    G -- JS bytes down but LCP worse --> I[Likely CSS font or LCP resource delay]
    G -- First-paint tie --> J[Still valuable for maintainability lower TBT]
    H & I & J --> K[Pair JS bytes with HTML transfer + Flight payload bytes]
    K --> L[Publish labeled results per cache state]
Loading

Reviews (1): Last reviewed commit: "Document warm SSR cache benchmarking for..." | Re-trigger Greptile

Comment thread docs/oss/core-concepts/performance-benchmarks.md
Comment thread docs/oss/core-concepts/performance-benchmarks.md
@claude

claude Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review summary

This is a docs-only PR adding an "RSC vs warm SSR cache" benchmarking guide to docs/oss/core-concepts/performance-benchmarks.md: a cache-state matrix, a static landing-page example, and guidance on when RSC does/doesn't beat a warm cache. All cross-links (caching.md#level-1-prerender-caching, #level-2-fragment-caching, #popmenu) resolve correctly, and RORP_CACHE_HIT is a real symbol set by the fragment-cache path.

Three issues worth a look, left as inline comments — the first is a concrete bug in the example code, the other two are technical-accuracy nits verified against the actual helper implementation:

  1. docs/oss/core-concepts/performance-benchmarks.md:108-126 — The "static landing-page pattern" example computes rendered = cached_react_component_hash(...) do ... end inside a non-outputting <% %> tag and never emits it (no <%= rendered %>). Copied verbatim, the example renders nothing.
  2. docs/oss/core-concepts/performance-benchmarks.md:92-96 — States that using cached_react_component/cached_react_component_hash "with config.prerender_caching = true" gives a warm prerender-cache baseline. In the actual code, both fragment-caching helpers unconditionally set skip_prerender_cache: true, which makes cache_enabled_for? in pro_rendering.rb return false regardless of config.prerender_caching — so that config has no effect on calls through these helpers. The "warm" state being described is the fragment cache, not the prerender cache.
  3. docs/oss/core-concepts/performance-benchmarks.md:122auto_load_bundle: false in the example only takes effect if the app's global config.auto_load_bundle is already false, since the helper computes ReactOnRails.configuration.auto_load_bundle || raw_options[:auto_load_bundle] (global-first OR). Apps with auto_load_bundle: true globally can't override it per-call this way.

Nothing else stood out — links, anchors, and table formatting all check out.

justin808 added 3 commits July 1, 2026 13:09
…s-4294

* origin/main:
  Docs: clarify RSC client reference scoping (#4309)
  Docs: add RSC performance optimization skill (#4308)
  Document HiChee RSC backport triage matrix (#4305)

@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: 6b11c4733f

ℹ️ 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 thread docs/oss/core-concepts/performance-benchmarks.md Outdated
@claude

claude Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Summary

Docs-only PR — no application code changes. I cross-checked the new Benchmarking RSC Against Warm SSR Caches section in docs/oss/core-concepts/performance-benchmarks.md against the actual Pro helper implementation and existing docs:

  • cached_react_component_hash / cached_react_component behavior (skip_prerender_cache, RORP_CACHE_HIT, RORP_CACHE_KEY) matches react_on_rails_pro/app/helpers/react_on_rails_pro_helper.rb.
  • The auto_load_bundle: false caveat is precisely correct: sanitized_options[:auto_load_bundle] = ReactOnRails.configuration.auto_load_bundle || raw_options[:auto_load_bundle] means the per-call false is silently overridden by a global config.auto_load_bundle = true (OR logic). Good catch calling that out explicitly — it's a real, non-obvious gotcha.
  • componentHtml / consoleReplayScript hash keys match react_component_hash's actual return shape.
  • Both caching.md anchor links (#level-1-prerender-caching, #level-2-fragment-caching) resolve to real headers.
  • The large llms-full.txt diff is not new content — it's the generated file catching up to doc content already merged into main via Document HiChee RSC backport triage matrix #4305/Docs: add RSC performance optimization skill #4308/Docs: clarify RSC client reference scoping #4309 (verified those sections already exist in origin/main's source .md files). This file has a deterministic generator (script/generate-llms-full.mjs) with a CI drift check, so it's low-risk.

Minor nit (non-blocking): in the second paragraph, "Fragment-caching helpers skip the prerender cache for that render call because the full fragment is already cached" reads as if this happens on a cache hit, but skip_prerender_cache: true is actually only set on the miss path (the block passed to Rails.cache.fetch only runs on miss). On a hit, no render call happens at all — props/JSON/JS work is skipped entirely, which the preceding sentence already states correctly. Could reword slightly to avoid implying the skip-prerender-cache flag is what produces the hit-path savings.

No security or performance concerns (documentation only). No blocking issues found.

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.

Document warm SSR prerender cache vs RSC performance tradeoffs

1 participant