You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Summary
Collapses `ReactOnRailsPro::PreSeedRendererCache` (copy) and
`ReactOnRailsPro::PrepareNodeRenderBundles` (symlink) into a single
entry point: `PreSeedRendererCache.call(mode: :copy | :symlink)`. Both
modes produce the same \`<cache>/<bundleHash>/<bundleHash>.js\` layout —
only the file operation differs.
Stacked on #3124 (PR A). Target base is
\`jg/3122-preseed-renderer-cache\`; will be rebased onto \`master\` once
PR A merges. Refs #3122.
## Changes
- **Unified API**: \`PreSeedRendererCache.call(mode: :copy)\` for
Docker/image builds (default); \`(mode: :symlink)\` for same-filesystem
workflows (local dev, CI, Heroku-style same-dyno deploys, bundle-caching
restores). Unknown modes → \`ArgumentError\`.
- **Non-dev env-var guard (copy mode only)**: When neither
\`RENDERER_SERVER_BUNDLE_CACHE_PATH\` nor \`RENDERER_BUNDLE_PATH\` is
set in a non-dev/test environment, \`mode: :copy\` raises a clear error.
Motivation: the Node renderer's default cache-path resolution can differ
from the Ruby side (falling back to \`/tmp\` when \`cwd\` is outside the
app tree), so silent fallback is a misconfig footgun that pre-seeds
bundles into a directory the renderer never reads.
- **Rake task**: \`react_on_rails_pro:pre_seed_renderer_cache\` accepts
\`MODE=copy\` (default) or \`MODE=symlink\`.
- **Deprecations (soft)**: \`PrepareNodeRenderBundles\` and the
\`pre_stage_bundle_for_node_renderer\` rake task remain as thin shims
emitting once-per-process deprecation warnings; both delegate to the
unified API with \`mode: :symlink\`. No behavior change for existing
users.
- **Auto-invocation**: \`AssetsPrecompile.call\` now calls
\`PreSeedRendererCache.call(mode: :symlink)\` after precompile
(previously \`PrepareNodeRenderBundles.call\` — same effect).
- **Doctor check**: \`react_on_rails:doctor\` scans common deploy-script
locations (\`Procfile*\`, \`Dockerfile\`, \`bin/deploy\`,
\`bin/release\`, \`bin/docker-entrypoint\`) for references to the
deprecated task and surfaces a migration warning.
- **Docs**: \`docs/pro/node-renderer.md\` updated to describe both
modes, the non-dev env-var requirement for copy, and the deprecation
story.
- **CHANGELOG**: new \`Changed\` entry.
## Why this shape
- The two classes shared ~90% of their logic after #3124 (both use
\`RendererCacheHelpers\` for bundle validation, asset collection, and
required-RSC-asset path construction). Keeping them separate forced
readers to understand two entry points with parallel semantics.
- Single class with \`mode:\` keeps the public surface obvious: the user
picks copy vs symlink based on whether bundles need to survive Docker
layer boundaries. Everything else is shared.
- Soft deprecation avoids breaking users with
\`Procfile\`/\`Dockerfile\`/\`bin/\` entries pinned to the old names.
The doctor check gives them a clear migration nudge.
## Test plan
- [x] 26 dummy specs pass for both \`pre_seed_renderer_cache_spec.rb\`
and \`prepare_node_renderer_bundles_spec.rb\` (+6 new: mode validation,
symlink mode via unified API, raise-in-non-dev guard, symlink mode
opt-out from guard, env-var bypass for guard, deprecation warning on the
shim).
- [x] 2 new doctor specs for \`check_deprecated_renderer_cache_task\`:
Procfile-reference warning + no-match silence.
- [x] 163 total doctor specs pass (1 pre-existing unrelated failure in
\`auto_fix_versions\`, not introduced by this PR).
- [x] \`bundle exec rubocop\` clean on all changed files.
- [ ] CI (will verify after push).
## Migration path for users
- Existing \`Procfile\` / \`Dockerfile\` / \`bin/*\` entries that call
\`pre_stage_bundle_for_node_renderer\` keep working unchanged — they
emit a one-time deprecation warning and delegate to \`MODE=symlink\`.
- Doctor surfaces affected files with migration guidance.
- No changes needed for users relying on \`AssetsPrecompile.call\`
auto-invocation (same behavior).
- Docker builds that were using the old task name should migrate to
\`MODE=copy\` (the default) for image-baked caches.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Touches Pro deployment/SSR renderer-cache staging behavior and
introduces new env-var enforcement in `MODE=copy`, which could break
misconfigured non-dev environments; changes are mitigated by deprecation
shims and added doctor warnings/tests.
>
> **Overview**
> **Unifies Node Renderer cache staging in Pro** by making
`ReactOnRailsPro::PreSeedRendererCache.call(mode: :copy | :symlink)` the
single entry point; both modes produce the same
`<cache>/<bundleHash>/<bundleHash>.js` layout and the rake task
`react_on_rails_pro:pre_seed_renderer_cache` now accepts `MODE=copy`
(default) or `MODE=symlink`.
>
> **Deprecates legacy paths**:
`react_on_rails_pro:pre_stage_bundle_for_node_renderer` and
`ReactOnRailsPro::PrepareNodeRenderBundles` now warn and delegate to
`mode: :symlink`, while `assets:precompile` auto-stages via `mode:
:symlink`.
>
> **Adds safety/migration checks**: `MODE=copy` now raises in
non-dev/test when neither `RENDERER_SERVER_BUNDLE_CACHE_PATH` nor
`RENDERER_BUNDLE_PATH` is set, and `react_on_rails:doctor` scans common
deploy scripts for the deprecated task and suggests the correct
replacement.
>
> Docs/CHANGELOG are updated for the new modes and deprecations; specs
are expanded for the new behavior, and the link checker ignore list adds
`guavapass.com`.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f511867. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,6 +34,7 @@ After a release, run `/update-changelog` in Claude Code to analyze commits, writ
34
34
35
35
#### Changed
36
36
37
+
- **[Pro]** **Unified renderer cache staging**: `ReactOnRailsPro::PreSeedRendererCache.call(mode: :copy | :symlink)` is now the single entry point for staging the Node Renderer cache. Both modes produce the same `<cache>/<bundleHash>/<bundleHash>.js` layout. The `react_on_rails_pro:pre_seed_renderer_cache` rake task accepts `MODE=copy` (default; Docker/image builds) or `MODE=symlink` (same-filesystem). `MODE=copy` now raises a clear error when neither `RENDERER_SERVER_BUNDLE_CACHE_PATH` nor `RENDERER_BUNDLE_PATH` is set in non-dev/test environments, because the Node renderer's default lookup can differ from the Ruby side and would silently drop pre-seeded bundles in the wrong directory. The legacy `react_on_rails_pro:pre_stage_bundle_for_node_renderer` task and `ReactOnRailsPro::PrepareNodeRenderBundles` class remain as deprecated shims that emit a once-per-process warning and delegate to `mode: :symlink`. `react_on_rails:doctor` flags deploy scripts that still reference the deprecated task. [PR 3167](https://github.com/shakacode/react_on_rails/pull/3167) by [justin808](https://github.com/justin808).
37
38
-**[Pro]****Pro generator now creates the Node Renderer at `renderer/node-renderer.js`**: The canonical location for the Node Renderer entry point is now a dedicated top-level `renderer/` directory instead of `client/`, making it straightforward to exclude from production Docker builds that strip JS sources after bundling. Docs and Pro `spec/dummy` now use the new path consistently. Existing apps are unaffected — the generator skips files that already exist (including a legacy `client/node-renderer.js`). Fixes [Issue 3073](https://github.com/shakacode/react_on_rails/issues/3073). [PR 3165](https://github.com/shakacode/react_on_rails/pull/3165) by [justin808](https://github.com/justin808).
38
39
-**Rspack install scaffolding now targets Rspack v2**: `react_on_rails:install --rspack` and `bin/switch-bundler` now generate the Rspack v2 package line (`@rspack/core@^2.0.0-0`, `@rspack/cli@^2.0.0-0`, `@rspack/plugin-react-refresh@^2.0.0`) while keeping `rspack-manifest-plugin@^5.0.0`, which is already compatible. Closes [Issue 3082](https://github.com/shakacode/react_on_rails/issues/3082). [PR 3084](https://github.com/shakacode/react_on_rails/pull/3084) by [justin808](https://github.com/justin808).
Copy file name to clipboardExpand all lines: docs/pro/node-renderer.md
+15-6Lines changed: 15 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -119,26 +119,35 @@ When a new container starts, the Node Renderer has an empty bundle cache. The fi
119
119
120
120
### Pre-seeding the bundle cache
121
121
122
-
The `pre_seed_renderer_cache` rake task copies compiled server bundles directly into the renderer's cache directory during your Docker build, so the renderer finds them immediately on startup:
122
+
The `pre_seed_renderer_cache` rake task stages compiled server bundles directly into the renderer's cache directory, so the renderer finds them immediately on startup.
123
+
124
+
It supports two modes, both producing the same on-disk cache layout (`<cache>/<bundleHash>/<bundleHash>.js`):
125
+
126
+
-**`MODE=copy`** (default) — copies files. Use in Docker/image builds so the cache is baked into an immutable artifact.
RUN bundle exec rake react_on_rails_pro:pre_seed_renderer_cache
127
133
```
128
134
129
-
This copies the bundle into the renderer's expected directory structure (`<cache>/<bundleHash>/<bundleHash>.js`), including any configured `assets_to_copy` and RSC bundles when RSC support is enabled.
135
+
Both modes stage the server bundle, any configured `assets_to_copy`, and (when RSC is enabled) the RSC bundle and its companion manifests.
130
136
131
-
This is the preferred path for Docker and other image-build workflows. React on Rails Pro has long supported runtime bundle uploads and the older `react_on_rails_pro:pre_stage_bundle_for_node_renderer` task for same-filesystem deployments; `pre_seed_renderer_cache` is the copy-based variant that fits immutable artifacts while using the same bundle-hash cache layout.
137
+
The `pre_seed_renderer_cache` task is also invoked automatically at the end of `assets:precompile` with `MODE=symlink`, so the local/CI/Heroku path has zero new configuration.
138
+
139
+
> [!NOTE]
140
+
> The older `react_on_rails_pro:pre_stage_bundle_for_node_renderer` rake task and `ReactOnRailsPro::PrepareNodeRenderBundles` class are deprecated in favor of the unified API. Both remain available as thin shims that emit a deprecation warning and delegate to `MODE=symlink`. `react_on_rails:doctor` flags deploy scripts that still reference the deprecated task.
132
141
133
142
### Configuration
134
143
135
144
The task follows the same environment-variable precedence as the Node Renderer, while the default fallback can differ between Ruby and standalone Node environments:
2.`RENDERER_BUNDLE_PATH` environment variable (deprecated — emits a warning)
139
-
3.`Rails.root.join(".node-renderer-bundles")` (Rails-side default when env vars are unset)
148
+
3.`Rails.root.join(".node-renderer-bundles")` (Rails-side default when env vars are unset, only accepted for `MODE=symlink` and in dev/test)
140
149
141
-
Set `RENDERER_SERVER_BUNDLE_CACHE_PATH` in your Dockerfile to match the renderer's configuration:
150
+
In **`MODE=copy`** (Docker image builds) the task requires one of the env vars above to be set in non-dev/test environments. "Non-dev/test" means any `RAILS_ENV` other than `development` or `test` — including custom environments like `staging`, `review`, or `ci` — so set `RENDERER_SERVER_BUNDLE_CACHE_PATH` wherever you run `MODE=copy` outside of local/CI-test runs. Because the Node renderer's own default can differ (e.g., falling back to `/tmp/react-on-rails-pro-node-renderer-bundles` when its `cwd` sits outside the app tree), relying on the silent fallback risks pre-seeded bundles landing in a directory the renderer never reads. The task raises a clear error if the env var is missing:
0 commit comments