Skip to content

Commit b76a52c

Browse files
justin808claude
andauthored
docs: RSC integration pitfalls from tutorial app (#3087)
## Summary Documents five real-world RSC integration pitfalls discovered during the [react-webpack-rails-tutorial RSC integration](shakacode/react-webpack-rails-tutorial#723): - **VM sandbox constraints** (`rendering-flow.md`, `rsc-troubleshooting.md`): Documents why `externals` must not be used for Node builtins in the server bundle (generates `require()` calls that fail in the VM sandbox), and that `resolve.fallback: false` is the correct approach - **MessageChannel polyfill** (`rsc-troubleshooting.md`): Documents the `BannerPlugin` polyfill pattern for `react-dom/server.browser.js` which needs `MessageChannel` at module load time - **`'use client'` classification audit** (`upgrading-existing-pro-app.md`): Adds a pre-migration section covering the `.server.jsx` naming collision, how auto-classification works, and a checklist of client APIs to audit for - **CI/test environment setup** (`basics.md`): Documents `Rails.env.local?` vs `Rails.env.development?`, TCP readiness checks, `RENDERER_PASSWORD` in CI, and a common CI failures table - **Three-bundle architecture table** (`rendering-flow.md`): Adds a reference table comparing all three bundles across runtime, Node builtin handling, `require()` availability, CSS extraction, and env vars Closes #3076 ## Test plan - [ ] Verify all markdown links resolve (pre-push hook validates this) - [ ] Verify formatting passes prettier (pre-commit hook validates this) - [ ] Review each doc section for technical accuracy against the [tutorial PR](shakacode/react-webpack-rails-tutorial#723) 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk because changes are documentation-only, though reviewers should sanity-check technical accuracy of the new webpack/VM and CI guidance. > > **Overview** > Adds a new **CI/test setup section** for the Node Renderer, including `Rails.env.local?` initializer guarding, a GitHub Actions example that starts the renderer with an HTTP/2 (h2c) readiness probe, `RENDERER_PASSWORD` guidance, and a common-failures table. > > Expands RSC troubleshooting and Pro RSC docs to clarify **bundle runtime differences** (client vs SSR server bundle VM sandbox vs full-Node RSC bundle), document `require()`/missing-global failure modes, recommend `resolve.fallback: false` over webpack `externals` for Node builtins in the server bundle, and add guidance for handling missing `MessageChannel` (polyfill via `BannerPlugin` / prefer `additionalContext`). > > Adds a pre-migration checklist for existing Pro apps to audit for client-only APIs and warns about the `.server.jsx` naming collision that can cause unintended Server Component classification without `'use client'`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit bf26cb1. 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** * Added CI/test SSR setup with readiness checks, env guidance, retry/fail behavior, and mapped common CI failure symptoms to fixes. * Expanded runtime and bundle architecture guidance, clarifying sandboxed server vs full-Node RSC constraints and safer handling of Node builtins to avoid runtime require failures. * Added troubleshooting entries for missing globals (require, MessageChannel) and guidance for polyfill or context-injection fixes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 63c4cfe commit b76a52c

4 files changed

Lines changed: 245 additions & 15 deletions

File tree

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

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,82 @@ This means a developer running the renderer locally without a password is safe b
121121

122122
See [JS Configuration](./js-configuration.md) for the `host` and `password` options, and [Container Deployment](./container-deployment.md) for architecture-specific guidance.
123123

124+
## CI and Test Environment Setup
125+
126+
Running tests that involve server-side rendering requires the Node Renderer to be running. Without it, tests will silently timeout with `Net::ReadTimeout` -- not crash with a clear error -- making the failure easy to misdiagnose.
127+
128+
### 1. Guard the initializer for test environments
129+
130+
A common mistake is guarding the Node Renderer configuration with `Rails.env.development?`, which excludes the test environment:
131+
132+
```ruby
133+
# config/initializers/react_on_rails_pro.rb
134+
135+
# WRONG -- excludes test environment
136+
if Rails.env.development?
137+
ReactOnRailsPro.configure do |config|
138+
config.server_renderer = "NodeRenderer"
139+
end
140+
end
141+
142+
# CORRECT -- covers both development and test
143+
if Rails.env.local?
144+
ReactOnRailsPro.configure do |config|
145+
config.server_renderer = "NodeRenderer"
146+
end
147+
end
148+
```
149+
150+
`Rails.env.local?` returns `true` for both `development` and `test` environments (available since Rails 7.1). For older Rails versions, use `Rails.env.development? || Rails.env.test?`.
151+
152+
### 2. Start the renderer in CI
153+
154+
The Node Renderer must be started as a background process before running tests. Add a step to your CI workflow:
155+
156+
```yaml
157+
# .github/workflows/test.yml (GitHub Actions example)
158+
jobs:
159+
test:
160+
env:
161+
# Job-level: both the renderer and Rails test steps need this
162+
RENDERER_PASSWORD: ${{ secrets.RENDERER_PASSWORD }}
163+
steps:
164+
- name: Start Node Renderer
165+
run: |
166+
node client/node-renderer.js &
167+
# Wait for the renderer to be ready.
168+
# The renderer uses cleartext HTTP/2 (h2c), so use --http2-prior-knowledge for the probe.
169+
# --max-time 2 prevents hangs if the port is open but the process is stalled.
170+
for i in $(seq 1 30); do
171+
if curl -s --http2-prior-knowledge --max-time 2 http://localhost:3800/ > /dev/null 2>&1; then
172+
echo "Node Renderer is ready"
173+
break
174+
fi
175+
echo "Waiting for Node Renderer... ($i/30)"
176+
sleep 1
177+
done
178+
# Fail fast if renderer never became ready
179+
if ! curl -s --http2-prior-knowledge --max-time 2 http://localhost:3800/ > /dev/null 2>&1; then
180+
echo "Node Renderer failed to start in time" >&2
181+
exit 1
182+
fi
183+
```
184+
185+
Key points:
186+
187+
- **Readiness check**: Poll port 3800 (or your configured port) before running tests. The renderer uses **cleartext HTTP/2 (h2c)**, so the `curl` probe must include `--http2-prior-knowledge`. Without it, `curl` sends an HTTP/1.1 request that the h2c server rejects.
188+
- **`RENDERER_PASSWORD`**: Must be set in the CI environment and match the value configured in `react_on_rails_pro.rb`. Add it as a CI secret. **Important:** Declare this at the job level (not just the renderer step) so Rails can also read it when running tests.
189+
- **Bundle pre-staging**: You do **not** need to set a bundle path env var for the renderer. In CI, run `rake react_on_rails_pro:pre_stage_bundle_for_node_renderer` after the webpack build and before starting the renderer — this symlinks the compiled bundle into the renderer's cache directory, eliminating the first-request upload latency. For remote renderers, use `rake react_on_rails_pro:copy_assets_to_remote_vm_renderer` instead.
190+
191+
### 3. Common CI failures
192+
193+
| Symptom | Cause | Fix |
194+
| ----------------------------------------- | ------------------------------ | -------------------------------------- |
195+
| All tests timeout with `Net::ReadTimeout` | Node Renderer not running | Add the renderer start step above |
196+
| "Connection refused" errors | Renderer started but not ready | Add the TCP readiness check loop |
197+
| Tests pass locally but fail in CI | `Rails.env.development?` guard | Change to `Rails.env.local?` |
198+
| "Invalid password" errors | `RENDERER_PASSWORD` mismatch | Ensure CI env var matches Rails config |
199+
124200
## Troubleshooting
125201

126202
- See [Memory Leaks guide](../../../pro/js-memory-leaks.md).

0 commit comments

Comments
 (0)