Skip to content

Commit 81ef2fa

Browse files
authored
Docs: add React Performance Tracks profiling guide (#3961)
## Summary Part of #3893. This completes the docs remainder from the 2026-06-11 triage and intentionally avoids source-map-specific claims while #3940 remains open. - adds a React Performance Tracks and profiling guide - refreshes the existing Node Renderer `--inspect` debugging page - refreshes the Pro SSR profiling page and links it back to the debugging/profiling decision guide - adds the new guide to `docs/sidebars.ts` - regenerates `llms-full.txt` ## Coordination - #3940 is still open and edits `docs/oss/building-features/node-renderer/debugging.md`; whichever branch lands second may need a small textual conflict resolution. - No semantic merge-after dependency on #3940: this PR omits source-map behavior references. ## Test plan - `node script/generate-llms-full.mjs` -> generated 146 pages, 2042 KiB, 72 docs URLs validated - `node script/generate-llms-full.mjs --check` -> pass - `script/check-docs-sidebar` -> pass - `script/ci-changes-detector origin/main` -> documentation-only, recommended CI: none - `pnpm start format.listDifferent` -> pass - `bin/check-links` -> pass, 2784 total, 0 errors - `git diff --check origin/main...HEAD` -> pass - `(cd react_on_rails && BUNDLE_GEMFILE=../Gemfile bundle exec rubocop)` -> pass Labels: none — docs-only, no code/workflow surface. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Documentation-only changes with no runtime, API, or workflow code paths affected. > > **Overview** > Adds **`performance-tracks-and-profiling.md`**, a decision guide for browser React Performance Tracks, Pro Node Renderer CPU profiling, breakpoints, memory, and production telemetry (Web Vitals, OpenTelemetry, error tracing), plus workflows for recording tracks, correlating browser and renderer traces, and User Timing in the renderer VM. > > **Refreshes** the Node Renderer debugging page with a concrete `overmind stop` + `pnpm run node-renderer:debug` quick start, a **Breakpoints vs. profiles** section, and cross-links; drops the old external Node debugger stub. > > **Modernizes** the Pro SSR profiling guide (title, `node-renderer:debug` script, clearer timeout/caching notes, hydration pointer to the new guide, ExecJS log typo `isolate`, **speedscope** via `pnpm dlx` / `npx` / `yarn dlx` instead of global install). > > Registers the new page under **Development & Ops** in `docs/sidebars.ts` and regenerates **`llms-full.txt`**. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e35d684. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Expanded renderer debugging guide with clearer quick-start steps for attaching the inspector, isolating renderer logs, setting breakpoints, and alternative inspect workflows * Added a comprehensive performance-profiling guide mapping symptoms to workflows and explaining React Performance Tracks and trace correlation * Modernized server-side rendering profiling guidance with updated recording, timeout troubleshooting, and analysis workflows * Updated docs navigation to surface the new profiling guidance <!-- end of auto-generated comment: release notes by coderabbit.ai --> ## Agent Merge Confidence Mode: accelerated-rc Current head SHA: e35d684 Score: 8/10 Auto-merge recommendation: yes Affected areas: OSS/Pro docs, docs sidebar, llms-full generated reference CI detector: `script/ci-changes-detector origin/main` -> Documentation-only changes; recommends no CI jobs Validation run: - `node script/generate-llms-full.mjs` -> generated; 146 pages, 2048 KiB, split threshold 2048 KiB; 73 docs URLs and 8 sidebar top-level sections validated - `node script/generate-llms-full.mjs --check` -> current; 146 pages, 2048 KiB, split threshold 2048 KiB - `script/check-docs-sidebar` -> new doc `building-features/performance-tracks-and-profiling` has sidebar entry - `pnpm start format.listDifferent` -> pass - Pre-commit/pre-push markdown link hooks -> pass Review/check gate: - GitHub checks: complete for `e35d6847a899ee5ed32bdda92a54adac9cbc0b7e`; 15 pass, 2 expected skips explained - Expected skips: secondary `claude` job skipped while `claude-review` passed; `build` in Lint JS and Ruby skipped by docs-only path selection while docs-format and local Prettier passed - Review threads: GraphQL unresolved count is 0 - Current-head reviewer verdicts: - Claude review: `claude-review` check passed for `e35d6847a899ee5ed32bdda92a54adac9cbc0b7e`; actionable debugging-flow threads fixed; later clarity nits triaged optional and resolved - CodeRabbit: check succeeded with "Review skipped" Known residual risk: Low; PR #3940 is still open, so this docs PR intentionally avoids source-map behavior references. llms-full is exactly at the 2048 KiB no-split threshold, so future docs additions will likely need the OSS/Pro split. Finalized by: `claude-review` GitHub check / Claude Code Review workflow for current head, run https://github.com/shakacode/react_on_rails/actions/runs/27463255831/job/81180874270
1 parent 47ab779 commit 81ef2fa

5 files changed

Lines changed: 329 additions & 102 deletions

File tree

docs/oss/building-features/node-renderer/debugging.md

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
> **Pro Feature** — Available with [React on Rails Pro](../../../pro/react-on-rails-pro.md).
44
> Free or very low cost for startups and small companies. [Upgrade or licensing details →](../../../pro/upgrading-to-pro.md#try-pro-risk-free)
55
6-
Because the renderer communicates over a port to the server, you can start a renderer instance locally in your application and debug it.
6+
Because the renderer communicates over a port to Rails, you can start a local renderer instance with Node's inspector and debug the server-rendered JavaScript directly.
7+
8+
Use this page for breakpoints, renderer logs, and memory snapshots. For CPU flamegraphs, use [Profiling Server-Side Rendering Code](../../../pro/profiling-server-side-rendering-code.md). For React 19.2 Performance Tracks, hydration traces, and choosing the right profiling tool, use [React Performance Tracks and Profiling](../performance-tracks-and-profiling.md).
79

810
## Monorepo Workflow
911

@@ -14,11 +16,22 @@ It is a `pnpm` workspace app and already points at the local packages in this mo
1416

1517
### Quick start: debugging with the full stack running
1618

17-
If you already have the dummy app running via `bin/dev` (which uses `Procfile.dev`), the node renderer is listening on port 3800 but without `--inspect`. To attach a debugger you first need to restart it with `--inspect` — either stop the renderer process and run `pnpm run node-renderer:debug`, or temporarily add `--inspect` to the `node-renderer:` entry in `Procfile.dev` and `overmind restart node-renderer`. Then:
19+
If you already have the dummy app running via `bin/dev` (which uses `Procfile.dev`), the node renderer is listening on port 3800 without `--inspect`. To attach a debugger, restart only the renderer with the inspector enabled:
20+
21+
```bash
22+
cd react_on_rails_pro/spec/dummy
23+
overmind stop node-renderer
24+
pnpm run node-renderer:debug
25+
```
26+
27+
Keep that terminal open while you debug. Then:
1828

1929
1. Open `chrome://inspect` in Chrome and connect to the renderer process.
20-
2. Use overmind to isolate renderer logs: `overmind connect node-renderer` (Ctrl-B to detach).
21-
3. After a code change, restart just the renderer: `overmind restart node-renderer`.
30+
2. Watch renderer logs in that terminal. Keep `bin/dev` visible for Rails logs.
31+
3. Set breakpoints in the inspector and reload the page that triggers SSR.
32+
4. After a server-bundle or renderer change, press Ctrl-C and rerun `pnpm run node-renderer:debug`.
33+
34+
If you prefer to keep the renderer under Overmind, temporarily add `--inspect` to the `node-renderer:` entry in `Procfile.dev`, then run `overmind restart node-renderer`.
2235

2336
### Isolated debugging: manual per-terminal startup
2437

@@ -52,6 +65,13 @@ Use this when you need full control over the renderer process — different flag
5265
```
5366
1. If you are debugging an external app instead of the monorepo dummy app, refresh the installed renderer package using your local package workflow (for example `yalc`, `npm pack`, or a workspace link) before rerunning the renderer.
5467

68+
### Breakpoints vs. profiles
69+
70+
- Use `--inspect` breakpoints when you need to inspect props, globals, module state, or the exact branch taken during SSR.
71+
- Use [the SSR profiling guide](../../../pro/profiling-server-side-rendering-code.md) when the code is correct but slow.
72+
- Use [React Performance Tracks and Profiling](../performance-tracks-and-profiling.md) when the slow path includes browser hydration, Suspense, RSC timing, or client interactions.
73+
- Use [Error Reporting and Tracing](./error-reporting-and-tracing.md) or [OpenTelemetry](../../../pro/node-renderer.md#observability-with-opentelemetry) for production request spans.
74+
5575
## Debugging Memory Leaks
5676

5777
If worker memory grows over time, use heap snapshots to find the source.
@@ -94,10 +114,6 @@ When diagnosing memory leaks in a containerized environment, running the Node re
94114

95115
See the [Memory Leaks guide](../../../pro/js-memory-leaks.md) for common patterns and fixes.
96116

97-
## Debugging using the Node debugger
98-
99-
1. See [this article](https://github.com/shakacode/react_on_rails/issues/1196) on setting up the debugger.
100-
101117
## Debugging Jest tests
102118

103119
1. See [the Jest documentation](https://jestjs.io/docs/troubleshooting) for overall guidance.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# React Performance Tracks and Profiling
2+
3+
React on Rails apps have three broad performance questions that look similar but need different tool clusters:
4+
5+
1. **What did the browser do?** Use Chrome DevTools Performance recordings with [React Performance Tracks](https://react.dev/reference/dev-tools/react-performance-tracks).
6+
2. **What did the React on Rails Pro Node Renderer do?** Use the Node inspector and the renderer tracing integrations.
7+
3. **What did real users experience?** Use field metrics such as [Web Vitals and Real User Monitoring](./web-vitals-and-rum.md).
8+
9+
React Performance Tracks are most useful when you can reproduce a slow interaction locally. They show React scheduler work, component render and effect durations, and, for React Server Components in development builds, server request and Server Component timing. They do not replace production telemetry, but they make the local trace much easier to read than a JavaScript stack alone.
10+
11+
## Choose the right profiling path
12+
13+
| Symptom | Start with | Why |
14+
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
15+
| Slow click, navigation, or hydration in the browser | Chrome DevTools Performance recording with React Performance Tracks | Shows React scheduler priority, component render cost, effects, network, layout, and paint on one timeline. |
16+
| A specific component renders too often | React Components track, React DevTools, and optional `<Profiler>` boundaries | Shows component render/effect duration and, in development builds, prop changes for selected entries. |
17+
| Slow server rendering in the Pro Node Renderer | [Profiling Server-Side Rendering Code](../../pro/profiling-server-side-rendering-code.md) | Attaches Chrome DevTools to the Node process and records CPU work such as bundle upload, VM setup, and render calls. |
18+
| Renderer breakpoints or request-by-request debugging | [Node Renderer Debugging](./node-renderer/debugging.md) | Uses `--inspect`, renderer logs, and focused restarts for breakpoint debugging. |
19+
| Production SSR latency or error correlation | [Error Reporting and Tracing](./node-renderer/error-reporting-and-tracing.md) and [OpenTelemetry](../../pro/node-renderer.md#observability-with-opentelemetry) | Captures spans and errors from live requests without attaching an inspector to production traffic. |
20+
| Memory growth in the renderer | [Memory Leaks](../../pro/js-memory-leaks.md) | Uses heap snapshots and worker restart strategy instead of CPU flamegraphs. |
21+
22+
## Record React Performance Tracks
23+
24+
Use this workflow for browser-side interaction, hydration, Suspense, and RSC timing investigations.
25+
26+
1. Run the app in development with React 19.2 or newer when your app supports that React line. For React on Rails Pro RSC apps, keep the React version supported by the current RSC guide and release notes; do not upgrade a generated RSC app only to capture Performance Tracks.
27+
2. Install and enable the React Developer Tools browser extension when you want the Components track to include the full component tree.
28+
3. Open Chrome DevTools, then open the **Performance** panel.
29+
4. Start recording, reload the page or perform the slow interaction, then stop recording.
30+
5. Inspect the React tracks alongside the normal browser tracks for network, JavaScript, layout, paint, and user timing.
31+
32+
React enables Performance Tracks automatically in development builds. In profiling builds, the Scheduler track is enabled by default. The Components track is limited to subtrees wrapped in `<Profiler>` unless the React DevTools extension is enabled. React's Server Components and Server Requests tracks are development-build only.
33+
34+
## Read the React tracks
35+
36+
The **Scheduler** track explains the priority and phase of React work:
37+
38+
- **Blocking** work usually comes from direct user interactions.
39+
- **Transition** work comes from non-blocking updates scheduled with `startTransition`.
40+
- **Suspense** work shows fallback and reveal timing.
41+
- **Idle** work runs only after higher-priority work is clear.
42+
43+
Within those lanes, look for update, render, commit, and remaining-effect spans. A render followed by repeated updates or long effects often points to avoidable state changes, expensive effects, or missing memoization boundaries.
44+
45+
The **Components** track shows component render and effect durations as flamegraphs. Use it to answer:
46+
47+
- Which component subtree is expensive?
48+
- Did the cost happen during render, layout effects, or passive effects?
49+
- Did a selected component receive changed props that explain the render?
50+
51+
The **Server** tracks are relevant when you use React Server Components in development. The Server Requests track visualizes async work that flows into Server Components, and the Server Components tracks show the component work and awaited Promises. Treat these as React-level RSC timing: they do not include every Rails controller, Fastify, network, or renderer worker cost.
52+
53+
## Keep names readable
54+
55+
Profiles are only useful when component and function names survive the build.
56+
57+
- Prefer named functions and named component exports over anonymous inline components.
58+
- Set `displayName` on components wrapped by helpers such as `memo` or `forwardRef` when the wrapper hides the useful name.
59+
- Use a development build first. It gives the clearest component names and enables the full React development instrumentation.
60+
- For a production-like profiling build, alias `react-dom/client` to `react-dom/profiling` at build time as described in the [React Performance Tracks docs](https://react.dev/reference/dev-tools/react-performance-tracks#using-profiling-builds), and preserve function/class names in that temporary build if minification erases useful labels. For Terser-style minifiers, that means profiling-only `keep_fnames` and `keep_classnames` settings or the equivalent setting in your bundler/minifier. Do not turn those knobs on blindly for production, since they can increase bundle size and reduce minification.
61+
62+
## Correlate browser and server work
63+
64+
For a local SSR/RSC investigation, collect one browser trace and one renderer trace for the same scenario:
65+
66+
1. Record the browser interaction with React Performance Tracks.
67+
2. Record the renderer process with the [SSR profiling workflow](../../pro/profiling-server-side-rendering-code.md).
68+
3. Compare timestamps, request logs, and component names. The browser trace shows hydration, interaction, Suspense, and paint timing. The renderer trace shows CPU spent before HTML or RSC payloads reach the browser.
69+
70+
If your server-rendered code needs its own named spans in a renderer CPU profile, add temporary User Timing marks around the code under investigation:
71+
72+
```js
73+
performance.mark('ror:ssr:ProductSummary:start');
74+
try {
75+
// Render or data preparation work under investigation.
76+
} finally {
77+
performance.mark('ror:ssr:ProductSummary:end');
78+
performance.measure('ror:ssr:ProductSummary', 'ror:ssr:ProductSummary:start', 'ror:ssr:ProductSummary:end');
79+
}
80+
```
81+
82+
In the Pro Node Renderer VM, `performance` is available when `supportModules: true`; otherwise inject it with `additionalContext`. See [Runtime Globals for SSR and RSC](./node-renderer/js-configuration.md#runtime-globals-for-ssr-and-rsc).
83+
84+
## Use production telemetry for production questions
85+
86+
Do not attach `--inspect` to production traffic as your primary profiling strategy. It slows the renderer and changes the workload you are trying to measure.
87+
88+
Use production-safe instrumentation instead:
89+
90+
- [Web Vitals and RUM](./web-vitals-and-rum.md) for user-visible browser outcomes such as LCP, INP, CLS, FCP, and TTFB.
91+
- [OpenTelemetry](../../pro/node-renderer.md#observability-with-opentelemetry) for SSR request spans from the Pro Node Renderer.
92+
- [Error Reporting and Tracing](./node-renderer/error-reporting-and-tracing.md) for Sentry, Honeybadger, and custom tracing integrations.
93+
- [Profiling Server-Side Rendering Code](../../pro/profiling-server-side-rendering-code.md) for short, local CPU profiling sessions when you can reproduce the slow path.

0 commit comments

Comments
 (0)