react_on_rails 16.4.0 → 16.5.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/lib/generators/react_on_rails/generator_messages.rb +20 -18
  4. data/lib/generators/react_on_rails/install_generator.rb +128 -12
  5. data/lib/generators/react_on_rails/pro_generator.rb +1 -1
  6. data/lib/generators/react_on_rails/pro_setup.rb +3 -2
  7. data/lib/generators/react_on_rails/react_with_redux_generator.rb +2 -1
  8. data/lib/generators/react_on_rails/rsc_generator.rb +1 -1
  9. data/lib/generators/react_on_rails/templates/base/base/bin/dev +1 -1
  10. data/lib/generators/react_on_rails/templates/pro/base/client/node-renderer.js +8 -4
  11. data/lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt +1 -1
  12. data/lib/generators/react_on_rails/templates/rsc/base/app/controllers/hello_server_controller.rb.tt +1 -1
  13. data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.jsx +1 -1
  14. data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.tsx +1 -1
  15. data/lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb +1 -1
  16. data/lib/generators/react_on_rails/templates/rsc/base/config/webpack/rscWebpackConfig.js.tt +1 -1
  17. data/lib/react_on_rails/config_path_resolver.rb +50 -0
  18. data/lib/react_on_rails/configuration.rb +1 -1
  19. data/lib/react_on_rails/dev/process_manager.rb +16 -1
  20. data/lib/react_on_rails/dev/server_manager.rb +2 -2
  21. data/lib/react_on_rails/doctor.rb +389 -25
  22. data/lib/react_on_rails/git_utils.rb +95 -23
  23. data/lib/react_on_rails/packer_utils.rb +1 -1
  24. data/lib/react_on_rails/packs_generator.rb +3 -3
  25. data/lib/react_on_rails/react_component/render_options.rb +48 -0
  26. data/lib/react_on_rails/server_rendering_js_code.rb +1 -1
  27. data/lib/react_on_rails/system_checker.rb +42 -19
  28. data/lib/react_on_rails/utils.rb +1 -1
  29. data/lib/react_on_rails/version.rb +1 -1
  30. data/lib/react_on_rails/version_synchronizer.rb +250 -0
  31. data/lib/tasks/generate_packs.rake +3 -3
  32. data/lib/tasks/sync_versions.rake +23 -0
  33. data/rakelib/examples_config.yml +1 -1
  34. data/rakelib/update_changelog.rake +3 -3
  35. data/react_on_rails.gemspec +1 -1
  36. data/sig/react_on_rails/dev/process_manager.rbs +2 -0
  37. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e8711eddc91f2c2afd343c203a466e320e3c98231a6cea82f950f91de9c234c
4
- data.tar.gz: 3e833073ef81b6051e2484075288e7aca18026eafb9d7e1727a84a7ae53e22fc
3
+ metadata.gz: 14bbaccde12f9bb4f998ade94c02d95d27e1df386a9dfaf887fefb0f073070e0
4
+ data.tar.gz: 952bf7eb1d5694d86b74dd654ab2cb10fd7490207d6be3c66ac6ea4866802eee
5
5
  SHA512:
6
- metadata.gz: fb4f879f38e2a7fce93204c22efaf2c360dc5031ad52384d7abe3cfcf0f712365dbfed53ae3385f93106d4d9549bb36a714caacb820d633d7c21a4864dce3c00
7
- data.tar.gz: df85baa5aecb849d6b28636975540a2102ab0f70c1efdc3b00e26923dd4524f4bda758a6153eb541c8db86dfc8e6860830c6336785e50c1d5416d12486b2d5e7
6
+ metadata.gz: 3bdbf4f3343cf568ea879a13d0902d650379016004832c44affd1498ac8c0be881de9e7d4bb42ecd883f095f5697518dfcc773d7d79b61c4250026457100d9cd
7
+ data.tar.gz: 920530b24dbe7d23af418d53ad564e9f75bbf0f21fcc03851b89de03994d6a1e910fdaeb962da9eb4f66eed0cc37f28a9048fd2dcf3d208c9422843a7208fe4c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- react_on_rails (16.4.0)
4
+ react_on_rails (16.5.0)
5
5
  addressable
