react_on_rails 16.6.0 → 16.7.0.rc.0

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/Gemfile.development_dependencies +2 -2
  4. data/Gemfile.lock +2 -14
  5. data/Rakefile +0 -6
  6. data/Steepfile +4 -0
  7. data/lib/generators/react_on_rails/base_generator.rb +4 -4
  8. data/lib/generators/react_on_rails/demo_page_config.rb +3 -3
  9. data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -1
  10. data/lib/generators/react_on_rails/generator_helper.rb +6 -65
  11. data/lib/generators/react_on_rails/generator_messages/ci_section.rb +42 -0
  12. data/lib/generators/react_on_rails/generator_messages/package_manager_detection.rb +194 -0
  13. data/lib/generators/react_on_rails/generator_messages/shakapacker_status_section.rb +61 -0
  14. data/lib/generators/react_on_rails/generator_messages.rb +22 -79
  15. data/lib/generators/react_on_rails/install_generator.rb +243 -28
  16. data/lib/generators/react_on_rails/js_dependency_manager.rb +7 -4
  17. data/lib/generators/react_on_rails/pro/USAGE +1 -1
  18. data/lib/generators/react_on_rails/pro_generator.rb +206 -183
  19. data/lib/generators/react_on_rails/pro_setup.rb +102 -26
  20. data/lib/generators/react_on_rails/react_with_redux_generator.rb +3 -2
  21. data/lib/generators/react_on_rails/templates/base/base/.env.example +25 -0
  22. data/lib/generators/react_on_rails/templates/base/base/.github/workflows/ci.yml.tt +86 -0
  23. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +4 -3
  24. data/lib/generators/react_on_rails/templates/base/base/babel.config.js.tt +1 -1
  25. data/lib/generators/react_on_rails/templates/base/base/bin/switch-bundler +2 -2
  26. data/lib/generators/react_on_rails/templates/base/base/config/webpack/ServerClientOrBoth.js.tt +1 -1
  27. data/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js.tt +1 -1
  28. data/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt +2 -2
  29. data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +1 -1
  30. data/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt +1 -1
  31. data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +6 -5
  32. data/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt +1 -1
  33. data/lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt +1 -1
  34. data/lib/generators/react_on_rails/templates/pro/base/{client → renderer}/node-renderer.js +1 -0
  35. data/lib/react_on_rails/config_path_resolver.rb +101 -4
  36. data/lib/react_on_rails/configuration.rb +22 -0
  37. data/lib/react_on_rails/dev/file_manager.rb +135 -8
  38. data/lib/react_on_rails/dev/port_selector.rb +259 -7
  39. data/lib/react_on_rails/dev/process_manager.rb +29 -2
  40. data/lib/react_on_rails/dev/server_manager.rb +607 -39
  41. data/lib/react_on_rails/doctor.rb +513 -45
  42. data/lib/react_on_rails/helper.rb +3 -11
  43. data/lib/react_on_rails/js_code_builder.rb +66 -0
  44. data/lib/react_on_rails/length_prefixed_parser.rb +142 -0
  45. data/lib/react_on_rails/packs_generator.rb +65 -12
  46. data/lib/react_on_rails/pro_migration.rb +175 -0
  47. data/lib/react_on_rails/render_request.rb +74 -0
  48. data/lib/react_on_rails/rendering_strategy/exec_js_strategy.rb +29 -0
  49. data/lib/react_on_rails/rendering_strategy.rb +44 -0
  50. data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +33 -22
  51. data/lib/react_on_rails/system_checker.rb +44 -23
  52. data/lib/react_on_rails/utils.rb +5 -0
  53. data/lib/react_on_rails/version.rb +1 -1
  54. data/lib/react_on_rails.rb +3 -0
  55. data/rakelib/run_rspec.rake +0 -5
  56. data/rakelib/shakapacker_examples.rake +66 -23
  57. data/react_on_rails.gemspec +18 -8
  58. data/sig/react_on_rails/js_code_builder.rbs +11 -0
  59. data/sig/react_on_rails/render_request.rbs +28 -0
  60. data/sig/react_on_rails/rendering_strategy/exec_js_strategy.rbs +11 -0
  61. data/sig/react_on_rails/rendering_strategy.rbs +7 -0
  62. data/sig/react_on_rails.rbs +6 -0
  63. metadata +31 -10
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "open-uri"
4
4
  require "execjs"
