react_on_rails 16.2.0.beta.8 → 16.2.0.beta.11

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/CHANGELOG.md +19 -13
  3. data/CLAUDE.md +136 -5
  4. data/CONTRIBUTING.md +3 -1
  5. data/Gemfile.lock +1 -1
  6. data/Steepfile +4 -0
  7. data/analysis/rake-task-duplicate-analysis.md +149 -0
  8. data/bin/ci-run-failed-specs +6 -4
  9. data/bin/ci-switch-config +4 -3
  10. data/knip.ts +1 -1
  11. data/lib/generators/react_on_rails/base_generator.rb +5 -119
  12. data/lib/generators/react_on_rails/generator_helper.rb +29 -0
  13. data/lib/generators/react_on_rails/install_generator.rb +5 -180
  14. data/lib/generators/react_on_rails/js_dependency_manager.rb +354 -0
  15. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +19 -0
  16. data/lib/generators/react_on_rails/templates/base/base/config/{shakapacker.yml → shakapacker.yml.tt} +18 -2
  17. data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +38 -4
  18. data/lib/react_on_rails/configuration.rb +82 -8
  19. data/lib/react_on_rails/dev/pack_generator.rb +1 -0
  20. data/lib/react_on_rails/dev/server_manager.rb +1 -0
  21. data/lib/react_on_rails/doctor.rb +94 -4
  22. data/lib/react_on_rails/engine.rb +2 -5
  23. data/lib/react_on_rails/system_checker.rb +7 -4
  24. data/lib/react_on_rails/utils.rb +54 -0
  25. data/lib/react_on_rails/version.rb +1 -1
  26. data/react_on_rails_pro/Gemfile.lock +3 -3
  27. data/react_on_rails_pro/lib/react_on_rails_pro/version.rb +1 -1
  28. data/react_on_rails_pro/package.json +1 -1
  29. data/react_on_rails_pro/spec/dummy/Gemfile.lock +3 -3
  30. data/react_on_rails_pro/spec/dummy/bin/shakapacker-precompile-hook +19 -0
  31. data/react_on_rails_pro/spec/dummy/config/shakapacker.yml +5 -0
  32. data/sig/react_on_rails/dev/file_manager.rbs +15 -0
  33. data/sig/react_on_rails/dev/pack_generator.rbs +19 -0
  34. data/sig/react_on_rails/dev/process_manager.rbs +22 -0
  35. data/sig/react_on_rails/dev/server_manager.rbs +39 -0
  36. data/sig/react_on_rails/generators/js_dependency_manager.rbs +123 -0
  37. metadata +11 -3
@@ -44,19 +44,53 @@ const configureServer = () => {
44
44
  };
45
45
  serverWebpackConfig.plugins.unshift(new bundler.optimize.LimitChunkCountPlugin({ maxChunks: 1 }));
46
46
 
47
- // Custom output for the server-bundle that matches the config in
48
- // config/initializers/react_on_rails.rb
49
- // Server bundles are output to a private directory (not public) for security
47
+ // Custom output for the server-bundle
48
+ <% if shakapacker_version_9_or_higher? -%>
49
+ // Using Shakapacker 9.0+ privateOutputPath for automatic sync with shakapacker.yml
50
+ // This eliminates manual path configuration and keeps configs in sync.
51
+ // Falls back to hardcoded path if private_output_path is not configured.
52
+ const serverBundleOutputPath = config.privateOutputPath ||
53
+ require('path').resolve(__dirname, '../../ssr-generated');
54
+ <% else -%>
55
+ // Using hardcoded path (Shakapacker < 9.0)
56
+ // For Shakapacker 9.0+, consider using config.privateOutputPath instead
57
+ // to automatically sync with shakapacker.yml private_output_path.
58
+ const serverBundleOutputPath = require('path').resolve(__dirname, '../../ssr-generated');
59
+ <% end -%>
60
+
50
61
  serverWebpackConfig.output = {
51
62
  filename: 'server-bundle.js',
52
63
  globalObject: 'this',
53
64
  // If using the React on Rails Pro node server renderer, uncomment the next line
54
65
  // libraryTarget: 'commonjs2',
55
- path: require('path').resolve(__dirname, '../../ssr-generated'),
66
+ path: serverBundleOutputPath,
56
67
  // No publicPath needed since server bundles are not served via web
57
68
  // https://webpack.js.org/configuration/output/#outputglobalobject
58
69
  };
