react_on_rails 17.0.1 → 17.1.0.rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.development_dependencies +1 -1
  3. data/Gemfile.lock +15 -15
  4. data/docs/agent/README.md +26 -0
  5. data/docs/agent/doctor-fix-loop.md +25 -0
  6. data/docs/agent/install-and-upgrade.md +164 -0
  7. data/docs/agent/rsc-adoption.md +31 -0
  8. data/docs/agent/streaming-debug.md +57 -0
  9. data/lib/generators/react_on_rails/base_generator.rb +4 -4
  10. data/lib/generators/react_on_rails/generator_helper.rb +12 -1
  11. data/lib/generators/react_on_rails/install_generator.rb +59 -7
  12. data/lib/generators/react_on_rails/js_dependency_manager.rb +1 -1
  13. data/lib/generators/react_on_rails/pro_generator.rb +5 -3
  14. data/lib/generators/react_on_rails/pro_setup.rb +51 -19
  15. data/lib/generators/react_on_rails/rsc_generator.rb +18 -1
  16. data/lib/generators/react_on_rails/rsc_setup/client_references.rb +63 -25
  17. data/lib/generators/react_on_rails/rsc_setup.rb +141 -39
  18. data/lib/generators/react_on_rails/templates/agent_files/AGENTS.md +31 -3
  19. data/lib/generators/react_on_rails/templates/base/base/{Procfile.dev-static-assets → Procfile.dev-static-assets.tt} +1 -1
  20. data/lib/generators/react_on_rails/templates/base/base/{Procfile.dev → Procfile.dev.tt} +1 -1
  21. data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +18 -42
  22. data/lib/react_on_rails/agent_guardrails/templates/rsc_app_safety_check.rb +215 -0
  23. data/lib/react_on_rails/agent_guardrails/templates/rsc_app_safety_skill.md +71 -0
  24. data/lib/react_on_rails/agent_guardrails.rb +223 -0
  25. data/lib/react_on_rails/dev/service_checker.rb +1 -1
  26. data/lib/react_on_rails/doctor.rb +880 -48
  27. data/lib/react_on_rails/doctor_schema.rb +192 -0
  28. data/lib/react_on_rails/engine.rb +2 -2
  29. data/lib/react_on_rails/helper.rb +17 -10
  30. data/lib/react_on_rails/length_prefixed_parser.rb +22 -14
  31. data/lib/react_on_rails/lenient_json.rb +0 -0
  32. data/lib/react_on_rails/prerender_error.rb +38 -8
  33. data/lib/react_on_rails/react_component/render_options.rb +1 -1
  34. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +168 -15
  35. data/lib/react_on_rails/system_checker.rb +2 -1
  36. data/lib/react_on_rails/version.rb +1 -1
  37. data/lib/tasks/agent_guardrails.rake +21 -0
  38. data/rakelib/run_rspec.rake +14 -0
  39. data/sig/react_on_rails/prerender_error.rbs +2 -1
  40. data/skills/doctor-fix-loop/SKILL.md +26 -0
  41. data/skills/install-and-upgrade/SKILL.md +24 -0
  42. data/skills/rsc-adoption/SKILL.md +28 -0
  43. data/skills/streaming-debug/SKILL.md +53 -0
  44. metadata +18 -4
  45. data/lib/generators/react_on_rails/templates/base/base/bin/shakapacker-watch +0 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0a69e6dd7950d3edc83c8ce77b7ad56419f243b3355878140e8fad6e1f56d54
4
- data.tar.gz: 2262184ed159c5e4efa4402e863d695c86cded69ff395dea8c7096b9fca73701
3
+ metadata.gz: 7026d13c6ff6a7d80dcb8c566a11e8446036d052ec2418e47f2bcdaec6a2eed3
4
+ data.tar.gz: 0a1354cabb04d73d50281387151ab91c440b06955d038dd0c564cc08cc20e51e
5
5
  SHA512:
6
- metadata.gz: abfc807dddaed6cc958329c40bece87518247237aea46f1f8fbbe7f5c7bfc7738658f80a2656de0755788cfaa861b1369ccda45c0de44fef225e37686cb6040a
7
- data.tar.gz: 630f17042cc9b1df2ce8cdaebe33883eeee4baa21ab041de75590984a5710751c0e5d7c53eedea1580823efbe62850d23c2e79d58f8baa1263d1c2aa9f1b4e3b
6
+ metadata.gz: a40e5cc18caeef6e4879a46314aa86ea6c5b48128fbf60b2e4793b1d32748b334767b4f432c8ef6e1779fa21a07d53edf00253235ced9d641b5e3b43f74db4b8
7
+ data.tar.gz: e3af833f783b8096f457d1ecbd4e268a7e07b61f8b39f00f48de30c0c976ad5f75f3285bf534afc71d179c73af75b55c6d640a0bf82b0ff656cadfd08ab24775
@@ -2,7 +2,7 @@
2
2
 
