react_on_rails 16.4.0.rc.8 → 16.4.0.rc.9

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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/lib/generators/react_on_rails/base_generator.rb +58 -27
  4. data/lib/generators/react_on_rails/generator_helper.rb +17 -9
  5. data/lib/generators/react_on_rails/generator_messages.rb +2 -0
  6. data/lib/generators/react_on_rails/install_generator.rb +19 -17
  7. data/lib/generators/react_on_rails/js_dependency_manager.rb +24 -20
  8. data/lib/generators/react_on_rails/pro_generator.rb +2 -2
  9. data/lib/generators/react_on_rails/pro_setup.rb +224 -68
  10. data/lib/generators/react_on_rails/rsc_generator.rb +2 -2
  11. data/lib/generators/react_on_rails/rsc_setup.rb +29 -30
  12. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +14 -10
  13. data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml.tt +9 -2
  14. data/lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb +9 -7
  15. data/lib/generators/react_on_rails/templates/dev_tests/spec/spec_helper.rb +2 -0
  16. data/lib/react_on_rails/dev/server_manager.rb +128 -3
  17. data/lib/react_on_rails/doctor.rb +744 -63
  18. data/lib/react_on_rails/helper.rb +1 -0
  19. data/lib/react_on_rails/test_helper/dev_assets_detector.rb +242 -0
  20. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +22 -9
  21. data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +44 -14
  22. data/lib/react_on_rails/test_helper.rb +2 -1
  23. data/lib/react_on_rails/utils.rb +10 -11
  24. data/lib/react_on_rails/version.rb +1 -1
  25. data/lib/react_on_rails/version_checker.rb +39 -9
  26. data/lib/react_on_rails.rb +1 -0
  27. data/rakelib/shakapacker_examples.rake +6 -0
  28. data/rakelib/update_changelog.rake +26 -1
  29. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8836b6e37dab21e6ee52f045e1f1dbb0ddce044107ce4ff6b48724ac57003bb9
4
- data.tar.gz: 3deef582db0eccf9d692813848f8dc0e1f7c610f819497bb563fb6de0b5b2091
3
+ metadata.gz: bdb10a9ed4626714e8eb70c05076bed77f57d4a7470a6a4e506505ee7e408c7b
4
+ data.tar.gz: 1e7050122dc2c9feb0a2da0bc4152fd450a31cbc51a6229486345eed3dd08dae
5
5
  SHA512:
6
- metadata.gz: 38982dfff467e79045d3c6017a991f8dedac9c17abee867cb55197e2514cbe238317ec99ef89e5ad0c258a7d306bf8325ea1266926ae85a98111af1f759023fb
7
- data.tar.gz: 124b251b8a0ca66b4f38a8d2990012690be96408c768a4f1081ad43f87c6d73b525a5bfd2de56d023a138288a28f5dbf6a6f988bdcbab8dd8bf7f1e2ea585be7
6
+ metadata.gz: fa093cb5e5ac6ac0c6b69fae0de4e998e0e90b56b71c8290e421cc553bdd6a4748afafffd4cdbe8aa56f95f3fa14956eab1cf4f08b7c38cd5d29d5e3798ab0d0
7
+ data.tar.gz: 4b00fb4d7606b6276f1cc23b3e7766c74b3cc4ba58b3f4e9162918714dbc9a400f3f470c7d1ed1c100678179abc11aa3fa6f94a75a6861e4e926fd796c989976
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- react_on_rails (16.4.0.rc.8)
4
+ react_on_rails (16.4.0.rc.9)
5
5
  addressable
6
6
  connection_pool
7
7
  execjs (~> 2.5)
@@ -104,7 +104,7 @@ module ReactOnRails
104
104
  end
105
105
 
106
106
  def copy_webpack_config
107
- puts "Adding #{using_rspack? ? 'Rspack' : 'Webpack'} config"
107
+ say "Adding #{using_rspack? ? 'Rspack' : 'Webpack'} config"
108
108
  base_path = "base/base"