6
6
  connection_pool
7
7
  execjs (~> 2.5)
@@ -3,6 +3,9 @@
3
3
  require "rainbow"
4
4
 
5
5
  module GeneratorMessages
6
+ PRO_UPGRADE_HINT = "\n\n 💎 For RSC, streaming SSR, and 10-100x faster SSR, try React on Rails Pro:" \
7
+ "\n #{Rainbow('https://reactonrails.com/docs/pro/upgrading-to-pro/').cyan.underline}".freeze
8
+
6
9
  class << self
7
10
  def output
8
11
  @output ||= []
@@ -40,14 +43,16 @@ module GeneratorMessages
40
43
  @output = []
41
44
  end
42
45
 
43
- def helpful_message_after_installation(component_name: "HelloWorld", route: "hello_world", rsc: false,
44
- shakapacker_just_installed: false)
46
+ def helpful_message_after_installation(component_name: "HelloWorld", route: "hello_world", pro: false,
47
+ rsc: false, shakapacker_just_installed: false)
45
48
  process_manager_section = build_process_manager_section
46
49
  testing_section = build_testing_section
47
50
  package_manager = detect_package_manager
48
51
  shakapacker_status = build_shakapacker_status_section(shakapacker_just_installed: shakapacker_just_installed)
49
52
  render_example = build_render_example(component_name: component_name, route: route, rsc: rsc)
50
53
  render_label = build_render_label(route: route, rsc: rsc)
54
+ # rsc guard is defensive; callers via install_generator already pass pro: true when rsc is set
55
+ pro_hint = pro || rsc ? "" : PRO_UPGRADE_HINT
51
56
 
52
57
  <<~MSG
53
58
 
@@ -61,13 +66,16 @@ module GeneratorMessages
61
66
  1. Install dependencies:
62
67
  #{Rainbow("bundle && #{package_manager} install").cyan}
63
68
 
64
- 2. Start the app:
69
+ 2. Prepare database:
70
+ #{Rainbow('bin/rails db:prepare').cyan}
71
+
72
+ 3. Start the app:
65
73
  ./bin/dev # HMR (Hot Module Replacement) mode
66
74
  ./bin/dev static # Static bundles (no HMR, faster initial load)
67
75
  ./bin/dev prod # Production-like mode for testing
68
76
  ./bin/dev help # See all available options
69
77
 
70
- 3. Visit: #{Rainbow(route ? "http://localhost:3000/#{route}" : 'http://localhost:3000').cyan.underline}
78
+ 4. Visit: #{Rainbow(route ? "http://localhost:3000/#{route}" : 'http://localhost:3000').cyan.underline}
71
79
  ✨ KEY FEATURES:
72
80
  ─────────────────────────────────────────────────────────────────────────
73
81
  • Auto-registration enabled - Your layout only needs:
@@ -79,16 +87,19 @@ module GeneratorMessages
79
87
 
80
88
  📚 LEARN MORE:
81
89
  ─────────────────────────────────────────────────────────────────────────
82
- • Documentation: #{Rainbow('https://www.shakacode.com/react-on-rails/docs/').cyan.underline}
90
+ • Documentation: #{Rainbow('https://reactonrails.com/docs/').cyan.underline}
83
91
  • Webpack customization: #{Rainbow('https://github.com/shakacode/shakapacker#webpack-configuration').cyan.underline}
84
92
 
85
- 💡 TIP: Run 'bin/dev help' for development server options and troubleshooting#{testing_section}
93
+ 💡 TIP: Run 'bin/dev help' for development server options and troubleshooting#{testing_section}#{pro_hint}
86
94
  MSG
87
95
  end
88
96
 
89
97
  # Uses relative lockfile paths resolved against Dir.pwd, so callers must invoke
90
98
  # this while the current working directory is the target Rails app root.
91
99
  def detect_package_manager