3
3
  eval_gemfile File.expand_path("../Gemfile.shared_dev_dependencies", __dir__)
4
4
 
5
- gem "shakapacker", "10.3.0"
5
+ gem "shakapacker", "10.3.2"
6
6
  gem "bootsnap", require: false
7
7
  gem "rails", "~> 7.1.0"
8
8
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- react_on_rails (17.0.1)
4
+ react_on_rails (17.1.0.rc.1)
5
5
  addressable
6
6
  connection_pool
7
7
  execjs (~> 2.5)
@@ -117,7 +117,7 @@ GEM
117
117
  cgi (0.5.2)
118
118
  childprocess (5.0.0)
119
119
  coderay (1.1.3)
120
- concurrent-ruby (1.3.7)
120
+ concurrent-ruby (1.3.8)
121
121
  connection_pool (3.0.2)
122
122
  crass (1.0.7)
123
123
  csv (3.3.5)
@@ -132,7 +132,7 @@ GEM
132
132
  drb (2.2.3)
133
133
  equivalent-xml (0.6.0)
134
134
  nokogiri (>= 1.4.3)
135
- erb (6.0.4)
135
+ erb (6.0.7)
136
136
  erubi (1.13.1)
137
137
  execjs (2.9.1)
138
138
  ffi (1.16.3)
@@ -146,7 +146,7 @@ GEM
146
146
  i18n (1.15.2)
147
147
  concurrent-ruby (~> 1.0)
148
148
  interception (0.5)
149
- io-console (0.8.2)
149
+ io-console (0.9.2)
150
150
  irb (1.18.0)
151
151
  pp (>= 0.6.0)
152
152
  prism (>= 1.3.0)
@@ -169,7 +169,7 @@ GEM
169
169
  rb-fsevent (~> 0.10, >= 0.10.3)
170
170
  rb-inotify (~> 0.9, >= 0.9.10)
171
171
  logger (1.7.0)
172
- loofah (2.25.1)
172
+ loofah (2.25.2)
173
173
  crass (~> 1.0.2)
174
174
  nokogiri (>= 1.12.0)
175
175
  mail (2.9.0)
@@ -228,16 +228,16 @@ GEM
228
228
  pry-rescue (1.6.0)
229
229
  interception (>= 0.5)
230
230
  pry (>= 0.12.0)
231
- psych (5.4.0)
231
+ psych (5.5.0)
232
232
  date
233
233
  stringio
234
234
  public_suffix (6.0.2)
235
235
  puma (6.6.1)
236
236
  nio4r (~> 2.0)
237
237
  racc (1.8.1)
238
- rack (3.2.6)
239
- rack-proxy (0.8.3)
240
- rack
238
+ rack (3.2.7)
239
+ rack-proxy (1.0.1)
240
+ rack (>= 2.0, < 4)
241
241
  rack-session (2.1.2)
242
242
  base64 (>= 0.1.0)
243
243
  rack (>= 3.0.0)
@@ -263,8 +263,8 @@ GEM
263
263
  activesupport (>= 5.0.0)
264
264
  minitest
265
265
  nokogiri (>= 1.6)
266
- rails-html-sanitizer (1.7.0)
267
- loofah (~> 2.25)
266
+ rails-html-sanitizer (1.7.1)
267
+ loofah (~> 2.25, >= 2.25.2)
268
268
  nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
269
269
  railties (7.1.6)
270
270
  actionpack (= 7.1.6)
@@ -288,7 +288,7 @@ GEM
288
288
  psych (>= 4.0.0)
289
289
  tsort
290
290
  regexp_parser (2.11.3)
291
- reline (0.6.3)
291
+ reline (0.7.0)
292
292
  io-console (~> 0.5)
293
293
  rexml (3.4.4)
294
294
  rspec-core (3.13.0)
@@ -331,7 +331,7 @@ GEM
331
331
  rubyzip (>= 1.2.2, < 3.0)
332
332
  websocket (~> 1.0)
333
333
  semantic_range (3.1.1)
334
- shakapacker (10.3.0)
334
+ shakapacker (10.3.2)
335
335
  activesupport (>= 5.2)
336
336
  package_json
337
337
  rack-proxy (>= 0.6.1)
@@ -402,7 +402,7 @@ GEM
402
402
  xpath (3.2.0)
403
403
  nokogiri (~> 1.8)
404
404
  yard (0.9.36)
405
- zeitwerk (2.8.2)
405
+ zeitwerk (2.8.3)
406
406
 
407
407
  PLATFORMS