5
+ require "react_on_rails/length_prefixed_parser"
5
6
 
6
7
  module ReactOnRails
7
8
  module ServerRenderingPool
@@ -79,11 +80,14 @@ module ReactOnRails
79
80
  raise ReactOnRails::Error, msg, err.backtrace
80
81
  end
81
82
 
82
- return parse_result_and_replay_console_messages(result, render_options) unless render_options.streaming?
83
+ return parse_render_result(result, render_options) unless render_options.streaming?
83
84
 
84
- # Streamed component is returned as stream of strings.
85
- # We need to parse each chunk and replay the console messages.
86
- result.transform { |chunk| parse_result_and_replay_console_messages(chunk, render_options) }
85
+ # Streamed chunks are Hashes (from LengthPrefixedParser in stream_request.rb).
86
+ # Just replay console messages and pass through.
87
+ result.transform do |chunk|
88
+ replay_console_to_rails_logger(chunk, render_options)
89
+ chunk
90
+ end
87
91
  end
88
92
 
89
93
  def trace_js_code_used(msg, js_code, file_name = "tmp/server-generated.js", force: false)
@@ -224,26 +228,33 @@ module ReactOnRails
224
228
  raise ReactOnRails::Error, msg
225
229
  end
226
230
 
227
- def parse_result_and_replay_console_messages(result_string, render_options)
228
- result = nil
229
- begin
230
- result = JSON.parse(result_string)
231
- rescue JSON::ParserError => e
232
- raise ReactOnRails::JsonParseError.new(parse_error: e, json: result_string)
233
- end
231
+ def parse_render_result(result_string, render_options)
232
+ # Auto-detect format: length-prefixed (contains tab) or legacy JSON.
233
+ # ExecJS with older bundles may return JSON; node renderer returns length-prefixed.
234
+ result = if result_string.to_s.include?("\t")
235
+ ReactOnRails::LengthPrefixedParser.parse_one_chunk_result(result_string)
236
+ else
237
+ JSON.parse(result_string.to_s)
238
+ end
239
+ replay_console_to_rails_logger(result, render_options)
240
+ result
241
+ rescue StandardError => e
242
+ raise ReactOnRails::JsonParseError.new(parse_error: e, json: result_string)
243
+ end
234
244
 
235
- if render_options.logging_on_server
236
- console_script = result["consoleReplayScript"]
237
- console_script_lines = console_script.split("\n")
238
- # Regular expression to match console.log or console.error calls with SERVER prefix
239
- re = /console\.(?:log|error)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
240
- console_script_lines&.each do |line|
241
- match = re.match(line)
242
- # Log matched messages to Rails logger with react_on_rails prefix
243
- Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
244
- end
245
+ def replay_console_to_rails_logger(result, render_options)
246
+ return unless render_options.logging_on_server
247
+
248
+ console_script = result["consoleReplayScript"]
249
+ return if console_script.nil? || console_script.empty?
250
+
251
+ # Regular expression to match console.log or console.error calls with SERVER prefix
252
+ re = /console\.(?:log|error|info|warn)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
253
+ console_script.split("\n").each do |line|
254
+ match = re.match(line)
255
+ # Log matched messages to Rails logger with react_on_rails prefix
256
+ Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
245
257
  end
246
- result
247
258
  end
248
259
  end
249
260
  # rubocop:enable Metrics/ClassLength
@@ -15,6 +15,7 @@ module ReactOnRails
15
15
  attr_reader :messages
16
16
 
17
17
  SUPPORTED_ASSETS_BUNDLERS = %w[webpack rspack].freeze
18
+ PackageManagerDetection = Struct.new(:manager, :lockfile_scan_blocked, keyword_init: true)
18
19
 
19
20
  def initialize
20
21
  @messages = []
@@ -115,7 +116,8 @@ module ReactOnRails
115
116
  end
116
117
 
117
118
  # Detect which package manager is actually being used
118
- used_manager = detect_used_package_manager
119
+ package_manager_detection = detect_package_manager_from_lockfile
120
+ used_manager = package_manager_detection.manager
119
121
  if used_manager
120
122
  version_info = get_package_manager_version(used_manager)