59
70
 
71
+ // Validate server bundle output path configuration
72
+ <% if shakapacker_version_9_or_higher? -%>
73
+ // For Shakapacker 9.0+, verify privateOutputPath is configured in shakapacker.yml
74
+ if (!config.privateOutputPath) {
75
+ console.warn('⚠️ Shakapacker 9.0+ detected but private_output_path not configured in shakapacker.yml');
76
+ console.warn(' Add to config/shakapacker.yml:');
77
+ console.warn(' private_output_path: ssr-generated');
78
+ console.warn(' Run: rails react_on_rails:doctor to validate your configuration');
79
+ }
80
+ <% else -%>
81
+ // For Shakapacker < 9.0, verify hardcoded path syncs with Rails config
82
+ // 1. Ensure config/initializers/react_on_rails.rb has: config.server_bundle_output_path = "ssr-generated"
83
+ // 2. Run: rails react_on_rails:doctor to verify configuration
84
+ const fs = require('fs');
85
+ if (!fs.existsSync(serverBundleOutputPath)) {
86
+ console.warn(`⚠️ Server bundle output directory does not exist: ${serverBundleOutputPath}`);
87
+ console.warn(' It will be created during build, but ensure React on Rails is configured:');
88
+ console.warn(' config.server_bundle_output_path = "ssr-generated" in config/initializers/react_on_rails.rb');
89
+ console.warn(' Run: rails react_on_rails:doctor to validate your configuration');
90
+ }
91
+ <% end -%>
92
+
93
+
60
94
  // Don't hash the server bundle b/c would conflict with the client manifest
61
95
  // And no need for the MiniCssExtractPlugin