408
408
  arm64-darwin
@@ -443,7 +443,7 @@ DEPENDENCIES
443
443
  sass-rails (~> 6.0)
444
444
  sdoc
445
445
  selenium-webdriver (= 4.9.0)
446
- shakapacker (= 10.3.0)
446
+ shakapacker (= 10.3.2)
447
447
  simplecov (~> 0.16.1)
448
448
  spring (~> 4.0)
449
449
  sprockets (~> 4.0)
@@ -0,0 +1,26 @@
1
+ # React on Rails bundled agent reference
2
+
3
+ These guides and skills ship with the installed React on Rails version. Read them before relying on
4
+ training data or hosted documentation, which may describe a different release.
5
+
6
+ | Workflow | Skill | Guide |
7
+ | ----------------------------------- | ------------------------------------------------------------------ | --------------------------------- |
8
+ | Install or upgrade | [`install-and-upgrade`](../../skills/install-and-upgrade/SKILL.md) | [Guide](./install-and-upgrade.md) |
9
+ | Adopt React Server Components (Pro) | [`rsc-adoption`](../../skills/rsc-adoption/SKILL.md) | [Guide](./rsc-adoption.md) |
10
+ | Debug streaming SSR (Pro) | [`streaming-debug`](../../skills/streaming-debug/SKILL.md) | [Guide](./streaming-debug.md) |
11
+ | Iterate with the doctor | [`doctor-fix-loop`](../../skills/doctor-fix-loop/SKILL.md) | [Guide](./doctor-fix-loop.md) |
12
+
13
+ The gem and npm package contain byte-identical copies. Use the installed gem directory as the
14
+ canonical, reliable lookup:
15
+
16
+ ```bash
17
+ bundle show react_on_rails
18
+ ```
19
+
20
+ Read `docs/agent/README.md` and the `skills/` paths from the returned directory. An optional
21
+ direct-dependency path is `node_modules/react-on-rails/`, but use it only when that directory
22
+ exists. Do not assume it exists: Pro installations may omit the direct base npm dependency, and
23
+ pnpm may isolate a transitive copy.
24
+
25
+ For broader explanation after reading the installed references, use the hosted documentation:
26
+ https://reactonrails.com/docs/.
@@ -0,0 +1,25 @@
1
+ # Doctor-driven fix loop
2
+
3
+ Use the stable JSON form for agent and CI workflows:
4
+
5
+ ```bash
6
+ bin/rails react_on_rails:doctor FORMAT=json
7
+ ```
8
+
9
+ Standard output is one JSON document. The top-level `status`, `checks`, and `summary` describe the
10
+ run. Every check exposes a stable `id`, `status`, `severity`, `message`, `fix_command`, `docs_url`,
11
+ `remediation`, and `details` contract.
12
+
13
+ For every non-passing check, in array order:
14
+
15
+ 1. Record `id` and `severity`.
16
+ 2. Inspect `message`, `remediation.files`, and the current app state.
17
+ 3. Use `remediation.prompt` and `remediation.expected_end_state` as bounded guidance.
18
+ 4. Review the smallest corrective diff.
19
+ 5. Rerun the JSON doctor and confirm the check passes without creating another failure.
20
+
21
+ Exit code `1` means at least one error remains. Warnings keep exit code `0`, so read `status` or
22
+ `summary.warn` when warning-free output matters. A `null` `fix_command` is expected; never infer an
23
+ unsafe global repair command from the check ID.
24
+
25
+ Secondary reference: https://reactonrails.com/docs/api-reference/doctor.
@@ -0,0 +1,164 @@
1
+ # Install and upgrade
2
+
3
+ Use this guide for an existing Rails app. Keep app-specific choices and custom configuration intact.
4
+
5
+ ## Preflight
6
+
7
+ - Record the Rails, Ruby, Node, Shakapacker, React on Rails gem, npm package, and package-manager state.
8
+ - Identify both Ruby and JavaScript lockfiles and start from a reviewable working tree.
9
+ - Keep the gem and npm package on the same React on Rails release. A Pro app must also update its Pro
10
+ gem and JavaScript packages together.
11
+
12
+ ## Install
13
+
14
+ Add React on Rails first so Bundler resolves a compatible Shakapacker version, then pin that resolved version when
15
+ promoting Shakapacker to a direct dependency.
16
+ Choose exactly one stack flag before running the install generator.
17
+ Use `--standard-only` for OSS, `--pro` for Pro, or `--rsc` for Pro with RSC.
18
+ Do not rely on an interactive TTY prompt; replace `<STACK_FLAG>` explicitly in every command.
19
+ Choose the language explicitly too: replace `<LANGUAGE_CHOICE>` with `--typescript` for TypeScript,
20
+ or remove that placeholder for JavaScript. TypeScript is optional; omitting its flag preserves JavaScript.
21
+
22
+ ```bash
23
+ bundle add react_on_rails --strict
24
+ SHAKAPACKER_VERSION="$(bundle exec ruby -rreact_on_rails -e 'print ReactOnRails::PackerUtils.shakapacker_version')"
25
+ bundle add shakapacker --version="${SHAKAPACKER_VERSION}" --strict
26
+ ```
27
+
28
+ For `--pro` or `--rsc`, React on Rails Pro is free for evaluation and non-production use;
29
+ production use requires a subscription. Review [Pro licensing and setup](https://reactonrails.com/docs/pro/upgrading-to-pro/)
30
+ before proceeding.
31
+
32
+ Skip this Pro-gem preparation for `--standard-only`.
33
+ For `--pro` or `--rsc` only, derive the exact installed base-gem version before adding the Pro gem:
34
+
35
+ ```bash
36
+ ROR_GEM_VERSION="$(bundle exec ruby -rreact_on_rails/version -e 'print ReactOnRails::VERSION')"
37
+ bundle add react_on_rails_pro --version="${ROR_GEM_VERSION}" --strict
38
+ ```
39
+
40
+ If that exact version is an unpublished prerelease, require a matching local/path `react_on_rails_pro` gem
41
+ and use the same exact version instead of the registry command:
42
+
43
+ ```bash
44
+ bundle add react_on_rails_pro --path="<path-to-matching-react_on_rails_pro>" --version="${ROR_GEM_VERSION}" --strict
45
+ ```
46
+
47
+ Never fall back silently to a stable Pro gem.
48
+ For `--pro` or `--rsc` only, after either Pro source command succeeds, remove the direct base-gem declaration:
49
+
50
+ ```bash
51
+ bundle remove react_on_rails
52
+ ```
53
+
54
+ This cleanup removes only the direct `react_on_rails` declaration; `react_on_rails_pro` retains the matching base gem
55
+ transitively. Do not run this cleanup for `--standard-only`.
56
+
57
+ After the conditional Pro preparation, run the generator with the explicit stack flag:
58
+
59
+ ```bash
60
+ bundle exec rails generate react_on_rails:install <LANGUAGE_CHOICE> <STACK_FLAG>
61
+ ```
62
+
63
+ Use the app's declared JavaScript package manager if the generator prints a manual install command.
64
+ Review the generated initializer, Shakapacker configuration, scripts, routes, and sample files.
65
+
66
+ ## Upgrade
67
+
68
+ 1. Record the installed Ruby gem version as `CURRENT_VERSION`:
69
+
70
+ ```bash
71
+ CURRENT_VERSION="$(bundle exec ruby -rreact_on_rails/version -e 'puts ReactOnRails::VERSION')"
72
+ printf '%s\n' "$CURRENT_VERSION"
73
+ ```
74
+
75
+ 2. Choose and verify explicit Ruby and npm target versions before editing dependency pins. Record
76
+ the Ruby/tag form as `GEM_TARGET_VERSION` and the npm semver form as `NPM_TARGET_VERSION`.
77
+ Ruby prereleases use dot notation (for example, `17.0.0.rc.6`); npm prereleases use hyphen notation
78
+ (for example, `17.0.0-rc.6`). Choose both explicitly rather than deriving either from
79
+ `CURRENT_VERSION` or from the other target.
80
+
81
+ ```bash
82
+ GEM_TARGET_VERSION="<Ruby/tag version you selected>"
83
+ NPM_TARGET_VERSION="<npm semver version you selected>"
84
+ git ls-remote --exit-code --tags https://github.com/shakacode/react_on_rails.git \
85
+ "refs/tags/v${GEM_TARGET_VERSION}"
86
+ ```
87
+
88
+ 3. Read the changelog and upgrade guidance from the immutable repository tag `v<GEM_TARGET_VERSION>`:
89
+ `https://github.com/shakacode/react_on_rails/tree/v<GEM_TARGET_VERSION>`. Compare the complete
90
+ `CURRENT_VERSION..GEM_TARGET_VERSION` release range before changing dependencies:
91
+ `https://github.com/shakacode/react_on_rails/compare/v<CURRENT_VERSION>...v<GEM_TARGET_VERSION>`.
92
+
93
+ ## JavaScript target matrix
94
+
95
+ Use exactly the row matching the detected stack. Verify every relevant package version before
96
+ pinning it; checking only the base package is insufficient. Use the app's declared package manager's
97
+ registry-inspection command for every exact package spec below. Do not assume pnpm, npm, Yarn, or Bun
98
+ is available merely because another package manager is installed.
99
+
100
+ - **OSS (`--standard-only`)**: pin and verify `react-on-rails@${NPM_TARGET_VERSION}`.
101
+
102
+ - **Pro (all renderers)**: pin and verify `react-on-rails-pro@${NPM_TARGET_VERSION}`. Also pin and verify
103
+ `react-on-rails-pro-node-renderer@${NPM_TARGET_VERSION}` only when the app uses the standalone NodeRenderer.
104
+ Do not add a direct `react-on-rails` dependency to Pro or RSC apps.
105
+
106
+ - **RSC (`--rsc`)**: follow the Pro rule, including its conditional standalone NodeRenderer package
107
+ and prohibition on a direct base dependency. Select `RSC_TARGET_VERSION` independently from the
108
+ target release guidance or the target tag's
109
+ `ReactOnRails::Generators::JsDependencyManager::RSC_PACKAGE_VERSION_PIN`:
110
+ `https://github.com/shakacode/react_on_rails/blob/v<GEM_TARGET_VERSION>/react_on_rails/lib/generators/react_on_rails/js_dependency_manager.rb`.
111
+ Never derive `RSC_TARGET_VERSION` from `NPM_TARGET_VERSION`. Pin and verify the exact
112
+ `react-on-rails-rsc@${RSC_TARGET_VERSION}` release.
113
+
114
+ ```bash
115
+ RSC_TARGET_VERSION="<exact RSC pin from target guidance>"
116
+ ```
117
+
118
+ 4. Pin Ruby gems with `GEM_TARGET_VERSION` and regenerate the Bundler lockfile.
119
+ Apply exactly the matching JavaScript matrix row with the app's declared package manager, pin each
120
+ package to the verified exact version, and regenerate the JavaScript lockfile.
121
+ 5. Detect the app's existing stack and current generator choices from its dependencies and
122
+ configuration. Use the one preserving mapping that matches the existing stack:
123
+ - Use `--standard-only` for an existing OSS stack.
124
+ - Use `--pro` only for an existing Pro + NodeRenderer stack.
125
+ - Use `--rsc` for an existing RSC stack.
126
+
127
+ Pro + ExecJS has no preserving install-generator flag.
128
+ For that stack, skip both generator preview and apply steps; upgrade dependencies and configuration manually.
129
+ Preserve the ExecJS renderer setup. For the three preserving mappings, preserve the current stack.
130
+ Preserve every other current generator choice, such as TypeScript, Redux, or generated
131
+ test-framework choices.
132
+
133
+ 6. For a stack with a preserving mapping, first rerun the generator as a preview, substituting the
134
+ selected stack flag and the app's other current choices:
135
+
136
+ ```bash
137
+ bundle exec rails generate react_on_rails:install --pretend <STACK_FLAG> <OTHER_CURRENT_CHOICES>
138
+ ```
139
+
140
+ `--pretend` omits dependency installation and script effects; it is not a complete mutation audit.
141
+ Review the complete preview without overwriting app-owned configuration. Never prescribe or run a
142
+ bare, non-TTY generator rerun.
143
+
144
+ 7. Only for a stack with a preserving mapping, and only after reviewing and accepting the preview,
145
+ apply the same choices without `--pretend` in a clean branch or worktree:
146
+
147
+ ```bash
148
+ bundle exec rails generate react_on_rails:install <STACK_FLAG> <OTHER_CURRENT_CHOICES>
149
+ ```
150
+
151
+ Before accepting any generated change, audit `package.json` and the JavaScript lockfile against
152
+ their pre-run state. The apply step installs the generator's current dependency defaults even
153
+ though `--pretend` skipped them; preserve intentional app pins and reject unintended upgrades.
154
+
155
+ 8. Run the doctor loop, compile assets, and run focused application tests.
156
+
157
+ ```bash
158
+ bin/rails react_on_rails:doctor FORMAT=json
159
+ bundle exec rails shakapacker:compile
160
+ ```
161
+
162
+ Secondary references:
163
+ https://reactonrails.com/docs/getting-started/existing-rails-app and
164
+ https://reactonrails.com/docs/upgrading/upgrading-react-on-rails.
@@ -0,0 +1,31 @@
1
+ # React Server Components adoption (Pro)
2
+
3
+ React Server Components require React on Rails Pro. Use the generator and installed package contracts;
4
+ do not reconstruct the RSC build or renderer protocol from memory.
5
+
6
+ ## Adoption sequence
7
+
8
+ 1. Confirm the Pro gem/npm packages, Node renderer, React, React DOM, and RSC package are compatible.
9
+ 2. Preserve the app's language when running the generator: use
10
+ `bundle exec rails generate react_on_rails:rsc --typescript` for a TypeScript app and
11
+ `bundle exec rails generate react_on_rails:rsc` for a JavaScript app. Review the generated client,
12
+ server, and RSC bundle configuration.
13
+ 3. Move one leaf at a time. The `'use client'` directive marks the server-to-client boundary, not
14
+ every module that will execute on the client. Modules imported below that boundary remain client code
15
+ even when they lack the directive; place it only where a subtree needs browser APIs, state, effects,
16
+ or event handlers.
17
+ 4. Keep `.client.` and `.server.` suffixes conceptually separate: they select bundle placement and do
18
+ not classify React Server Components.
19
+ 5. Keep Rails-owned data and security decisions in Rails. Supply data through props or async props;
20
+ server components do not gain in-process access to Rails models, sessions, or cookies.
21
+ 6. Install the app safety guardrails and review the generated skill and advisory hook:
22
+
23
+ ```bash
24
+ bundle exec rake react_on_rails:install_rsc_agent_guardrails
25
+ bin/rails react_on_rails:doctor FORMAT=json
26
+ ```
27
+
28
+ Before completion, protect any RSC payload route, keep the Node renderer private, avoid sensitive
29
+ logged props or URLs, build all three bundles, and exercise navigation and hydration in a browser.
30
+
31
+ Secondary reference: https://reactonrails.com/docs/pro/react-server-components.
@@ -0,0 +1,57 @@
1
+ # Streaming SSR debugging (Pro)
2
+
3
+ Streaming requires React on Rails Pro and the Node renderer. First determine whether the selected
4
+ helper is progressive or intentionally buffered.
5
+
6
+ ## Debug in boundary order
7
+
8
+ 1. Run `bin/rails react_on_rails:doctor FORMAT=json` and resolve configuration or dependency errors.
9
+ 2. Identify the exact helper before applying streaming prerequisites.
10
+
11
+ ## Progressive helpers
12
+
13
+ For `stream_react_component`, `cached_stream_react_component`, and
14
+ `stream_react_component_with_async_props`:
15
+
16
+ 1. Confirm the controller includes `ReactOnRailsPro::Stream`, the action enters the view through
17
+ `stream_view_containing_react_components` instead of ordinary `render`, and the Node renderer
18
+ is reachable.
19
+ 2. When Suspense content should reveal progressively, confirm the boundary's child actually suspends.
20
+ 3. For `stream_react_component_with_async_props` only, confirm
21
+ `ReactOnRailsPro.configuration.enable_rsc_support` is enabled by setting
22
+ `config.enable_rsc_support = true` in the Pro initializer.
23
+ This is not a prerequisite for `stream_react_component` or `cached_stream_react_component`.
24
+ 4. For async props, start slow work inside the streaming block, emit only JSON-serializable values,
25
+ and emit or reject every prop the renderer requests.
26
+
27
+ ## Buffered helpers
28
+
29
+ For `buffered_stream_react_component`, `cached_buffered_stream_react_component`, and
30
+ `cached_static_rsc_component`:
31
+
32
+ 1. Confirm the Node renderer is reachable and inspect the complete buffered result.
33
+ 2. These helpers do not require the streaming controller wrapper: they do not require
34
+ `ReactOnRailsPro::Stream`, `stream_view_containing_react_components`, or a suspending boundary.
35
+ 3. For `cached_static_rsc_component`, set `config.enable_rsc_support = true`; disabling RSC support
36
+ omits the RSC payload generation that gives this helper its static-RSC behavior.
37
+ This setting is not a prerequisite for `buffered_stream_react_component` or
38
+ `cached_buffered_stream_react_component`.
39
+ 4. Expect the browser to receive the page only after the renderer has produced the complete result;
40
+ early shell flush and progressive Suspense reveal are not buffered-helper behavior.
41
+
42
+ ## Debug either path
43
+
44
+ Probe the origin with buffering disabled in the client, then compare the same route through each
45
+ reverse proxy or CDN. Inspect response headers, chunk arrival, compression, Rails logs, Node
46
+ renderer logs, and browser timing marks.
47
+
48
+ A useful transport probe is:
49
+
50
+ ```bash
51
+ curl --no-buffer --dump-header - https://your-app.example/streaming-route
52
+ ```
53
+
54
+ If the origin streams but the public route buffers, fix the proxy/CDN boundary. If neither streams,
55
+ reduce to one Suspense boundary and one known-slow value before changing application architecture.
56
+
57
+ Secondary reference: https://reactonrails.com/docs/pro/streaming-ssr.
@@ -251,9 +251,7 @@ module ReactOnRails
251
251
  ensure_new_app_root_route_initialized
252
252
 
253
253
  base_path = "base/base/"
254
- base_files = %w[Procfile.dev
255
- Procfile.dev-static-assets
256
- Procfile.dev-prod-assets
254
+ base_files = %w[Procfile.dev-prod-assets
257
255
  .dev-services.yml.example
258
256
  .env.example
259
257
  bin/shakapacker-precompile-hook]
@@ -262,7 +260,9 @@ module ReactOnRails
262
260
  # Exception: Redux still needs the HelloWorld controller even with RSC
263
261
  base_files << "app/controllers/hello_world_controller.rb" unless use_rsc? && !options.redux?
264
262
  base_files << "app/controllers/home_controller.rb" if generate_new_app_home_page?
265
- base_templates = %w[config/initializers/react_on_rails.rb]
263
+ base_templates = %w[Procfile.dev
264
+ Procfile.dev-static-assets
265
+ config/initializers/react_on_rails.rb]
266
266
  base_files.each { |file| copy_file("#{base_path}#{file}", file) }
267
267
  copy_react_on_rails_default_layout(base_path)
268
268
  warn_existing_hello_world_tailwind_layout
@@ -85,7 +85,7 @@ module GeneratorHelper
85
85
  end
86
86
 
87
87
  def add_documentation_reference(message, source)
88
- "#{message} \n#{source}"
88
+ "#{message}\n#{source}"
89
89
  end
90
90
 
91
91
  def print_generator_messages
@@ -492,6 +492,17 @@ module GeneratorHelper
492
492
  nil
493
493
  end
494
494
 
495
+ # Prefer Shakapacker's optional watcher binstub when the application has an executable copy. Older
496
+ # supported Shakapacker installations can still run watch mode through the required
497
+ # bin/shakapacker binstub, so React on Rails does not need to vendor a fallback watcher.
498
+ def shakapacker_watch_command
499
+ watch_binstub = File.join(destination_root, "bin/shakapacker-watch")
500
+ watch_binstub_available = File.file?(watch_binstub) && File.executable?(watch_binstub)
501
+ executable = watch_binstub_available ? "bin/shakapacker-watch" : "bin/shakapacker"
502
+
503
+ "#{executable} --watch"
504
+ end
505
+
495
506
  # Check if Shakapacker 9.0 or higher is available
496
507
  # Returns true if Shakapacker >= 9.0, false otherwise
497
508
  #
@@ -86,16 +86,22 @@ module ReactOnRails
86
86
  desc: "Write AI-agent guidance files (AGENTS.md + editor pointers). Default: true"
87
87
 
88
88
  # --pro
89
+ # No static default: prompt suppression needs to distinguish an omitted flag from --no-pro.
89
90
  class_option :pro,
90
91
  type: :boolean,
91
- default: false,
92
- desc: "Install React on Rails Pro with Node Renderer. Default: false"
92
+ desc: "Install React on Rails Pro with Node Renderer"
93
93
 
94
94
  # --rsc
95
+ # No static default: prompt suppression needs to distinguish an omitted flag from --no-rsc.
95
96
  class_option :rsc,
97
+ type: :boolean,
98
+ desc: "Install React Server Components support (includes Pro)"
99
+
100
+ # --standard-only
101
+ class_option :standard_only,
96
102
  type: :boolean,
97
103
  default: false,
98
- desc: "Install React Server Components support (includes Pro). Default: false"
104
+ desc: "Install only the open-source package; cannot be combined with --pro or --rsc"
99
105
 
100
106
  # Hidden option: allows tests (and advanced users) to signal that Shakapacker
101
107
  # was just installed, triggering force-overwrite of shakapacker.yml with RoR's template.
@@ -196,6 +202,7 @@ module ReactOnRails
196
202
  # This is inherited by all invoked generators and persists through Rails initialization
197
203
  # See lib/react_on_rails/engine.rb for the validation skip logic
198
204
  ENV["REACT_ON_RAILS_SKIP_VALIDATION"] = "true"
205
+ prompt_for_pro_features_if_applicable
199
206
 
200
207
  if installation_prerequisites_met? || options.ignore_warnings?
201
208
  invoke_generators
@@ -230,6 +237,40 @@ module ReactOnRails
230
237
 
231
238
  private
232
239
 
240
+ def use_pro?
241
+ return @interactive_pro_selection if defined?(@interactive_pro_selection)
242
+
243
+ !!super
244
+ end
245
+
246
+ def prompt_for_pro_features_if_applicable
247
+ validate_product_stack_choice!
248
+ return if options.new_app? || explicit_product_stack_choice? || !interactive_install_session?
249
+
250
+ say "React on Rails Pro is free for evaluation; production use requires a subscription."
251
+ say "Learn more: https://reactonrails.com/docs/pro/upgrading-to-pro/"
252
+ answer = ask(
253
+ "Enable React on Rails Pro features (Node Renderer and streaming SSR; RSC available separately)? [Y/n]",
254
+ :cyan
255
+ )
256
+ normalized_answer = answer.to_s.strip
257
+ @interactive_pro_selection = normalized_answer.empty? || normalized_answer.match?(/\A(?:y|yes)\z/i)
258
+ end
259
+
260
+ def explicit_product_stack_choice?
261
+ options.key?(:pro) || options.key?(:rsc) || options.standard_only?
262
+ end
263
+
264
+ def interactive_install_session?
265
+ !ReactOnRails::GitUtils.truthy_env?(ENV.fetch("CI", nil)) && $stdin.tty? && $stdout.tty?
266
+ end
267
+
268
+ def validate_product_stack_choice!
269
+ return unless options.standard_only? && (options.pro? || options.rsc?)
270
+
271
+ raise Thor::Error, "--standard-only cannot be combined with --pro or --rsc"
272
+ end
273
+
233
274
  # Fresh-install context: default to Rspack (when Shakapacker supports it) unless the
234
275
  # app already declares a bundler. See GeneratorHelper#fresh_install_rspack_default.
235
276
  # NOTE: BaseGenerator#rspack_bundler_default is an intentional twin of this override
@@ -866,8 +907,12 @@ module ReactOnRails
866
907
  end
867
908
 
868
909
  def product_stack_install_flag
869
- return "--rsc" if options.rsc?
870
- return "--pro" if options.pro?
910
+ return "--rsc" if use_rsc?
911
+ return "--pro" if use_pro?
912
+ return "--standard-only" if options.standard_only?
913
+ return "--no-rsc" if options.key?(:rsc)
914
+ return "--no-pro" if options.key?(:pro)
915
+ return "--standard-only" if defined?(@interactive_pro_selection)
871
916
 
872
917
  nil
873
918
  end
@@ -988,7 +1033,13 @@ module ReactOnRails
988
1033
  say "📝 Adding Shakapacker to Gemfile...", :yellow
989
1034
  # Use with_unbundled_env to prevent inheriting BUNDLE_GEMFILE from parent process
990
1035
  # See: https://github.com/shakacode/react_on_rails/issues/2287
991
- success = Bundler.with_unbundled_env { system("bundle add shakapacker --strict") }
1036
+ # Pin the version already resolved through react_on_rails. Without an explicit
1037
+ # version, `bundle add --strict` can prefer an older globally installed gem and
1038
+ # downgrade the target app's lockfile.
1039
+ shakapacker_version = ReactOnRails::PackerUtils.shakapacker_version
1040
+ success = Bundler.with_unbundled_env do
1041
+ system("bundle", "add", "shakapacker", "--version", shakapacker_version, "--strict")
1042
+ end
992
1043
  return true if success
993
1044
 
994
1045
  handle_shakapacker_gemfile_error
@@ -1118,6 +1169,7 @@ module ReactOnRails
1118
1169
  end
1119
1170
 
1120
1171
  def handle_shakapacker_gemfile_error
1172
+ shakapacker_version = ReactOnRails::PackerUtils.shakapacker_version
1121
1173
  error = <<~MSG.strip
1122
1174
  🚫 Failed to add Shakapacker to your Gemfile.
1123
1175
 
@@ -1127,7 +1179,7 @@ module ReactOnRails
1127
1179
  • Gemfile permissions
1128
1180
 
1129
1181
  Please try manually:
1130
- bundle add shakapacker --strict
1182
+ bundle add shakapacker --version #{shakapacker_version} --strict
1131
1183
 
1132
1184
  #{recovery_working_tree_note}
1133
1185
  Then re-run: #{recovery_install_command}
@@ -177,7 +177,7 @@ module ReactOnRails
177
177
  end
178
178
 
179
179
  def add_js_dependencies
180
- using_pro = respond_to?(:use_pro?) && use_pro?
180
+ using_pro = respond_to?(:use_pro?, true) && use_pro?
181
181
  using_rsc = respond_to?(:use_rsc?) && use_rsc?
182
182
  # Pro package includes react-on-rails, so skip base package when using Pro
183
183
  add_react_on_rails_package unless using_pro
@@ -40,9 +40,11 @@ module ReactOnRails
40
40
  )
41
41
 
42
42
  setup_pro
43
- add_pro_npm_dependencies
44
- update_imports_to_pro_package unless options[:invoked_by_install]
45
- print_success_message unless options[:invoked_by_install]
43
+ unless options[:invoked_by_install]
44
+ add_pro_npm_dependencies
45
+ update_imports_to_pro_package
46
+ print_success_message
47
+ end
46
48
  else
47
49
  GeneratorMessages.add_error(<<~MSG.strip)
48
50
  🚫 React on Rails Pro generator prerequisites not met!