109
109
  base_files = %w[babel.config.js
110
110
  config/webpack/clientWebpackConfig.js
@@ -130,12 +130,12 @@ module ReactOnRails
130
130
  config = "config/shakapacker.yml"
131
131
 
132
132
  if options.shakapacker_just_installed?
133
- puts "Replacing Shakapacker default config with React on Rails version"
133
+ say "Replacing Shakapacker default config with React on Rails version"
134
134
  # Shakapacker's installer just created this file from scratch (no pre-existing config).
135
135
  # Safe to overwrite silently with RoR's version-aware template (e.g., private_output_path).
136
136
  template("#{base_path}#{config}.tt", config, force: true)
137
137
  else
138
- puts "Adding Shakapacker #{ReactOnRails::PackerUtils.shakapacker_version} config"
138
+ say "Adding Shakapacker #{ReactOnRails::PackerUtils.shakapacker_version} config"
139
139
  # Thor handles the conflict: prompts user interactively, or respects --force/--skip flags.
140
140
  template("#{base_path}#{config}.tt", config)
141
141
  end
@@ -176,25 +176,42 @@ module ReactOnRails
176
176
  end
177
177
 
178
178
  def append_to_spec_rails_helper
179
- rails_helper = File.join(destination_root, "spec/rails_helper.rb")
180
- if File.exist?(rails_helper)
181
- add_configure_rspec_to_compile_assets(rails_helper)
182
- else
183
- spec_helper = File.join(destination_root, "spec/spec_helper.rb")
184
- add_configure_rspec_to_compile_assets(spec_helper) if File.exist?(spec_helper)
185
- end
179
+ rspec_helper = preferred_rspec_helper_file
180
+ add_configure_rspec_to_compile_assets(rspec_helper) if rspec_helper
181
+
182
+ test_helper = File.join(destination_root, "test/test_helper.rb")
183
+ add_configure_minitest_to_compile_assets(test_helper) if File.exist?(test_helper)
186
184
  end
187
185
 
188
186
  CONFIGURE_RSPEC_TO_COMPILE_ASSETS = <<-STR.strip_heredoc
189
187
  RSpec.configure do |config|
190
188
  # Ensure that if we are running js tests, we are using latest webpack assets
191
189
  # This will use the defaults of :js and :server_rendering meta tags
190
+ # Requires config.build_test_command in config/initializers/react_on_rails.rb.
191
+ # This is the default setup for React on Rails generated apps.
192
192
  ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
193
193
  end
194
194
  STR
195
195
 
196
+ CONFIGURE_MINITEST_TO_COMPILE_ASSETS = <<-STR.strip_heredoc
197
+ # Ensure that tests run against fresh webpack assets.
198
+ ActiveSupport::TestCase.setup do
199
+ ReactOnRails::TestHelper.ensure_assets_compiled
200
+ end
201
+ STR
202
+
196
203
  private
197
204
 
205
+ def preferred_rspec_helper_file
206
+ rails_helper = File.join(destination_root, "spec/rails_helper.rb")
207
+ return rails_helper if File.exist?(rails_helper)
208
+
209
+ spec_helper = File.join(destination_root, "spec/spec_helper.rb")
210
+ return spec_helper if File.exist?(spec_helper)
211
+
212
+ nil
213
+ end
214
+
198
215
  def copy_webpack_main_config(base_path, config)
199
216
  webpack_config_path = bundler_main_config_path
200
217
 
@@ -206,12 +223,12 @@ module ReactOnRails
206
223
  # Remove the file first to avoid conflict prompt, then recreate it
207
224
  remove_file(webpack_config_path, verbose: false)
208
225
  # Show what we're doing
209
- puts " #{set_color('replace', :green)} #{webpack_config_path} " \
210
- "(auto-upgrading from standard Shakapacker to React on Rails config)"
226
+ say_status :replace,
227
+ "#{webpack_config_path} (auto-upgrading from standard Shakapacker to React on Rails config)",
228
+ :green
211
229
  template("#{base_path}/config/webpack/webpack.config.js.tt", webpack_config_path, config)
212
230
  elsif react_on_rails_config?(existing_content)
213
- puts " #{set_color('identical', :blue)} #{webpack_config_path} " \
214
- "(already React on Rails compatible)"
231
+ say_status :identical, "#{webpack_config_path} (already React on Rails compatible)", :blue
215
232
  # Skip - don't need to do anything
216
233
  else
217
234
  handle_custom_webpack_config(base_path, config, webpack_config_path)
@@ -226,23 +243,25 @@ module ReactOnRails
226
243
  # Custom config - ask user
227
244
  config_file_name = File.basename(webpack_config_path)
228
245
  bundler_name = using_rspack? ? "rspack" : "webpack"
229
- puts "\n#{set_color('NOTICE:', :yellow)} Your #{config_file_name} appears to be customized."
230
- puts "React on Rails needs to replace it with an environment-specific loader."
231
- puts "Your current config will be backed up to #{config_file_name}.backup"
246
+ say ""
247
+ say_status :notice, "Your #{config_file_name} appears to be customized.", :yellow
248
+ say "React on Rails needs to replace it with an environment-specific loader."
249
+ say "Your current config will be backed up to #{config_file_name}.backup"
232
250
 
233
251
  if yes?("Replace #{config_file_name} with React on Rails version? (Y/n)")
234
252
  # Create backup
235
253
  backup_path = "#{webpack_config_path}.backup"
236
254
  if File.exist?(webpack_config_path)
237
255
  FileUtils.cp(webpack_config_path, backup_path)
238
- puts " #{set_color('create', :green)} #{backup_path} (backup of your custom config)"
256
+ say_status :create, "#{backup_path} (backup of your custom config)", :green
239
257
  end
240
258
 
241
259
  template("#{base_path}/config/webpack/webpack.config.js.tt", webpack_config_path, config)
242
260
  else
243
- puts " #{set_color('skip', :yellow)} #{webpack_config_path}"
244
- puts " #{set_color('WARNING:', :red)} React on Rails may not work correctly " \
245
- "without the environment-specific #{bundler_name} config"
261
+ say_status :skip, webpack_config_path, :yellow
262
+ say_status :warning,
263
+ "React on Rails may not work correctly without the environment-specific #{bundler_name} config",
264
+ :red
246
265
  end
247
266
  end
248
267
 
@@ -359,15 +378,27 @@ module ReactOnRails
359
378
  end
360
379
 
361
380
  def add_configure_rspec_to_compile_assets(helper_file)
362
- search_str = "RSpec.configure do |config|"
363
- gsub_file(helper_file, search_str, CONFIGURE_RSPEC_TO_COMPILE_ASSETS)
381
+ content = File.read(helper_file)
382
+ return if content.match?(/^\s*[^#\s][^#]*ReactOnRails::TestHelper\.configure_rspec_to_compile_assets/)
383
+
384
+ updated_content = content.sub("RSpec.configure do |config|", CONFIGURE_RSPEC_TO_COMPILE_ASSETS)
385
+ return if updated_content == content
386
+
387
+ File.write(helper_file, updated_content)
388
+ end
389
+
390
+ def add_configure_minitest_to_compile_assets(helper_file)
391
+ content = File.read(helper_file)
392
+ return if content.match?(/^\s*[^#\s][^#]*ReactOnRails::TestHelper\.ensure_assets_compiled/)
393
+
394
+ append_to_file(helper_file, "\n\n#{CONFIGURE_MINITEST_TO_COMPILE_ASSETS}\n")
364
395
  end
365
396
 
366
397
  def configure_rspack_in_shakapacker
367
398
  shakapacker_config_path = "config/shakapacker.yml"
368
399
  return unless File.exist?(shakapacker_config_path)
369
400
 
370
- puts Rainbow("🔧 Configuring Shakapacker for Rspack...").yellow
401
+ say "🔧 Configuring Shakapacker for Rspack...", :yellow
371
402
 
372
403
  # Use regex replacement to preserve file structure (comments, anchors, aliases)
373
404
  # This replaces ALL occurrences of assets_bundler, not just in default section
@@ -385,7 +416,7 @@ module ReactOnRails
385
416
  '\1swc\2'
386
417
  )
387
418
 
388
- puts Rainbow("✅ Updated shakapacker.yml for Rspack").green
419
+ say "✅ Updated shakapacker.yml for Rspack", :green
389
420
  end
390
421
 
391
422
  def configure_precompile_hook_in_shakapacker
@@ -406,7 +437,7 @@ module ReactOnRails
406
437
  /^(\s*)#\s*precompile_hook:\s*~\s*$/,
407
438
  "\\1precompile_hook: 'bin/shakapacker-precompile-hook'"
408
439
 
409
- puts Rainbow("✅ Configured precompile_hook in shakapacker.yml").green
440
+ say "✅ Configured precompile_hook in shakapacker.yml", :green
410
441
  end
411
442
 
412
443
  def configure_private_output_path_in_shakapacker
@@ -446,7 +477,7 @@ module ReactOnRails
446
477
 
447
478
  return unless File.read(shakapacker_config_path).match?(/^\s+private_output_path:\s*ssr-generated/)
448
479
 
449
- puts Rainbow("✅ Configured private_output_path in shakapacker.yml").green
480
+ say "✅ Configured private_output_path in shakapacker.yml", :green
450
481
  end
451
482
  end
452
483
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rainbow"
4
3
  require "json"
5
4
 
5
+ # rubocop:disable Metrics/ModuleLength
6
6
  module GeneratorHelper
7
7
  def package_json
8
8
  # Lazy load package_json gem only when actually needed for dependency management
@@ -10,12 +10,13 @@ module GeneratorHelper
10
10
  require "package_json" unless defined?(PackageJson)
11
11
  @package_json ||= PackageJson.read
12
12
  rescue LoadError
13
- puts "Warning: package_json gem not available. This is expected before Shakapacker installation."
14
- puts "Dependencies will be installed using the default package manager after Shakapacker setup."
13
+ say_status :warning, "package_json gem not available. This is expected before Shakapacker installation.", :yellow
14
+ say_status :warning, "Dependencies will be installed using the default package manager after Shakapacker setup.",
15
+ :yellow
15
16
  nil
16
17
  rescue StandardError => e
17
- puts "Warning: Could not read package.json: #{e.message}"
18
- puts "This is normal before Shakapacker creates the package.json file."
18
+ say_status :warning, "Could not read package.json: #{e.message}", :yellow
19
+ say_status :warning, "This is normal before Shakapacker creates the package.json file.", :yellow
19
20
  nil
20
21
  end
21
22
 
@@ -32,8 +33,8 @@ module GeneratorHelper
32
33
  end
33
34
  true
34
35
  rescue StandardError => e
35
- puts "Warning: Could not add packages via package_json gem: #{e.message}"
36
- puts "Will fall back to direct npm commands."
36
+ say_status :warning, "Could not add packages via package_json gem: #{e.message}", :yellow
37
+ say_status :warning, "Will fall back to direct npm commands.", :yellow
37
38
  false
38
39
  end
39
40
  end
@@ -93,9 +94,11 @@ module GeneratorHelper
93
94
  end
94
95
 
95
96
  def print_generator_messages
97
+ # GeneratorMessages stores pre-colored strings, so we strip ANSI manually for --no-color output.
98
+ no_color = !shell.is_a?(Thor::Shell::Color)
96
99
  GeneratorMessages.messages.each do |message|
97
- puts message
98
- puts "" # Blank line after each message for readability
100
+ say(no_color ? message.to_s.gsub(/\e\[[0-9;]*m/, "") : message)
101
+ say "" # Blank line after each message for readability
99
102
  end
100
103
  end
101
104
 
@@ -129,6 +132,10 @@ module GeneratorHelper
129
132
  @pro_gem_installed = Gem.loaded_specs.key?("react_on_rails_pro") || gem_in_lockfile?("react_on_rails_pro")
130
133
  end
131
134
 
135
+ def mark_pro_gem_installed!
136
+ @pro_gem_installed = true
137
+ end
138
+
132
139
  # Check if Pro features should be enabled
133
140
  # Returns true if --pro flag is set OR --rsc flag is set (RSC implies Pro)
134
141
  #
@@ -347,3 +354,4 @@ module GeneratorHelper
347
354
  config.dig("default", "assets_bundler") == "rspack"
348
355
  end
349
356
  end
357
+ # rubocop:enable Metrics/ModuleLength
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rainbow"
4
+
3
5
  module GeneratorMessages
4
6
  class << self
5
7
  def output
@@ -187,8 +187,10 @@ module ReactOnRails
187
187
  # js(.coffee) are not checked by this method, but instead produce warning messages
188
188
  # and allow the build to continue
189
189
  def installation_prerequisites_met?
190
- !(missing_node? || missing_package_manager? || missing_pro_gem? ||
191
- ReactOnRails::GitUtils.uncommitted_changes?(GeneratorMessages))
190
+ # Check uncommitted_changes? before missing_pro_gem? so that
191
+ # auto-install does not mutate the Gemfile on a dirty working tree.
192
+ !(missing_node? || missing_package_manager? ||
193
+ ReactOnRails::GitUtils.uncommitted_changes?(GeneratorMessages) || missing_pro_gem?)
192
194
  end
193
195
 
194
196
  def missing_node?
@@ -358,15 +360,15 @@ module ReactOnRails
358
360
  end
359
361
 
360
362
  def print_shakapacker_setup_banner
361
- puts Rainbow("\n#{'=' * 80}").cyan
362
- puts Rainbow("🔧 SHAKAPACKER SETUP").cyan.bold
363
- puts Rainbow("=" * 80).cyan
363
+ say "\n#{set_color('=' * 80, :cyan)}"
364
+ say set_color("🔧 SHAKAPACKER SETUP", :cyan, :bold)
365
+ say set_color("=" * 80, :cyan)
364
366
  end
365
367
 
366
368
  def ensure_shakapacker_in_gemfile
367
369
  return if shakapacker_in_gemfile?
368
370
 
369
- puts Rainbow("📝 Adding Shakapacker to Gemfile...").yellow
371
+ say "📝 Adding Shakapacker to Gemfile...", :yellow
370
372
  # Use with_unbundled_env to prevent inheriting BUNDLE_GEMFILE from parent process
371
373
  # See: https://github.com/shakacode/react_on_rails/issues/2287
372
374
  success = Bundler.with_unbundled_env { system("bundle add shakapacker --strict") }
@@ -376,11 +378,11 @@ module ReactOnRails
376
378
  end
377
379
 
378
380
  def install_shakapacker
379
- puts Rainbow("⚙️ Installing Shakapacker (required for webpack integration)...").yellow
381
+ say "⚙️ Installing Shakapacker (required for webpack integration)...", :yellow
380
382
 
381
383
  # First run bundle install to make shakapacker available
382
384
  # Use with_unbundled_env to prevent inheriting BUNDLE_GEMFILE from parent process
383
- puts Rainbow("📦 Running bundle install...").yellow
385
+ say "📦 Running bundle install...", :yellow
384
386
  bundle_success = Bundler.with_unbundled_env { system("bundle install") }
385
387
  unless bundle_success
386
388
  handle_shakapacker_install_error
@@ -404,10 +406,10 @@ module ReactOnRails
404
406
  end
405
407
 
406
408
  def finalize_shakapacker_setup(yml_content_before)
407
- puts Rainbow("✅ Shakapacker installed successfully!").green
408
- puts Rainbow("=" * 80).cyan
409
- puts Rainbow("🚀 CONTINUING WITH REACT ON RAILS SETUP").cyan.bold
410
- puts "#{Rainbow('=' * 80).cyan}\n"
409
+ say "✅ Shakapacker installed successfully!", :green
410
+ say "=" * 80, :cyan
411
+ say set_color("🚀 CONTINUING WITH REACT ON RAILS SETUP", :cyan, :bold)
412
+ say "#{'=' * 80}\n", :cyan
411
413
 
412
414
  yml_content_after = File.exist?(SHAKAPACKER_YML_PATH) ? File.read(SHAKAPACKER_YML_PATH) : nil
413
415
 
@@ -501,7 +503,7 @@ module ReactOnRails
501
503
  return
502
504
  end
503
505
 
504
- puts Rainbow("📝 Installing TypeScript dependencies...").yellow
506
+ say "📝 Installing TypeScript dependencies...", :yellow
505
507
  # Delegate to shared module for consistent dependency management
506
508
  add_typescript_dependencies
507
509
  end
@@ -512,7 +514,7 @@ module ReactOnRails
512
514
  return
513
515
  end
514
516
 
515
- puts Rainbow("📝 Creating CSS module type definitions...").yellow
517
+ say "📝 Creating CSS module type definitions...", :yellow
516
518
 
517
519
  # Ensure the types directory exists
518
520
  FileUtils.mkdir_p("app/javascript/types")
@@ -536,7 +538,7 @@ module ReactOnRails
536
538
  TS
537
539
 
538
540
  File.write("app/javascript/types/css-modules.d.ts", css_module_types_content)
539
- puts Rainbow("✅ Created CSS module type definitions").green
541
+ say "✅ Created CSS module type definitions", :green
540
542
  end
541
543
 
542
544
  def create_typescript_config
@@ -546,7 +548,7 @@ module ReactOnRails
546
548
  end
547
549
 
548
550
  if File.exist?("tsconfig.json")
549
- puts Rainbow("⚠️ tsconfig.json already exists, skipping creation").yellow
551
+ say "⚠️ tsconfig.json already exists, skipping creation", :yellow
550
552
  return
551
553
  end
552
554
 
@@ -572,7 +574,7 @@ module ReactOnRails
572
574
  }
573
575
 
574
576
  File.write("tsconfig.json", JSON.pretty_generate(tsconfig_content))
575
- puts Rainbow("✅ Created tsconfig.json").green
577
+ say "✅ Created tsconfig.json", :green
576
578
  end
577
579
  end
578
580
  # rubocop:enable Metrics/ClassLength
@@ -186,13 +186,15 @@ module ReactOnRails
186
186
 
187
187
  "react-on-rails@#{npm_version}"
188
188
  else
189
- puts "WARNING: Unrecognized version format #{ReactOnRails::VERSION}. " \
190
- "Adding the latest react-on-rails NPM module. " \
191
- "Double check this is correct in package.json"
189
+ say_status :warning,
190
+ "Unrecognized version format #{ReactOnRails::VERSION}. " \
191
+ "Adding the latest react-on-rails NPM module. " \
192
+ "Double check this is correct in package.json",
193
+ :yellow
192
194
  "react-on-rails"
193
195
  end
194
196
 
195
- puts "Installing React on Rails package..."
197
+ say "Installing React on Rails package..."
196
198
  return if add_package(react_on_rails_pkg)
197
199
 
198
200
  GeneratorMessages.add_warning(<<~MSG.strip)
@@ -211,7 +213,7 @@ module ReactOnRails
211
213
  end
212
214
 
213
215
  def add_react_dependencies
214
- puts "Installing React dependencies..."
216
+ say "Installing React dependencies..."
215
217
 
216
218
  # RSC requires React 19.0.x specifically (not 19.1.x or later)
217
219
  # Pin to ~19.0.4 to allow patch updates while staying within 19.0.x
@@ -239,7 +241,7 @@ module ReactOnRails
239
241
  end
240
242
 
241
243
  def add_css_dependencies
242
- puts "Installing CSS handling dependencies..."
244
+ say "Installing CSS handling dependencies..."
243
245
  return if add_packages(CSS_DEPENDENCIES)
244
246
 
245
247
  GeneratorMessages.add_warning(<<~MSG.strip)
@@ -258,7 +260,7 @@ module ReactOnRails
258
260
  end
259
261
 
260
262
  def add_rspack_dependencies
261
- puts "Installing Rspack core dependencies..."
263
+ say "Installing Rspack core dependencies..."
262
264
  return if add_packages(RSPACK_DEPENDENCIES)
263
265
 
264
266
  GeneratorMessages.add_warning(<<~MSG.strip)
@@ -277,7 +279,7 @@ module ReactOnRails
277
279
  end
278
280
 
279
281
  def add_swc_dependencies
280
- puts "Installing SWC transpiler dependencies (20x faster than Babel)..."
282
+ say "Installing SWC transpiler dependencies (20x faster than Babel)..."
281
283
  return if add_packages(SWC_DEPENDENCIES, dev: true)
282
284
 
283
285
  GeneratorMessages.add_warning(<<~MSG.strip)
@@ -297,7 +299,7 @@ module ReactOnRails
297
299
  end
298
300
 
299
301
  def add_babel_react_dependencies
300
- puts "Installing Babel React preset dependency..."
302
+ say "Installing Babel React preset dependency..."
301
303
  return if add_packages(BABEL_REACT_DEPENDENCIES, dev: true)
302
304
 
303
305
  GeneratorMessages.add_warning(<<~MSG.strip)
@@ -316,7 +318,7 @@ module ReactOnRails
316
318
  end
317
319
 
318
320
  def add_typescript_dependencies
319
- puts "Installing TypeScript dependencies..."
321
+ say "Installing TypeScript dependencies..."
320
322
  return if add_packages(TYPESCRIPT_DEPENDENCIES, dev: true)
321
323
 
322
324
  GeneratorMessages.add_warning(<<~MSG.strip)
@@ -335,7 +337,7 @@ module ReactOnRails
335
337
  end
336
338
 
337
339
  def add_pro_dependencies
338
- puts "Installing React on Rails Pro dependencies..."
340
+ say "Installing React on Rails Pro dependencies..."
339
341
 
340
342
  # When upgrading from base React on Rails to Pro, remove the base package first
341
343
  # Pro package includes all base functionality, so having both causes validation errors
@@ -364,19 +366,21 @@ module ReactOnRails
364
366
 
365
367
  # Returns Pro package names with version suffix matching the gem version.
366
368
  # Uses VersionSyntaxConverter to handle Ruby->npm format conversion.
367
- # Falls back to unversioned package names if version can't be determined.
369
+ # Falls back to ReactOnRails::VERSION since Pro and base gems share the same version.
368
370
  def pro_packages_with_version
369
- return PRO_DEPENDENCIES unless defined?(ReactOnRailsPro::VERSION)
370
-
371
- npm_version = ReactOnRails::VersionSyntaxConverter.new.rubygem_to_npm(ReactOnRailsPro::VERSION)
371
+ # Prefer Pro gem version if loaded; fall back to base gem version (same by policy).
372
+ # After auto-install via bundle add, the Pro gem isn't loaded in the current process,
373
+ # so ReactOnRailsPro::VERSION won't be defined. The base gem version is always available.
374
+ gem_version = defined?(ReactOnRailsPro::VERSION) ? ReactOnRailsPro::VERSION : ReactOnRails::VERSION
375
+ npm_version = ReactOnRails::VersionSyntaxConverter.new.rubygem_to_npm(gem_version)
372
376
  PRO_DEPENDENCIES.map { |pkg| "#{pkg}@#{npm_version}" }
373
377
  rescue StandardError
374
- puts "WARNING: Could not determine Pro package version. Installing latest."
378
+ say_status :warning, "Could not determine Pro package version. Installing latest.", :yellow
375
379
  PRO_DEPENDENCIES
376
380
  end
377
381
 
378
382
  def add_rsc_dependencies
379
- puts "Installing React Server Components dependencies..."
383
+ say "Installing React Server Components dependencies..."
380
384
  return if add_packages(RSC_DEPENDENCIES)
381
385
 
382
386
  GeneratorMessages.add_warning(<<~MSG.strip)
@@ -401,9 +405,9 @@ module ReactOnRails
401
405
  dependencies = pj.fetch("dependencies", {})
402
406
  return unless dependencies.key?("react-on-rails")
403
407
 
404
- puts "Removing base 'react-on-rails' package (Pro package includes all base functionality)..."
408
+ say "Removing base 'react-on-rails' package (Pro package includes all base functionality)..."
405
409
  pj.manager.remove(["react-on-rails"])
406
- puts "✅ Removed 'react-on-rails' package"
410
+ say "✅ Removed 'react-on-rails' package"
407
411
  rescue StandardError => e
408
412
  GeneratorMessages.add_warning(<<~MSG.strip)
409
413
  ⚠️ Could not remove base 'react-on-rails' package: #{e.message}
@@ -414,7 +418,7 @@ module ReactOnRails
414
418
  end
415
419
 
416
420
  def add_dev_dependencies
417
- puts "Installing development dependencies..."
421
+ say "Installing development dependencies..."
418
422
 
419
423
  # Use Rspack-specific dev dependencies if rspack is configured
420
424
  dev_deps = using_rspack? ? RSPACK_DEV_DEPENDENCIES : DEV_DEPENDENCIES
@@ -70,9 +70,9 @@ module ReactOnRails
70
70
  end
71
71
 
72
72
  def add_pro_npm_dependencies
73
- puts Rainbow("📝 Adding Pro npm dependencies...").yellow
73
+ say "📝 Adding Pro npm dependencies...", :yellow
74
74
  add_pro_dependencies
75
- puts Rainbow("✅ Pro npm dependencies added").green
75
+ say "✅ Pro npm dependencies added", :green
76
76
  end
77
77
 
78
78
  def print_success_message