100
+ env_package_manager = ENV.fetch("REACT_ON_RAILS_PACKAGE_MANAGER", nil)&.strip&.downcase
101
+ return env_package_manager if %w[npm pnpm yarn bun].include?(env_package_manager)
102
+
92
103
  # Check for lock files to determine package manager
93
104
  return "yarn" if File.exist?("yarn.lock")
94
105
  return "pnpm" if File.exist?("pnpm-lock.yaml")
@@ -133,10 +144,7 @@ module GeneratorMessages
133
144
  end
134
145
 
135
146
  def build_testing_section
136
- # Check if we have any spec files to determine if testing setup is needed
137
- has_spec_files = File.exist?("spec/rails_helper.rb") || File.exist?("spec/spec_helper.rb")
138
-
139
- return "" if has_spec_files
147
+ return "" if File.exist?("spec/rails_helper.rb") || File.exist?("spec/spec_helper.rb")
140
148
 
141
149
  <<~TESTING
142
150
 
@@ -160,7 +168,6 @@ module GeneratorMessages
160
168
 
161
169
  def build_shakapacker_status_section(shakapacker_just_installed: false)
162
170
  version_warning = check_shakapacker_version_warning
163
-
164
171
  if shakapacker_just_installed
165
172
  base = <<~SHAKAPACKER
166
173
 
@@ -179,18 +186,13 @@ module GeneratorMessages
179
186
  end
180
187
 
181
188
  def check_shakapacker_version_warning
182
- # Try to detect Shakapacker version from Gemfile.lock
183
189
  return "" unless File.exist?("Gemfile.lock")
184
190
 
185
- gemfile_lock_content = File.read("Gemfile.lock")
186
- shakapacker_match = gemfile_lock_content.match(/shakapacker \((\d+\.\d+\.\d+)\)/)
187
-
191
+ shakapacker_match = File.read("Gemfile.lock").match(/shakapacker \((\d+\.\d+\.\d+)\)/)
188
192
  return "" unless shakapacker_match
189
193
 
190
194
  version = shakapacker_match[1]
191
- major_version = version.split(".").first.to_i
192
-
193
- if major_version < 8
195
+ if version.split(".").first.to_i < 8
194
196
  <<~WARNING
195
197
 
196
198
  ⚠️ #{Rainbow('IMPORTANT: Upgrade Recommended').yellow.bold}
@@ -79,6 +79,49 @@ module ReactOnRails
79
79
  # Removed: --skip-shakapacker-install (Shakapacker is now a required dependency)
80
80
 
81
81
  SHAKAPACKER_YML_PATH = "config/shakapacker.yml"
82
+ # Matches the stock `bin/dev` written by Rails 8.x. Rails 7.1 commonly
83
+ # generated a foreman-based shell script instead, which stock_rails_bin_dev?
84
+ # also recognizes so the React on Rails template can replace either variant.
85
+ STOCK_RAILS_BIN_DEV = <<~RUBY
86
+ #!/usr/bin/env ruby
87
+ exec "./bin/rails", "server", *ARGV
88
+ RUBY
89
+ # Recognize only known legacy Rails foreman templates. Any other variant is
90
+ # treated as customized so install does not overwrite app-specific logic.
91
+ LEGACY_FOREMAN_BIN_DEV_TEMPLATES = [
92
+ <<~BASH,
93
+ #!/usr/bin/env bash
94
+ if ! gem list foreman -i --silent; then
95
+ gem install foreman
96
+ fi
97
+
98
+ exec foreman start -f Procfile.dev "$@"
99
+ BASH
100
+ <<~SH,
101
+ #!/usr/bin/env sh
102
+ if ! gem list foreman -i --silent; then
103
+ gem install foreman
104
+ fi
105
+
106
+ exec foreman start -f Procfile.dev "$@"
107
+ SH
108
+ <<~BASH,
109
+ #!/usr/bin/env bash
110
+ if ! gem list foreman -i --silent; then
111
+ gem install foreman
112
+ fi
113
+
114
+ exec foreman start -f Procfile.dev $@
115
+ BASH
116
+ <<~SH
117
+ #!/usr/bin/env sh
118
+ if ! gem list foreman -i --silent; then
119
+ gem install foreman
120
+ fi
121
+
122
+ exec foreman start -f Procfile.dev $@
123
+ SH
124
+ ].map { |template| template.gsub("\r\n", "\n").strip }.freeze
82
125
 
83
126
  # Main generator entry point
84
127
  #
@@ -188,10 +231,28 @@ module ReactOnRails
188
231
  # js(.coffee) are not checked by this method, but instead produce warning messages
189
232
  # and allow the build to continue
190
233
  def installation_prerequisites_met?
191
- # Check uncommitted_changes? before missing_pro_gem? so that
192
- # auto-install does not mutate the Gemfile on a dirty working tree.
193
- !(missing_node? || missing_package_manager? ||
194
- ReactOnRails::GitUtils.uncommitted_changes?(GeneratorMessages) || missing_pro_gem?)
234
+ # Non-blocking: warn about dirty worktree but don't prevent installation.
235
+ # A clean tree makes the generator diff easier to review, but blocking would
236
+ # be too strict for a generator that creates many new files.
237
+ has_worktree_issues = ReactOnRails::GitUtils.warn_if_uncommitted_changes(
238
+ GeneratorMessages, git_installed: cli_exists?("git")
239
+ )
240
+
241
+ # missing_pro_gem? may auto-install the gem (mutating Gemfile), so only run
242
+ # it on a clean worktree. On a dirty tree, use the read-only pro_gem_installed?
243
+ # check to catch a missing gem without triggering auto-install.
244
+ if has_worktree_issues && use_pro? && !pro_gem_installed?
245
+ GeneratorMessages.add_error(<<~MSG.strip)
246
+ 🚫 react_on_rails_pro gem is required for #{options[:rsc] ? '--rsc' : '--pro'} but is not installed.
247
+ Auto-install was skipped because the worktree has uncommitted changes.
248
+ Please add it manually:
249
+ gem 'react_on_rails_pro', '~> #{recommended_pro_gem_version}'
250
+ Then run: bundle install
251
+ MSG
252
+ return false
253
+ end
254
+
255
+ !(missing_node? || missing_package_manager? || (!has_worktree_issues && missing_pro_gem?))
195
256
  end
196
257
 
197
258
  def missing_node?
@@ -277,13 +338,23 @@ module ReactOnRails
277
338
  end
278
339
 
279
340
  def add_bin_scripts
341
+ replace_stock_rails_bin_dev!
342
+
280
343
  # Copy bin scripts from templates
281
344
  template_bin_path = "#{__dir__}/templates/base/base/bin"
282
- directory template_bin_path, "bin"
345
+ directory_options = {}
346
+ directory_options[:exclude_pattern] = %r{/dev(?:\.tt)?\z} if preserve_existing_bin_dev?
347
+ directory template_bin_path, "bin", directory_options
283
348
 
284
349
  # For --rsc without --redux, hello_world doesn't exist — update DEFAULT_ROUTE
285
350
  if use_rsc? && !options.redux?
286
- gsub_file "bin/dev", 'DEFAULT_ROUTE = "hello_world"', 'DEFAULT_ROUTE = "hello_server"'
351
+ if preserve_existing_bin_dev?
352
+ say_status :warn,
353
+ 'Custom bin/dev detected: update DEFAULT_ROUTE to "hello_server" manually for --rsc',
354
+ :yellow
355
+ else
356
+ gsub_file "bin/dev", 'DEFAULT_ROUTE = "hello_world"', 'DEFAULT_ROUTE = "hello_server"'
357
+ end
287
358
  end
288
359
 
289
360
  # `directory` and `gsub_file` above are Thor actions that already honor
@@ -294,13 +365,48 @@ module ReactOnRails
294
365
  end
295
366
 
296
367
  # Make these and only these files executable