121
123
  deprecation_note = get_deprecation_note(used_manager, version_info)
@@ -124,7 +126,9 @@ module ReactOnRails
124
126
  add_success(message)
125
127
  else
126
128
  add_success("✅ Package managers available: #{available_managers.join(', ')}")
127
- add_info("ℹ️ No lock file detected - run npm/yarn/pnpm install to establish which manager is used")
129
+ unless package_manager_detection.lockfile_scan_blocked
130
+ add_info("ℹ️ No lock file detected - run npm/yarn/pnpm install to establish which manager is used")
131
+ end
128
132
  end
129
133
  true
130
134
  end
@@ -192,8 +196,8 @@ module ReactOnRails
192
196
  end
193
197
 
194
198
  def check_react_on_rails_npm_package
195
- package_json_path = resolved_package_json_path
196
- return unless File.exist?(package_json_path)
199
+ package_json_path = package_json_path_for("react-on-rails npm package")
200
+ return unless package_json_path
197
201
 
198
202
  package_json = JSON.parse(File.read(package_json_path))
199
203
  package_name, npm_version = react_on_rails_npm_package_details(package_json)
@@ -213,8 +217,8 @@ module ReactOnRails
213
217
  end
214
218
 
215
219
  def check_package_version_sync
216
- package_json_path = resolved_package_json_path
217
- return unless File.exist?(package_json_path)
220
+ package_json_path = package_json_path_for("React on Rails package version sync")
221
+ return unless package_json_path
218
222
 
219
223
  begin
220
224
  package_json = JSON.parse(File.read(package_json_path))
@@ -282,9 +286,10 @@ module ReactOnRails
282
286
 
283
287
  # React dependencies validation
284
288
  def check_react_dependencies
285
- return unless File.exist?(resolved_package_json_path)
289
+ package_json_path = package_json_path_for("React dependencies")
290
+ return unless package_json_path
286
291
 
287
- package_json = parse_package_json
292
+ package_json = parse_package_json(package_json_path)
288
293
  return unless package_json
289
294
 
290
295
  # Check core React dependencies
@@ -444,17 +449,33 @@ module ReactOnRails
444
449
  status.success?
445
450
  end
446
451
 
447
- def detect_used_package_manager
448
- # Check for lock files to determine which package manager is being used
449
- if File.exist?("yarn.lock")
450
- "yarn"
451
- elsif File.exist?("pnpm-lock.yaml")
452
- "pnpm"
453
- elsif File.exist?("bun.lock") || File.exist?("bun.lockb")
454
- "bun"
455
- elsif File.exist?("package-lock.json")
456
- "npm"
457
- end
452
+ def detect_package_manager_from_lockfile
453
+ # Check for lock files next to the configured package.json to support
454
+ # legacy apps that keep their JS package tree under client/.
455
+ package_root = resolved_package_root
456
+ package_json_path = package_json_path_for(
457
+ "package manager",
458
+ package_root
459
+ )
460
+ # If package.json cannot be read, the configured package root is broken
461
+ # enough that detecting a stray lockfile would be misleading. Block the
462
+ # scan so check_package_manager does not suggest installing lockfiles.
463
+ # Covers both cases handled by package_json_path_for: a missing package
464
+ # root directory and an existing directory without a package.json.
465
+ return PackageManagerDetection.new(manager: nil, lockfile_scan_blocked: true) unless package_json_path
466
+
467
+ manager = if File.exist?(File.join(package_root, "yarn.lock"))
468
+ "yarn"
469
+ elsif File.exist?(File.join(package_root, "pnpm-lock.yaml"))
470
+ "pnpm"
471
+ elsif File.exist?(File.join(package_root, "bun.lock")) ||
472
+ File.exist?(File.join(package_root, "bun.lockb"))
473
+ "bun"
474
+ elsif File.exist?(File.join(package_root, "package-lock.json"))
475
+ "npm"
476
+ end
477
+
478
+ PackageManagerDetection.new(manager: manager, lockfile_scan_blocked: false)
458
479
  end
459
480
 
460
481
  def get_package_manager_version(manager)
@@ -717,8 +738,8 @@ module ReactOnRails
717
738
  end
718
739
  # rubocop:enable Metrics/CyclomaticComplexity
719
740
 