62
96
  serverWebpackConfig.plugins = serverWebpackConfig.plugins.filter(
@@ -1,5 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/enumerable"
4
+ require "active_support/core_ext/object/blank"
5
+
6
+ # Polyfill for compact_blank (added in Rails 6.1) to support Rails 5.2-6.0
7
+ unless [].respond_to?(:compact_blank)
8
+ module Enumerable
9
+ def compact_blank
10
+ reject(&:blank?)
11
+ end
12
+ end
13
+
14
+ class Array
15
+ def compact_blank
16
+ reject(&:blank?)
17
+ end
18
+ end
19
+ end
20
+
3
21
  # rubocop:disable Metrics/ClassLength
4
22
 
5
23
  module ReactOnRails
@@ -10,6 +28,7 @@ module ReactOnRails
10
28
 
11
29
  DEFAULT_GENERATED_ASSETS_DIR = File.join(%w[public webpack], Rails.env).freeze
12
30
  DEFAULT_COMPONENT_REGISTRY_TIMEOUT = 5000
31
+ DEFAULT_SERVER_BUNDLE_OUTPUT_PATH = "ssr-generated"
13
32
 
14
33
  def self.configuration
15
34
  @configuration ||= Configuration.new(
@@ -46,7 +65,7 @@ module ReactOnRails
46
65
  # Set to 0 to disable the timeout and wait indefinitely for component registration.
47
66
  component_registry_timeout: DEFAULT_COMPONENT_REGISTRY_TIMEOUT,
48
67
  generated_component_packs_loading_strategy: nil,
49
- server_bundle_output_path: "ssr-generated",
68
+ server_bundle_output_path: DEFAULT_SERVER_BUNDLE_OUTPUT_PATH,
50
69
  enforce_private_server_bundles: false
51
70
  )
52
71
  end
@@ -184,6 +203,7 @@ module ReactOnRails
184
203
  check_component_registry_timeout
185
204
  validate_generated_component_packs_loading_strategy
186
205
  validate_enforce_private_server_bundles
206
+ auto_detect_server_bundle_path_from_shakapacker
187
207
  end
188
208
 
189
209
  private
@@ -257,6 +277,57 @@ module ReactOnRails
257
277
  "the public directory. Please set it to a directory outside of public."
258
278
  end
259
279
 
280
+ # Auto-detect server_bundle_output_path from Shakapacker 9.0+ private_output_path
281
+ # Checks if user explicitly set a value and warns them to use auto-detection instead
282
+ def auto_detect_server_bundle_path_from_shakapacker
283
+ # Skip if Shakapacker is not available
284
+ return unless defined?(::Shakapacker)
285
+
286
+ # Check if Shakapacker config has private_output_path method (9.0+)
287
+ return unless ::Shakapacker.config.respond_to?(:private_output_path)
288
+
289
+ # Get the private_output_path from Shakapacker
290
+ private_path = ::Shakapacker.config.private_output_path
291
+ return unless private_path
292
+
293
+ relative_path = ReactOnRails::Utils.normalize_to_relative_path(private_path)
294
+
295
+ # Check if user explicitly configured server_bundle_output_path
296
+ if server_bundle_output_path != ReactOnRails::DEFAULT_SERVER_BUNDLE_OUTPUT_PATH
297
+ warn_about_explicit_configuration(relative_path)
298
+ return
299
+ end
300
+
301
+ apply_shakapacker_private_output_path(relative_path)
302
+ rescue StandardError => e
303
+ # Fail gracefully - if auto-detection fails, keep the default
304
+ Rails.logger&.debug("ReactOnRails: Could not auto-detect server bundle path from " \
305
+ "Shakapacker: #{e.message}")
306
+ end
307
+
308
+ def warn_about_explicit_configuration(shakapacker_path)
309
+ # Normalize both paths for comparison
310
+ normalized_config = server_bundle_output_path.to_s.chomp("/")
311
+ normalized_shakapacker = shakapacker_path.to_s.chomp("/")
312
+
313
+ # Only warn if there's a mismatch
314
+ return if normalized_config == normalized_shakapacker
315
+
316
+ Rails.logger&.warn(
317
+ "ReactOnRails: server_bundle_output_path is explicitly set to '#{server_bundle_output_path}' " \
318
+ "but shakapacker.yml private_output_path is '#{shakapacker_path}'. " \
319
+ "Consider removing server_bundle_output_path from your React on Rails initializer " \
320
+ "to use the auto-detected value from shakapacker.yml."
321
+ )
322
+ end
323
+
324
+ def apply_shakapacker_private_output_path(relative_path)
325
+ self.server_bundle_output_path = relative_path
326
+
327
+ Rails.logger&.debug("ReactOnRails: Auto-detected server_bundle_output_path from " \
328
+ "shakapacker.yml private_output_path: '#{relative_path}'")
329
+ end
330
+
260
331
  def check_minimum_shakapacker_version
261
332
  ReactOnRails::PackerUtils.raise_shakapacker_version_incompatible_for_basic_pack_generation unless
262
333
  ReactOnRails::PackerUtils.supports_basic_pack_generation?
@@ -360,13 +431,16 @@ module ReactOnRails
360
431
  def ensure_webpack_generated_files_exists
361
432
  return unless webpack_generated_files.empty?
362
433
 
363
- self.webpack_generated_files = [
364
- "manifest.json",
365
- server_bundle_js_file,
366
- rsc_bundle_js_file,
367
- react_client_manifest_file,
368
- react_server_client_manifest_file
369
- ].compact_blank
434
+ files = ["manifest.json", server_bundle_js_file]
435
+
436
+ if ReactOnRails::Utils.react_on_rails_pro?
437
+ pro_config = ReactOnRailsPro.configuration
438
+ files << pro_config.rsc_bundle_js_file
439
+ files << pro_config.react_client_manifest_file
440
+ files << pro_config.react_server_client_manifest_file
441
+ end
442
+
443
+ self.webpack_generated_files = files.compact_blank
370
444
  end
371
445
 
372
446
  def configure_skip_display_none_deprecation
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "English"
4
4
  require "stringio"
5
+ require_relative "../packer_utils"
5
6
 
6
7
  module ReactOnRails
7
8
  module Dev
@@ -3,6 +3,7 @@
3
3
  require "English"
4
4
  require "open3"
5
5
  require "rainbow"
6
+ require_relative "../packer_utils"
6
7
 
7
8
  module ReactOnRails
8
9
  module Dev
@@ -667,6 +667,7 @@ module ReactOnRails
667
667
  end
668
668
  end
669
669
 
670
+ # rubocop:disable Metrics/CyclomaticComplexity
670
671
  def analyze_server_rendering_config(content)
671
672
  checker.add_info("\n🖥️ Server Rendering:")
672
673
 
@@ -678,6 +679,19 @@ module ReactOnRails
678
679
  checker.add_info(" server_bundle_js_file: server-bundle.js (default)")
679
680
  end
680
681
 
682
+ # Server bundle output path
683
+ server_bundle_path_match = content.match(/config\.server_bundle_output_path\s*=\s*["']([^"']+)["']/)
684
+ default_path = ReactOnRails::DEFAULT_SERVER_BUNDLE_OUTPUT_PATH
685
+ rails_bundle_path = server_bundle_path_match ? server_bundle_path_match[1] : default_path
686
+ checker.add_info(" server_bundle_output_path: #{rails_bundle_path}")
687
+
688
+ # Enforce private server bundles
689
+ enforce_private_match = content.match(/config\.enforce_private_server_bundles\s*=\s*([^\s\n,]+)/)
690
+ checker.add_info(" enforce_private_server_bundles: #{enforce_private_match[1]}") if enforce_private_match
691
+
692
+ # Check Shakapacker integration and provide recommendations
693
+ check_shakapacker_private_output_path(rails_bundle_path)
694
+
681
695
  # RSC bundle file (Pro feature)
682
696
  rsc_bundle_match = content.match(/config\.rsc_bundle_js_file\s*=\s*["']([^"']+)["']/)
683
697
  if rsc_bundle_match
@@ -702,9 +716,9 @@ module ReactOnRails
702
716
 
703
717
  checker.add_info(" raise_on_prerender_error: #{raise_on_error_match[1]}")
704
718
  end
705
- # rubocop:enable Metrics/AbcSize
719
+ # rubocop:enable Metrics/CyclomaticComplexity
706
720
 
707
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
721
+ # rubocop:disable Metrics/CyclomaticComplexity
708
722
  def analyze_performance_config(content)
709
723
  checker.add_info("\n⚡ Performance & Loading:")
710
724
 
@@ -1387,9 +1401,85 @@ module ReactOnRails
1387
1401
  end
1388
1402
 
1389
1403
  def log_debug(message)
1390
- return unless defined?(Rails.logger) && Rails.logger
1404
+ Rails.logger&.debug(message)
1405
+ end
1406
+
1407
+ # Check Shakapacker private_output_path integration and provide recommendations
1408
+ def check_shakapacker_private_output_path(rails_bundle_path)
1409
+ return report_no_shakapacker unless defined?(::Shakapacker)
1410
+ return report_upgrade_shakapacker unless ::Shakapacker.config.respond_to?(:private_output_path)
1411
+
1412
+ check_shakapacker_9_private_output_path(rails_bundle_path)
1413
+ rescue StandardError => e
1414
+ checker.add_info("\n ℹ️ Could not check Shakapacker config: #{e.message}")
1415
+ end
1416
+
1417
+ def report_no_shakapacker
1418
+ checker.add_info("\n ℹ️ Shakapacker not detected - using manual configuration")
1419
+ end
1420
+
1421
+ def report_upgrade_shakapacker
1422
+ checker.add_info(<<~MSG.strip)
1423
+ \n 💡 Recommendation: Upgrade to Shakapacker 9.0+
1424
+
1425
+ Shakapacker 9.0+ adds 'private_output_path' in shakapacker.yml for server bundles.
1426
+ This eliminates the need to configure server_bundle_output_path separately.
1427
+
1428
+ Benefits:
1429
+ - Single source of truth in shakapacker.yml
1430
+ - Automatic detection by React on Rails
1431
+ - No configuration duplication
1432
+ MSG
1433
+ end
1434
+
1435
+ def check_shakapacker_9_private_output_path(rails_bundle_path)
1436
+ private_path = ::Shakapacker.config.private_output_path
1437
+
1438
+ if private_path
1439
+ report_shakapacker_path_status(private_path, rails_bundle_path)
1440
+ else
1441
+ report_configure_private_output_path(rails_bundle_path)
1442
+ end
1443
+ end
1444
+
1445
+ def report_shakapacker_path_status(private_path, rails_bundle_path)
1446
+ relative_path = ReactOnRails::Utils.normalize_to_relative_path(private_path)
1447
+ # Normalize both paths for comparison (remove trailing slashes)
1448
+ normalized_relative = relative_path.to_s.chomp("/")
1449
+ normalized_rails = rails_bundle_path.to_s.chomp("/")
1450
+
1451
+ if normalized_relative == normalized_rails
1452
+ checker.add_success("\n ✅ Using Shakapacker 9.0+ private_output_path: '#{relative_path}'")
1453
+ checker.add_info(" Auto-detected from shakapacker.yml - no manual config needed")
1454
+ else
1455
+ report_configuration_mismatch(relative_path, rails_bundle_path)
1456
+ end
1457
+ end
1458
+
1459
+ def report_configuration_mismatch(relative_path, rails_bundle_path)
1460
+ checker.add_warning(<<~MSG.strip)
1461
+ \n ⚠️ Configuration mismatch detected!
1462
+
1463
+ Shakapacker private_output_path: '#{relative_path}'
1464
+ React on Rails server_bundle_output_path: '#{rails_bundle_path}'
1465
+
1466
+ Recommendation: Remove server_bundle_output_path from your React on Rails
1467
+ initializer and let it auto-detect from shakapacker.yml private_output_path.
1468
+ MSG
1469
+ end
1470
+
1471
+ def report_configure_private_output_path(rails_bundle_path)
1472
+ checker.add_info(<<~MSG.strip)
1473
+ \n 💡 Recommendation: Configure private_output_path in shakapacker.yml
1474
+
1475
+ Add to config/shakapacker.yml:
1476
+ private_output_path: #{rails_bundle_path}
1391
1477
 
1392
- Rails.logger.debug(message)
1478
+ This will:
1479
+ - Keep webpack and Rails configs in sync automatically
1480
+ - Enable auto-detection by React on Rails
1481
+ - Serve as single source of truth for server bundle location
1482
+ MSG
1393
1483
  end
1394
1484
  end
1395
1485
  # rubocop:enable Metrics/ClassLength
@@ -83,10 +83,7 @@ module ReactOnRails
83
83
  ReactOnRails::ServerRenderingPool.reset_pool
84
84
  end
85
85
 
86
- rake_tasks do
87
- load File.expand_path("../tasks/generate_packs.rake", __dir__)
88
- load File.expand_path("../tasks/assets.rake", __dir__)
89
- load File.expand_path("../tasks/locale.rake", __dir__)
90
- end
86
+ # Rake tasks are automatically loaded from lib/tasks/*.rake by Rails::Engine
87
+ # No need to explicitly load them here to avoid duplicate loading
91
88
  end
92
89
  end
@@ -213,17 +213,20 @@ module ReactOnRails
213
213
 
214
214
  return unless npm_version && defined?(ReactOnRails::VERSION)
215
215
 
216
- # Clean version strings for comparison (remove ^, ~, =, etc.)
217
- clean_npm_version = npm_version.gsub(/[^0-9.]/, "")
216
+ # Normalize NPM version format to Ruby gem format for comparison
217
+ # Uses existing VersionSyntaxConverter to handle dash/dot differences
218
+ # (e.g., "16.2.0-beta.10" → "16.2.0.beta.10")
219
+ converter = ReactOnRails::VersionSyntaxConverter.new
220
+ normalized_npm_version = converter.npm_to_rubygem(npm_version)
218
221
  gem_version = ReactOnRails::VERSION
219
222
 
220
- if clean_npm_version == gem_version
223
+ if normalized_npm_version == gem_version
221
224
  add_success("✅ React on Rails gem and NPM package versions match (#{gem_version})")
222
225
  check_version_patterns(npm_version, gem_version)
223
226
  else
224
227
  # Check for major version differences
225
228
  gem_major = gem_version.split(".")[0].to_i
226
- npm_major = clean_npm_version.split(".")[0].to_i
229
+ npm_major = normalized_npm_version.split(".")[0].to_i
227
230
 
228
231
  if gem_major != npm_major # rubocop:disable Style/NegatedIfElseCondition
229
232
  add_error(<<~MSG.strip)
@@ -443,6 +443,60 @@ module ReactOnRails
443
443
  end
444
444
  end
445
445
 
446
+ # Converts an absolute path (String or Pathname) to a path relative to Rails.root.
447
+ # If the path is already relative or doesn't contain Rails.root, returns it as-is.
448
+ #
449
+ # This method is used to normalize paths from Shakapacker's privateOutputPath (which is
450
+ # absolute) to relative paths suitable for React on Rails configuration.
451
+ #
452
+ # Note: Absolute paths that don't start with Rails.root are intentionally passed through
453
+ # unchanged. While there's no known use case for server bundles outside Rails.root,
454
+ # this behavior preserves the original path for debugging and error messages.
455
+ #
456
+ # @param path [String, Pathname] The path to normalize
457
+ # @return [String, nil] The relative path as a string, or nil if path is nil
458
+ #
459
+ # @example Converting absolute paths within Rails.root
460
+ # # Assuming Rails.root is "/app"
461
+ # normalize_to_relative_path("/app/ssr-generated") # => "ssr-generated"
462
+ # normalize_to_relative_path("/app/foo/bar") # => "foo/bar"
463
+ #
464
+ # @example Already relative paths pass through
465
+ # normalize_to_relative_path("ssr-generated") # => "ssr-generated"
466
+ # normalize_to_relative_path("./ssr-generated") # => "./ssr-generated"
467
+ #
468
+ # @example Absolute paths outside Rails.root (edge case)
469
+ # normalize_to_relative_path("/other/path/bundles") # => "/other/path/bundles"
470
+ # rubocop:disable Metrics/CyclomaticComplexity
471
+ def self.normalize_to_relative_path(path)
472
+ return nil if path.nil?
473
+
474
+ path_str = path.to_s
475
+ rails_root_str = Rails.root.to_s.chomp("/")
476
+
477
+ # Treat as "inside Rails.root" only for exact match or a subdirectory
478
+ inside_rails_root = rails_root_str.present? &&
479
+ (path_str == rails_root_str || path_str.start_with?("#{rails_root_str}/"))
480
+
481
+ # If path is within Rails.root, remove that prefix
482
+ if inside_rails_root
483
+ # Remove Rails.root and any leading slash
484
+ path_str.sub(%r{^#{Regexp.escape(rails_root_str)}/?}, "")
485
+ else
486
+ # Path is already relative or outside Rails.root
487
+ # Warn if it's an absolute path outside Rails.root (edge case)
488
+ if path_str.start_with?("/") && !inside_rails_root
489
+ Rails.logger&.warn(
490
+ "ReactOnRails: Detected absolute path outside Rails.root: '#{path_str}'. " \
491
+ "Server bundles are typically stored within Rails.root. " \
492
+ "Verify this is intentional."
493
+ )
494
+ end
495
+ path_str
496
+ end
497
+ end
498
+ # rubocop:enable Metrics/CyclomaticComplexity
499
+
446
500
  def self.default_troubleshooting_section
447
501
  <<~DEFAULT
448
502
  📞 Get Help & Support:
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "16.2.0.beta.8"
4
+ VERSION = "16.2.0.beta.11"
5
5
  end
@@ -9,7 +9,7 @@ GIT
9
9
  PATH
10
10
  remote: ..
11
11
  specs:
12
- react_on_rails (16.2.0.beta.8)
12
+ react_on_rails (16.2.0.beta.11)
13
13
  addressable
14
14
  connection_pool
15
15
  execjs (~> 2.5)
@@ -20,7 +20,7 @@ PATH
20
20
  PATH
21
21
  remote: .
22
22
  specs:
23
- react_on_rails_pro (16.2.0.beta.8)
23
+ react_on_rails_pro (16.2.0.beta.11)
24
24
  addressable
25
25
  async (>= 2.6)
26
26
  connection_pool
@@ -28,7 +28,7 @@ PATH
28
28
  httpx (~> 1.5)
29
29
  jwt (~> 2.7)
30
30
  rainbow
31
- react_on_rails (= 16.2.0.beta.8)
31
+ react_on_rails (= 16.2.0.beta.11)
32
32
 
33
33
  GEM
34
34
  remote: https://rubygems.org/
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRailsPro
4
- VERSION = "16.2.0.beta.8"
4
+ VERSION = "16.2.0.beta.11"
5
5
  PROTOCOL_VERSION = "2.0.0"
6
6
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-on-rails-pro-node-renderer",
3
- "version": "16.2.0-beta.8",
3
+ "version": "16.2.0-beta.11",
4
4
  "protocolVersion": "2.0.0",
5
5
  "description": "react-on-rails-pro JavaScript for react_on_rails_pro Ruby gem",
6
6
  "exports": {
@@ -9,7 +9,7 @@ GIT
9
9
  PATH
10
10
  remote: ../../..
11
11
  specs:
12
- react_on_rails (16.2.0.beta.8)
12
+ react_on_rails (16.2.0.beta.11)
13
13
  addressable
14
14
  connection_pool
15
15
  execjs (~> 2.5)
@@ -20,7 +20,7 @@ PATH
20
20
  PATH
21
21
  remote: ../..
22
22
  specs:
23
- react_on_rails_pro (16.2.0.beta.8)
23
+ react_on_rails_pro (16.2.0.beta.11)
24
24
  addressable
25
25
  async (>= 2.6)
26
26
  connection_pool
@@ -28,7 +28,7 @@ PATH
28
28
  httpx (~> 1.5)
29
29
  jwt (~> 2.7)
30
30
  rainbow
31
- react_on_rails (= 16.2.0.beta.8)
31
+ react_on_rails (= 16.2.0.beta.11)
32
32
 
33
33
  GEM
34
34
  remote: https://rubygems.org/
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Shakapacker precompile hook for React on Rails Pro test dummy app
5
+ #
6
+ # This script loads the shared test helper implementation.
7
+ # For production apps, use the generator template which includes a standalone implementation.
8
+
9
+ # Find the gem root directory (four levels up from react_on_rails_pro/spec/dummy/bin)
10
+ gem_root = File.expand_path("../../../..", __dir__)
11
+ shared_hook = File.join(gem_root, "spec", "support", "shakapacker_precompile_hook_shared.rb")
12
+
13
+ unless File.exist?(shared_hook)
14
+ warn "❌ Error: Shared precompile hook not found at #{shared_hook}"
15
+ exit 1
16
+ end
17
+
18
+ # Load and execute the shared hook
19
+ load shared_hook
@@ -19,6 +19,11 @@ default: &default
19
19
  # Reload manifest.json on all requests so we reload latest compiled packs
20
20
  cache_manifest: false
21
21
 
22
+ # Hook to run before webpack compilation (e.g., for generating dynamic entry points)
23
+ # SECURITY: Only reference trusted scripts within your project. Ensure the hook path
24
+ # points to a file within the project root that you control.
25
+ precompile_hook: 'bin/shakapacker-precompile-hook'
26
+
22
27
  # Extract and emit a css file
23
28
  extract_css: true
24
29
 
@@ -0,0 +1,15 @@
1
+ module ReactOnRails
2
+ module Dev
3
+ class FileManager
4
+ def self.cleanup_stale_files: () -> bool
5
+
6
+ private
7
+
8
+ def self.cleanup_overmind_sockets: () -> bool
9
+ def self.cleanup_rails_pid_file: () -> bool
10
+ def self.overmind_running?: () -> bool
11
+ def self.process_running?: (Integer) -> bool
12
+ def self.remove_file_if_exists: (String, String) -> bool
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module ReactOnRails
2
+ module Dev
3
+ class PackGenerator
4
+ def self.generate: (?verbose: bool) -> void
5
+
6
+ private
7
+
8
+ def self.run_pack_generation: (?silent: bool) -> bool
9
+ def self.should_run_directly?: () -> bool
10
+ def self.rails_available?: () -> bool
11
+ def self.run_rake_task_directly: (?silent: bool) -> bool
12
+ def self.load_rake_tasks: () -> void
13
+ def self.prepare_rake_task: () -> untyped
14
+ def self.capture_output: (bool) { () -> bool } -> bool
15
+ def self.handle_rake_error: (Exception, bool) -> void
16
+ def self.run_via_bundle_exec: (?silent: bool) -> (bool | nil)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ module ReactOnRails
2
+ module Dev
3
+ class ProcessManager
4
+ VERSION_CHECK_TIMEOUT: Integer
5
+
6
+ def self.installed?: (String) -> bool
7
+ def self.ensure_procfile: (String) -> void
8
+ def self.run_with_process_manager: (String) -> void
9
+
10
+ private
11
+
12
+ def self.installed_in_current_context?: (String) -> bool
13
+ def self.version_flags_for: (String) -> Array[String]
14
+ def self.run_process_if_available: (String, Array[String]) -> bool
15
+ def self.run_process_outside_bundle: (String, Array[String]) -> bool
16
+ def self.process_available_in_system?: (String) -> bool
17
+ def self.with_unbundled_context: () { () -> untyped } -> untyped
18
+ def self.show_process_manager_installation_help: () -> void
19
+ def self.valid_procfile_path?: (String) -> bool
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ module ReactOnRails
2
+ module Dev
3
+ class ServerManager
4
+ type mode = :development | :production_like | :static | :hmr
5
+
6
+ def self.start: (mode, String?, ?verbose: bool, ?route: String?, ?rails_env: String?) -> void
7
+ def self.kill_processes: () -> void
8
+ def self.development_processes: () -> Hash[String, String]
9
+ def self.kill_running_processes: () -> bool
10
+ def self.find_process_pids: (String) -> Array[Integer]
11
+ def self.terminate_processes: (Array[Integer]) -> void
12
+ def self.kill_port_processes: (Array[Integer]) -> bool
13
+ def self.find_port_pids: (Integer) -> Array[Integer]
14
+ def self.cleanup_socket_files: () -> bool
15
+ def self.print_kill_summary: (bool) -> void
16
+ def self.show_help: () -> void
17
+ def self.run_from_command_line: (?Array[String]) -> void
18
+
19
+ private
20
+
21
+ def self.help_usage: () -> String
22
+ def self.help_commands: () -> String
23
+ def self.help_options: () -> String
24
+ def self.help_customization: () -> String
25
+ def self.help_mode_details: () -> String
26
+ def self.help_troubleshooting: () -> String
27
+ def self.run_production_like: (?_verbose: bool, ?route: String?, ?rails_env: String?) -> void
28
+ def self.run_static_development: (String, ?verbose: bool, ?route: String?) -> void
29
+ def self.run_development: (String, ?verbose: bool, ?route: String?) -> void
30
+ def self.print_server_info: (String, Array[String], ?Integer, ?route: String?) -> void
31
+ def self.print_procfile_info: (String, ?route: String?) -> void
32
+ def self.procfile_port: (String) -> Integer
33
+ def self.box_border: (Integer) -> String
34
+ def self.box_bottom: (Integer) -> String
35
+ def self.box_empty_line: (Integer) -> String
36
+ def self.format_box_line: (String, Integer) -> String
37
+ end
38
+ end
39
+ end