297
- files_to_copy = []
298
- Dir.chdir(template_bin_path) do
299
- files_to_copy.concat(Dir.glob("*"))
368
+ files_to_become_executable = bin_scripts_to_chmod(template_bin_path)
369
+ File.chmod(0o755, *files_to_become_executable)
370
+ end
371
+
372
+ def replace_stock_rails_bin_dev!
373
+ @preserve_existing_bin_dev = false
374
+
375
+ unless stock_rails_bin_dev?
376
+ if File.exist?("bin/dev")
377
+ say_status :skip, "bin/dev exists but does not match a stock Rails template; keeping existing file", :yellow
378
+ @preserve_existing_bin_dev = true
379
+ end
380
+ return
300
381
  end
301
- files_to_become_executable = files_to_copy.map { |filename| "bin/#{filename}" }
302
382
 
303
- File.chmod(0o755, *files_to_become_executable)
383
+ if options[:pretend] || options[:skip]
384
+ say_status :skip, "Detected stock Rails bin/dev; leaving existing file in place for --pretend/--skip", :yellow
385
+ @preserve_existing_bin_dev = true
386
+ return
387
+ end
388
+
389
+ say_status :replace, "Detected stock Rails bin/dev; installing React on Rails bin/dev", :yellow
390
+ remove_file "bin/dev", verbose: false
391
+ end
392
+
393
+ def preserve_existing_bin_dev?
394
+ # Set by replace_stock_rails_bin_dev! which always runs first via add_bin_scripts.
395
+ # Explicitly coerce to boolean so nil (before initialization) is treated as false.
396
+ !!@preserve_existing_bin_dev
397
+ end
398
+
399
+ def bin_scripts_to_chmod(template_bin_path)
400
+ files = Dir.children(template_bin_path)
401
+ files.reject! { |f| f == "dev" } if preserve_existing_bin_dev?
402
+ files.map { |filename| "bin/#{filename}" }
403
+ end
404
+
405
+ def stock_rails_bin_dev?
406
+ return false unless File.exist?("bin/dev")
407
+
408
+ content = normalize_bin_dev_content(File.read("bin/dev"))
409
+ content == normalize_bin_dev_content(STOCK_RAILS_BIN_DEV) || legacy_foreman_bin_dev?(content)
304
410
  end
305
411
 
306
412
  def add_post_install_message
@@ -322,6 +428,7 @@ module ReactOnRails
322
428
  GeneratorMessages.add_info(GeneratorMessages.helpful_message_after_installation(
323
429
  component_name: component_name,
324
430
  route: route,
431
+ pro: use_pro?,
325
432
  rsc: use_rsc?,
326
433
  shakapacker_just_installed: shakapacker_just_installed?
327
434
  ))
@@ -411,7 +518,16 @@ module ReactOnRails
411
518
  end
412
519
 
413
520
  def cli_exists?(command)
414
- system("which #{command} > /dev/null 2>&1")
521
+ which_command = ReactOnRails::Utils.running_on_windows? ? "where" : "which"
522
+ system(which_command, command, out: File::NULL, err: File::NULL)
523
+ end
524
+
525
+ def normalize_bin_dev_content(content)
526
+ content.gsub("\r\n", "\n").strip
527
+ end
528
+
529
+ def legacy_foreman_bin_dev?(content)
530
+ LEGACY_FOREMAN_BIN_DEV_TEMPLATES.include?(content)
415
531
  end
416
532
 
417
533
  def shakapacker_binaries_exist?
@@ -89,7 +89,7 @@ module ReactOnRails
89
89
  3. Visit http://localhost:3000/#{route}
90
90
  4. The Node Renderer will start on port 3800
91
91
 
92
- Documentation: https://www.shakacode.com/react-on-rails-pro/docs/
92
+ Documentation: https://reactonrails.com/docs/pro/
93
93
  MSG
94
94
  end
95
95
  end
@@ -78,8 +78,9 @@ module ReactOnRails
78
78
 
79
79
  Then run: bundle install
80
80
 
81
- Try Pro free! Email justin@shakacode.com for an evaluation license.
82
- For evaluation licenses or more info, see: https://www.shakacode.com/react-on-rails-pro/
81
+ No license needed for evaluation or non-production use.
82
+ Free or low-cost production licenses available for startups and small companies.
83
+ Get started: https://pro.reactonrails.com/
83
84
  MSG
84
85
  true
85
86
  end
@@ -99,7 +99,8 @@ module ReactOnRails
99
99
 
100
100
  # Append Redux-specific post-install instructions
101
101
  GeneratorMessages.add_info(
102
- GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world")
102
+ GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world",
103
+ pro: Gem.loaded_specs.key?("react_on_rails_pro"))
103
104
  )
104
105
  end
105
106
 
@@ -92,7 +92,7 @@ module ReactOnRails
92
92
  2. Visit http://localhost:3000/hello_server to see RSC in action
93
93
  3. The RSC bundle watcher will compile server components
94
94
 
95
- Documentation: https://www.shakacode.com/react-on-rails-pro/docs/rsc/
95
+ Documentation: https://reactonrails.com/docs/pro/react-server-components/
96
96
  MSG
97
97
  end
98
98
  end
@@ -35,7 +35,7 @@
35
35
  # 2. Remove precompile_hook from config/shakapacker.yml if present
36
36
  # 3. Uncomment the run_precompile_tasks call near the bottom of this file
37
37
  #
38
- # See documentation: https://www.shakacode.com/react-on-rails/docs/building-features/extensible-precompile-pattern
38
+ # See documentation: https://reactonrails.com/docs/building-features/extensible-precompile-pattern
39
39
  #
40
40
  # def run_precompile_tasks
41
41
  # require_relative "../config/environment"
@@ -1,7 +1,9 @@
1
1
  const path = require('path');
2
- const { reactOnRailsProNodeRenderer } = require('react-on-rails-pro-node-renderer');
2
+ const { reactOnRailsProNodeRenderer, parseWorkersCount } = require('react-on-rails-pro-node-renderer');
3
3
 
4
4
  const { env } = process;
5
+ const configuredWorkersCount =
6
+ parseWorkersCount(env.RENDERER_WORKERS_COUNT) ?? parseWorkersCount(env.NODE_RENDERER_CONCURRENCY);
5
7
 
6
8
  const config = {
7
9
  serverBundleCachePath: path.resolve(__dirname, '../.node-renderer-bundles'),
@@ -12,8 +14,10 @@ const config = {
12
14
  password: env.RENDERER_PASSWORD || 'devPassword',
13
15
 
14
16
  // Number of Node.js worker threads for SSR rendering
15
- // Set NODE_RENDERER_CONCURRENCY env var to override (e.g., for production tuning)
16
- workersCount: env.NODE_RENDERER_CONCURRENCY != null ? Number(env.NODE_RENDERER_CONCURRENCY) : 3,
17
+ // Set RENDERER_WORKERS_COUNT env var to override (e.g., for production tuning)
18
+ // Set to 0 for single-process mode (useful for debugging).
19
+ // Legacy fallback: NODE_RENDERER_CONCURRENCY
20
+ workersCount: configuredWorkersCount ?? 3,
17
21
 
18
22
  // If set to true, `supportModules` enables the server-bundle code to call a default set of NodeJS modules
19
23
  // that get added to the VM context: { Buffer, process, setTimeout, setInterval, clearTimeout, clearInterval }.
@@ -34,7 +38,7 @@ const config = {
34
38
  // Renderer detects a total number of CPUs on virtual hostings like Heroku or CircleCI instead
35
39
  // of CPUs number allocated for current container. This results in spawning many workers while
36
40
  // only 1-2 of them really needed.
37
- if (env.CI) {
41
+ if (env.CI && configuredWorkersCount == null) {
38
42
  config.workersCount = 2;
39
43
  }
40
44
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # See https://www.shakacode.com/react-on-rails-pro/docs/configuration/
3
+ # See https://reactonrails.com/docs/configuration/configuration-pro
4
4
  # License: Set REACT_ON_RAILS_PRO_LICENSE environment variable
5
5
  ReactOnRailsPro.configure do |config|
6
6
  config.server_renderer = "NodeRenderer"
@@ -10,7 +10,7 @@
10
10
  # - Automatic hydration on the client
11
11
  #
12
12
  # For more information, see:
13
- # https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/
13
+ # https://reactonrails.com/docs/pro/react-server-components/
14
14
 
15
15
  class HelloServerController < ApplicationController
16
16
  layout "<%= config[:layout_name] %>"
@@ -9,7 +9,7 @@
9
9
  // 4. Streaming — wrapped in <Suspense>, this component streams HTML as it resolves
10
10
  //
11
11
  // For more information, see:
12
- // https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/
12
+ // https://reactonrails.com/docs/pro/react-server-components/
13
13
 
14
14
  import React from 'react';
15
15
  import LikeButton from './LikeButton';
@@ -9,7 +9,7 @@
9
9
  // 4. Streaming — wrapped in <Suspense>, this component streams HTML as it resolves
10
10
  //
11
11
  // For more information, see:
12
- // https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/
12
+ // https://reactonrails.com/docs/pro/react-server-components/
13
13
 
14
14
  import React from 'react';
15
15
  import LikeButton from './LikeButton';
@@ -30,7 +30,7 @@
30
30
 
31
31
  <p style="margin-top: 16px;">
32
32
  <strong>Learn more:</strong>
33
- <a href="https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/">
33
+ <a href="https://reactonrails.com/docs/pro/react-server-components/">
34
34
  React Server Components Documentation
35
35
  </a>
36
36
  </p>
@@ -1,6 +1,6 @@
1
1
  // React Server Components webpack configuration
2
2
  // This creates the RSC bundle based on the server webpack config
3
- // See: https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/
3
+ // See: https://reactonrails.com/docs/pro/react-server-components/
4
4
 
5
5
  const serverWebpackModule = require('./serverWebpackConfig');
6
6
 
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactOnRails
4
+ module ConfigPathResolver
5
+ private
6
+
7
+ def resolved_package_json_path
8
+ node_modules_location = ReactOnRails.configuration.node_modules_location.to_s
9
+ return "package.json" if node_modules_location.empty? || node_modules_location == Rails.root.to_s
10
+
11
+ Rails.root.join(node_modules_location, "package.json").to_s
12
+ end
13
+
14
+ def resolved_webpack_config_path
15
+ webpack_config_candidates.find { |path| File.exist?(path) }
16
+ end
17
+
18
+ def webpack_config_candidates
19
+ candidates = []
20
+
21
+ shakapacker_config_dir = shakapacker_webpack_config_directory
22
+ if shakapacker_config_dir
23
+ candidates.concat(%w[js ts cjs mjs].flat_map do |ext|
24
+ [
25
+ File.join(shakapacker_config_dir, "webpack.config.#{ext}"),
26
+ File.join(shakapacker_config_dir, "rspack.config.#{ext}")
27
+ ]
28
+ end)
29
+ end
30
+
31
+ candidates << "config/webpack/webpack.config.js"
32
+ candidates << "config/webpack/webpack.config.ts"
33
+ candidates << "config/rspack/rspack.config.js"
34
+ candidates << "config/rspack/rspack.config.ts"
35
+ candidates.uniq
36
+ end
37
+
38
+ def shakapacker_webpack_config_directory
39
+ require "shakapacker"
40
+ path = Shakapacker.config.assets_bundler_config_path.to_s
41
+ return nil if path.empty?
42
+
43
+ directory = File.dirname(path)
44
+ rails_root = Rails.root.to_s
45
+ directory.start_with?("#{rails_root}/") ? directory.sub("#{rails_root}/", "") : directory
46
+ rescue LoadError, StandardError
47
+ nil
48
+ end
49
+ end
50
+ end
@@ -463,7 +463,7 @@ module ReactOnRails
463
463
  msg = <<~MSG
464
464
  **ERROR** ReactOnRails: auto_load_bundle is set to true, yet components_subdirectory is not configured.\
465
465
  Please set components_subdirectory to the desired directory. For more information, please see \
466
- https://www.shakacode.com/react-on-rails/docs/guides/file-system-based-automated-bundle-generation.md
466
+ https://reactonrails.com/docs/guides/file-system-based-automated-bundle-generation.md
467
467
  MSG
468
468
 
469
469
  raise ReactOnRails::Error, msg
@@ -8,6 +8,14 @@ module ReactOnRails
8
8
  # Timeout for version check operations to prevent hanging
9
9
  VERSION_CHECK_TIMEOUT = 5
10
10
 
11
+ # Env vars set after Bundler.setup that must survive with_unbundled_env.
12
+ # with_unbundled_env restores the pre-Bundler env snapshot, so any var
13
+ # set at runtime (e.g. PORT by PortSelector) is lost. We capture them
14
+ # before entering the block and pass them explicitly to system().
15
+ # This follows the same pattern used by Rails' bundle_command (railties),
16
+ # Spring's process spawning, and this codebase's own PackGenerator.
17
+ ENV_KEYS_TO_PRESERVE = %w[PORT SHAKAPACKER_DEV_SERVER_PORT].freeze
18
+
11
19
  class << self
12
20
  # Check if a process is available and usable in the current execution context
13
21
  # This accounts for bundler context where system commands might be intercepted
@@ -103,8 +111,9 @@ module ReactOnRails
103
111
  # This allows using system-installed processes even when they're not in the Gemfile
104
112
  def run_process_outside_bundle(process, args)
105
113
  if defined?(Bundler)
114
+ env_overrides = preserve_runtime_env_vars
106
115
  with_unbundled_context do
107
- system(process, *args)
116
+ system(env_overrides, process, *args)
108
117
  end
109
118
  else
110
119
  # Fallback if Bundler is not available
@@ -168,6 +177,12 @@ module ReactOnRails
168
177
  MSG
169
178
  end
170
179
 
180
+ def preserve_runtime_env_vars
181
+ ENV_KEYS_TO_PRESERVE.each_with_object({}) do |key, hash|
182
+ hash[key] = ENV[key] if ENV[key]
183
+ end
184
+ end
185
+
171
186
  def valid_procfile_path?(procfile)
172
187
  # Reject paths with shell metacharacters
173
188
  return false if procfile.match?(/[;&|`$(){}\[\]<>]/)
@@ -457,7 +457,7 @@ module ReactOnRails
457
457
  puts Rainbow(" 1. Upgrade to Shakapacker 9.4.0 or later:").cyan
458
458
  puts Rainbow(" bundle update shakapacker").cyan.bold
459
459
  puts Rainbow(" 2. Or switch to a script-based hook with a self-guard.").cyan
460
- puts Rainbow(" See: https://www.shakacode.com/react-on-rails/docs/building-features/process-managers").cyan
460
+ puts Rainbow(" See: https://reactonrails.com/docs/building-features/process-managers").cyan
461
461
  puts ""
462
462
  end
463
463
  # rubocop:enable Metrics/AbcSize
@@ -889,7 +889,7 @@ module ReactOnRails
889
889
  #{Rainbow('📖 DOCUMENTATION:').cyan.bold}
890
890
  #{Rainbow('•').yellow} #{Rainbow('Testing & dev server guide:').white} #{Rainbow('docs/oss/building-features/dev-server-and-testing.md').green}
891
891
  #{Rainbow('•').yellow} #{Rainbow('Testing configuration:').white} #{Rainbow('docs/oss/building-features/testing-configuration.md').green}
892
- #{Rainbow('•').yellow} #{Rainbow('Full docs:').white} #{Rainbow('https://www.shakacode.com/react-on-rails/docs/').cyan.underline}
892
+ #{Rainbow('•').yellow} #{Rainbow('Full docs:').white} #{Rainbow('https://reactonrails.com/docs/').cyan.underline}
893
893
  TROUBLESHOOTING
894
894
  end
895
895
  # rubocop:enable Metrics/AbcSize