720
- def parse_package_json
721
- JSON.parse(File.read(resolved_package_json_path))
741
+ def parse_package_json(package_json_path)
742
+ JSON.parse(File.read(package_json_path))
722
743
  rescue Errno::ENOENT, JSON::ParserError
723
744
  add_warning("⚠️ Could not parse package.json to check React dependencies")
724
745
  nil
@@ -814,8 +835,8 @@ module ReactOnRails
814
835
  end
815
836
 
816
837
  def report_webpack_version
817
- package_json_path = resolved_package_json_path
818
- return unless File.exist?(package_json_path)
838
+ package_json_path = package_json_path_for("Webpack version")
839
+ return unless package_json_path
819
840
 
820
841
  begin
821
842
  package_json = JSON.parse(File.read(package_json_path))
@@ -161,6 +161,11 @@ module ReactOnRails
161
161
  (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
162
162
  end
163
163
 
164
+ def self.command_available?(command)
165
+ which_command = running_on_windows? ? "where" : "which"
166
+ !!system(which_command, command, out: File::NULL, err: File::NULL)
167
+ end
168
+
164
169
  def self.rails_version_less_than(version)
165
170
  @rails_version_less_than ||= {}
166
171
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "16.6.0"
4
+ VERSION = "16.7.0.rc.0"
5
5
  end
@@ -12,6 +12,9 @@ require "react_on_rails/version_checker"
12
12
  require "react_on_rails/configuration"
13
13
  require "react_on_rails/server_rendering_pool"
14
14
  require "react_on_rails/server_rendering_js_code"
15
+ require "react_on_rails/render_request"
16
+ require "react_on_rails/js_code_builder"
17
+ require "react_on_rails/rendering_strategy"
15
18
  require "react_on_rails/engine"
16
19
  require "react_on_rails/react_component/render_options"
17
20
  require "react_on_rails/version_syntax_converter"
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "coveralls/rake/task" if ENV["USE_COVERALLS"] == "TRUE"
4
-
5
3
  require "pathname"
6
4
  require "yaml"
7
5
 
@@ -141,8 +139,6 @@ namespace :run_rspec do
141
139
  pinned_version_examples.each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
142
140
  end
143
141
 
144
- Coveralls::RakeTask.new if ENV["USE_COVERALLS"] == "TRUE"
145
-
146
142
  desc "run all tests no examples"
147
143
  task all_but_examples: %i[gem dummy_no_turbolinks dummy js_tests] do
148
144
  puts "Completed all RSpec tests"
@@ -209,7 +205,6 @@ def run_tests_in(dir, options = {})
209
205
  env_tokens = []
210
206
  env_tokens << options.fetch(:env_vars, "").strip unless options.fetch(:env_vars, "").strip.empty?
211
207
  env_tokens << "TEST_ENV_COMMAND_NAME=\"#{command_name}\""
212
- env_tokens << "COVERAGE=true" if ENV["USE_COVERALLS"]
213
208
 
214
209
  env_vars = env_tokens.join(" ")
215
210
  command = "#{env_vars} bundle exec rspec #{rspec_args}"
@@ -64,6 +64,38 @@ namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
64
64
  fallback_match&.[](1)
65
65
  end
66
66
 
67
+ def local_react_on_rails_package_ref(dir)
68
+ package_dir = File.expand_path("../packages/react-on-rails", gem_root)
69
+ relative_package_dir = Pathname(package_dir).relative_path_from(Pathname(dir)).to_s
70
+ "file:#{relative_package_dir}"
71
+ end
72
+
73
+ # Makes generated examples use the local monorepo package for react-on-rails.
74
+ # This ensures CI validates the package code in this branch rather than a
75
+ # potentially stale published npm version.
76
+ def pin_react_on_rails_to_local_package(dir)
77
+ package_json_path = File.join(dir, "package.json")
78
+ return unless File.exist?(package_json_path)
79
+
80
+ begin
81
+ package_json = JSON.parse(File.read(package_json_path))
82
+ rescue JSON::ParserError => e
83
+ puts " ERROR: Failed to parse #{package_json_path}: #{e.message}"
84
+ raise
85
+ end
86
+
87
+ deps = package_json["dependencies"]
88
+ return unless deps&.key?("react-on-rails")
89
+
90
+ local_package_ref = local_react_on_rails_package_ref(dir)
91
+
92
+ return if deps["react-on-rails"] == local_package_ref
93
+
94
+ puts " Pinning react-on-rails npm dependency from #{deps['react-on-rails']} to #{local_package_ref}"
95
+ deps["react-on-rails"] = local_package_ref
96
+ File.write(package_json_path, "#{JSON.pretty_generate(package_json)}\n")
97
+ end
98
+
67
99
  # Updates React-related dependencies to a specific version
68
100
  def update_react_dependencies(deps, react_version)
69
101
  return unless deps
@@ -115,6 +147,37 @@ namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
115
147
  puts " React: #{react_version}"
116
148
  end
117
149
 
150
+ def install_local_react_on_rails_package(dir, legacy_peer_deps: false)
151
+ legacy_peer_deps_flag = legacy_peer_deps ? "--legacy-peer-deps " : ""
152
+ sh_in_dir(dir,
153
+ "npm install react-on-rails@#{local_react_on_rails_package_ref(dir)} " \
154
+ "#{legacy_peer_deps_flag}--install-links")
155
+ end
156
+
157
+ def install_example_node_dependencies(example_type)
158
+ pin_shakapacker_npm_version(example_type.dir)
159
+ pin_react_on_rails_to_local_package(example_type.dir)
160
+
161
+ if example_type.pinned_react_version?
162
+ # Use --legacy-peer-deps to avoid peer dependency conflicts when
163
+ # react-on-rails expects newer React versions.
164
+ sh_in_dir(example_type.dir, "npm install --legacy-peer-deps --install-links")
165
+ # Explicit re-install is required because npm install --install-links does not
166
+ # reliably copy a file: dependency that was just pinned in the same session.
167
+ install_local_react_on_rails_package(example_type.dir, legacy_peer_deps: true)
168
+ # Regenerate Shakapacker binstubs after downgrading from 9.x to 8.2.x
169
+ # The binstub format may differ between major versions.
170
+ unbundled_sh_in_dir(example_type.dir, "bundle exec rake shakapacker:binstubs")
171
+ else
172
+ # Use --install-links to copy file: dependencies instead of symlinking,
173
+ # preventing duplicate React instances from webpack resolving through symlinks.
174
+ sh_in_dir(example_type.dir, "npm install --install-links")
175
+ # Explicit re-install is required because npm install --install-links does not
176
+ # reliably copy a file: dependency that was just pinned in the same session.
177
+ install_local_react_on_rails_package(example_type.dir)
178
+ end
179
+ end
180
+
118
181
  # Define tasks for each example type
119
182
  ExampleType.all[:shakapacker_examples].each do |example_type| # rubocop:disable Metrics/BlockLength
120
183
  relative_gem_root = Pathname(gem_root).relative_path_from(Pathname(example_type.dir))
@@ -150,7 +213,7 @@ namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
150
213
  # Use unbundled_sh_in_dir to ensure the generator uses the example app's
151
214
  # gem versions, not the parent workspace's cached bundle context.
152
215
  unbundled_sh_in_dir(example_type.dir, generator_commands)
153
- # Re-run bundle install since dev_tests generator adds rspec-rails and coveralls to Gemfile
216
+ # Re-run bundle install since dev_tests generator adds rspec-rails and simplecov to Gemfile
154
217
  bundle_install_in(example_type.dir)
155
218
 
156
219
  # Apply specific React version for compatibility testing examples
@@ -158,29 +221,9 @@ namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
158
221
  apply_react_version(example_type.dir, example_type.react_version_string)
159
222
  # Re-run bundle install to ensure dependencies are resolved correctly
160
223
  bundle_install_in(example_type.dir)
161
- # Pin the npm shakapacker version to exactly match the installed gem version.
162
- # shakapacker:install may add "^X.Y.Z" to package.json, which allows npm to
163
- # resolve a newer minor version (e.g., 9.6.0 when gem is 9.5.0), causing
164
- # Shakapacker's gem/npm version consistency check to fail.
165
- pin_shakapacker_npm_version(example_type.dir)
166
- # Use --legacy-peer-deps to avoid peer dependency conflicts when
167
- # react-on-rails expects newer React versions
168
- # Use --install-links to copy file: dependencies instead of symlinking,
169
- # preventing duplicate React instances from webpack resolving through symlinks
170
- sh_in_dir(example_type.dir, "npm install --legacy-peer-deps --install-links")
171
- # Regenerate Shakapacker binstubs after downgrading from 9.x to 8.2.x
172
- # The binstub format may differ between major versions
173
- unbundled_sh_in_dir(example_type.dir, "bundle exec rake shakapacker:binstubs")
174
- else
175
- # Pin the npm shakapacker version to exactly match the installed gem version.
176
- # shakapacker:install may add "^X.Y.Z" to package.json, which allows npm to
177
- # resolve a newer minor version (e.g., 9.6.0 when gem is 9.5.0), causing
178
- # Shakapacker's gem/npm version consistency check to fail.
179
- pin_shakapacker_npm_version(example_type.dir)
180
- # Use --install-links to copy file: dependencies instead of symlinking,
181
- # preventing duplicate React instances from webpack resolving through symlinks
182
- sh_in_dir(example_type.dir, "npm install --install-links")
183
224
  end
225
+ # Pin npm package versions and install node dependencies for generated example.
226
+ install_example_node_dependencies(example_type)
184
227
  # Generate the component packs after running the generator to ensure all
185
228
  # auto-bundled components have corresponding pack files created.
186
229
  # Use unbundled_sh_in_dir to ensure we're using the generated app's Gemfile
@@ -13,8 +13,16 @@ Gem::Specification.new do |s|
13
13
 
14
14
  s.summary = "Rails with react server rendering with webpack. "
15
15
  s.description = "See README.md"
16
- s.homepage = "https://github.com/shakacode/react_on_rails"
16
+ s.homepage = "https://reactonrails.com/docs/"
17
17
  s.license = "MIT"
18
+ s.metadata = {
19
+ "bug_tracker_uri" => "https://github.com/shakacode/react_on_rails/issues",
20
+ "changelog_uri" => "https://github.com/shakacode/react_on_rails/blob/main/CHANGELOG.md",
21
+ "documentation_uri" => "https://reactonrails.com/docs/",
22
+ "homepage_uri" => "https://reactonrails.com/docs/",
23
+ "rubygems_mfa_required" => "true",
24
+ "source_code_uri" => "https://github.com/shakacode/react_on_rails/tree/main/react_on_rails"
25
+ }
18
26
 
19
27
  s.files = Dir.chdir(__dir__) do
20
28
  `git ls-files -z`.split("\x0").reject do |f|
@@ -37,12 +45,14 @@ Gem::Specification.new do |s|
37
45
  s.add_dependency "shakapacker", ">= 6.0"
38
46
 
39
47
  s.add_development_dependency "gem-release"
40
- s.post_install_message = '
41
- --------------------------------------------------------------------------------
42
- Checkout https://pro.reactonrails.com for information about
43
- "React on Rails Pro" which includes a gem for better performance, via caching helpers, and our
44
- node rendering server, support for React 19, and much more.
45
- --------------------------------------------------------------------------------
46
- '
48
+ s.post_install_message = <<~MESSAGE
49
+ --------------------------------------------------------------------------------
50
+ Need React Server Components, streaming SSR, caching, or faster Node-based SSR?
51
+ React on Rails Pro is free to try in development, CI/CD, and staging.
52
+ Compare OSS vs Pro: https://reactonrails.com/docs/getting-started/oss-vs-pro/
53
+ Pro quick start: https://reactonrails.com/docs/getting-started/pro-quick-start/
54
+ Contact ShakaCode: https://www.shakacode.com/contact/
55
+ --------------------------------------------------------------------------------
56
+ MESSAGE
47
57
  end
48
58
  # rubocop:enable Metrics/BlockLength
@@ -0,0 +1,11 @@
1
+ module ReactOnRails
2
+ class JsCodeBuilder
3
+ def build: (RenderRequest render_request) -> String
4
+ def build_sections: (RenderRequest render_request) -> Array[String?]
5
+ def rails_context_section: (RenderRequest render_request) -> String
6
+ def store_initialization_section: (RenderRequest render_request) -> String?
7
+ def props_section: (RenderRequest render_request) -> String
8
+ def render_call_section: (RenderRequest render_request) -> String
9
+ def wrap_in_iife: (String body, RenderRequest render_request) -> String
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ module ReactOnRails
2
+ class RenderRequest
3
+ attr_reader component_name: String
4
+ attr_reader props: Hash[untyped, untyped] | String
5
+ attr_reader rails_context: Hash[untyped, untyped]
6
+ attr_reader store_initializations: String?
7
+ attr_reader render_options: untyped
8
+
9
+ def initialize: (
10
+ component_name: String,
11
+ props: Hash[untyped, untyped] | String,
12
+ rails_context: Hash[untyped, untyped],
13
+ store_initializations: String?,
14
+ render_options: untyped
15
+ ) -> void
16
+
17
+ def to_js: () -> String
18
+ def props_string: () -> String
19
+ def rails_context_json: () -> String
20
+ def dom_id: () -> String
21
+ def streaming?: () -> bool
22
+ def rsc_payload_streaming?: () -> bool
23
+
24
+ private
25
+
26
+ def validate_server_bundle_configured!: () -> void
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ module ReactOnRails
2
+ module RenderingStrategy
3
+ class ExecJsStrategy
4
+ include ReactOnRails::RenderingStrategy
5
+
6
+ def execute: (RenderRequest render_request) -> untyped
7
+ def reset: () -> void
8
+ def reset_if_bundle_changed: () -> void
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module ReactOnRails
2
+ module RenderingStrategy
3
+ def execute: (RenderRequest render_request) -> untyped
4
+ def reset: () -> void
5
+ def reset_if_bundle_changed: () -> void
6
+ end
7
+ end
@@ -9,6 +9,12 @@ module ReactOnRails
9
9
  def self.configure: () { (Configuration) -> void } -> void
10
10
  def self.configuration: () -> Configuration
11
11
 
12
+ def self.rendering_strategy: () -> RenderingStrategy
13
+ def self.rendering_strategy=: (RenderingStrategy strategy) -> RenderingStrategy
14
+
15
+ def self.js_code_builder: () -> JsCodeBuilder
16
+ def self.js_code_builder=: (JsCodeBuilder builder) -> JsCodeBuilder
17
+
12
18
  # Error classes are defined in separate RBS files:
13
19
  # - sig/react_on_rails/prerender_error.rbs
14
20
  # - sig/react_on_rails/json_parse_error.rbs
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.6.0
4
+ version: 16.7.0.rc.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-09 00:00:00.000000000 Z
11
+ date: 2026-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -130,6 +130,9 @@ files:
130
130
  - lib/generators/react_on_rails/dev_tests_generator.rb
131
131
  - lib/generators/react_on_rails/generator_helper.rb
132
132
  - lib/generators/react_on_rails/generator_messages.rb
133
+ - lib/generators/react_on_rails/generator_messages/ci_section.rb
134
+ - lib/generators/react_on_rails/generator_messages/package_manager_detection.rb
135
+ - lib/generators/react_on_rails/generator_messages/shakapacker_status_section.rb
133
136
  - lib/generators/react_on_rails/install_generator.rb
134
137
  - lib/generators/react_on_rails/js_dependency_manager.rb
135
138
  - lib/generators/react_on_rails/pro/USAGE
@@ -143,6 +146,7 @@ files:
143
146
  - lib/generators/react_on_rails/templates/.eslintrc
144
147
  - lib/generators/react_on_rails/templates/base/base/.dev-services.yml.example
145
148
  - lib/generators/react_on_rails/templates/base/base/.env.example
149
+ - lib/generators/react_on_rails/templates/base/base/.github/workflows/ci.yml.tt
146
150
  - lib/generators/react_on_rails/templates/base/base/Procfile.dev
147
151
  - lib/generators/react_on_rails/templates/base/base/Procfile.dev-prod-assets
148
152
  - lib/generators/react_on_rails/templates/base/base/Procfile.dev-static-assets
@@ -185,8 +189,8 @@ files:
185
189
  - lib/generators/react_on_rails/templates/dev_tests/spec/spec_helper.rb
186
190
  - lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_server_spec.rb
187
191
  - lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_world_spec.rb
188
- - lib/generators/react_on_rails/templates/pro/base/client/node-renderer.js
189
192
  - lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt
193
+ - lib/generators/react_on_rails/templates/pro/base/renderer/node-renderer.js
190
194
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/actions/helloWorldActionCreators.js
191
195
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/actions/helloWorldActionCreators.ts
192
196
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx
@@ -230,8 +234,10 @@ files:
230
234
  - lib/react_on_rails/error.rb
231
235
  - lib/react_on_rails/git_utils.rb
232
236
  - lib/react_on_rails/helper.rb
237
+ - lib/react_on_rails/js_code_builder.rb
233
238
  - lib/react_on_rails/json_output.rb
234
239
  - lib/react_on_rails/json_parse_error.rb
240
+ - lib/react_on_rails/length_prefixed_parser.rb
235
241
  - lib/react_on_rails/locales/base.rb
236
242
  - lib/react_on_rails/locales/to_js.rb
237
243
  - lib/react_on_rails/locales/to_json.rb
@@ -239,7 +245,11 @@ files:
239
245
  - lib/react_on_rails/packs_generator.rb
240
246
  - lib/react_on_rails/prerender_error.rb
241
247
  - lib/react_on_rails/pro_helper.rb
248
+ - lib/react_on_rails/pro_migration.rb
242
249
  - lib/react_on_rails/react_component/render_options.rb
250
+ - lib/react_on_rails/render_request.rb
251
+ - lib/react_on_rails/rendering_strategy.rb
252
+ - lib/react_on_rails/rendering_strategy/exec_js_strategy.rb
243
253
  - lib/react_on_rails/server_rendering_js_code.rb
244
254
  - lib/react_on_rails/server_rendering_pool.rb
245
255
  - lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb
@@ -287,25 +297,36 @@ files:
287
297
  - sig/react_on_rails/generators/js_dependency_manager.rbs
288
298
  - sig/react_on_rails/git_utils.rbs
289
299
  - sig/react_on_rails/helper.rbs
300
+ - sig/react_on_rails/js_code_builder.rbs
290
301
  - sig/react_on_rails/json_parse_error.rbs
291
302
  - sig/react_on_rails/locales.rbs
292
303
  - sig/react_on_rails/packer_utils.rbs
293
304
  - sig/react_on_rails/prerender_error.rbs
305
+ - sig/react_on_rails/render_request.rbs
306
+ - sig/react_on_rails/rendering_strategy.rbs
307
+ - sig/react_on_rails/rendering_strategy/exec_js_strategy.rbs
294
308
  - sig/react_on_rails/server_rendering_pool.rbs
295
309
  - sig/react_on_rails/smart_error.rbs
296
310
  - sig/react_on_rails/test_helper.rbs
297
311
  - sig/react_on_rails/utils.rbs
298
312
  - sig/react_on_rails/version_checker.rbs
299
- homepage: https://github.com/shakacode/react_on_rails
313
+ homepage: https://reactonrails.com/docs/
300
314
  licenses:
301
315
  - MIT
302
- metadata: {}
303
- post_install_message: |2
304
-
316
+ metadata:
317
+ bug_tracker_uri: https://github.com/shakacode/react_on_rails/issues
318
+ changelog_uri: https://github.com/shakacode/react_on_rails/blob/main/CHANGELOG.md
319
+ documentation_uri: https://reactonrails.com/docs/
320
+ homepage_uri: https://reactonrails.com/docs/
321
+ rubygems_mfa_required: 'true'
322
+ source_code_uri: https://github.com/shakacode/react_on_rails/tree/main/react_on_rails
323
+ post_install_message: |
305
324
  --------------------------------------------------------------------------------
306
- Checkout https://pro.reactonrails.com for information about
307
- "React on Rails Pro" which includes a gem for better performance, via caching helpers, and our
308
- node rendering server, support for React 19, and much more.
325
+ Need React Server Components, streaming SSR, caching, or faster Node-based SSR?
326
+ React on Rails Pro is free to try in development, CI/CD, and staging.
327
+ Compare OSS vs Pro: https://reactonrails.com/docs/getting-started/oss-vs-pro/
328
+ Pro quick start: https://reactonrails.com/docs/getting-started/pro-quick-start/
329
+ Contact ShakaCode: https://www.shakacode.com/contact/
309
330
  --------------------------------------------------------------------------------
310
331
  rdoc_options: []
311
332
  require_paths: