react_on_rails 16.6.0.rc.0 → 16.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2294c0aab02fdb0995b81b139099a0585b25ee39ebe903d6238e91a40e2a0341
4
- data.tar.gz: 76c6b154c56c639566069a5840496e4ba142b6130429f38ab7580f6bb33bbc29
3
+ metadata.gz: bd57c5ba417fed762b468a17579ea7bdf04bb314730eb62e9b2ae210fd873c9c
4
+ data.tar.gz: a860a8fafb5f17aaf1bb9f07d519a3d73bbc6f3b997b44d7398c7fce7e4c45ab
5
5
  SHA512:
6
- metadata.gz: 0521bd2c98262935f0f7bac35e779aec25a6cb8a8039906141ab7e560d27deade2c3b1601d389d4e362ead52ed64b4be0e851ae22a07cb61e15948407e925a69
7
- data.tar.gz: bd80ca64b259c5e303111d7f46aeaa2b1e1bcda60af3fcc1873db9e51b39db2bf42bb4f846b9678ea9b8d6b5d4dac0b70183ce6fa30b7953ad2d0a65ee6d7dc4
6
+ metadata.gz: 36ac38e9d74615e2970df360ce082bbfc625624347deaf0ddddf4756c21c112a76572795652ccd94f8f0cc05e8bbf51b6499a68a36c61a0e32eac06b17268721
7
+ data.tar.gz: 6a084e79ce8b4b8b5f9328d3243d71d740a2f34291f07c57fc56e33985d75242015171fc7c15b74a36545dc40263e603ece9cb0d4d722e4d624060fb56c14726
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- react_on_rails (16.6.0.rc.0)
4
+ react_on_rails (16.6.0)
5
5
  addressable
6
6
  connection_pool
7
7
  execjs (~> 2.5)
@@ -52,29 +52,39 @@ module ReactOnRails
52
52
  # Include this module in generator classes and call setup_js_dependencies
53
53
  # to handle all JS dependency installation via package_json gem.
54
54
  module JsDependencyManager
55
+ # Third-party dependencies are pinned to ^major.0.0 ranges to prevent breaking
56
+ # changes from uncontrolled major version bumps (e.g., peer dependency conflicts)
57
+ # while still allowing minor/patch updates. Pre-1.0 packages are left bare since
58
+ # ^0.x ranges pin to the minor version, which is too narrow.
59
+ # Exception: SWC deps are pinned to match Shakapacker's own version constraints
60
+ # (swc-loader@^0.2.0 is pre-1.0 but deliberately pinned for Shakapacker compat).
61
+ #
62
+ # Update these pins deliberately when adopting a new major version.
63
+
55
64
  # Core React dependencies required for React on Rails
56
65
  # Note: @babel/preset-react is handled separately in BABEL_REACT_DEPENDENCIES
57
66
  # and is added only when SWC is not the active transpiler.
58
67
  REACT_DEPENDENCIES = %w[
59
- react
60
- react-dom
61
- prop-types
68
+ react@^19.0.0
69
+ react-dom@^19.0.0
70
+ prop-types@^15.0.0
62
71
  ].freeze
63
72
 
64
73
  # Babel preset needed by the generated babel.config.js for non-SWC setups.
65
74
  BABEL_REACT_DEPENDENCIES = %w[
66
- @babel/preset-react
75
+ @babel/preset-react@^7.0.0
67
76
  ].freeze
68
77
 
69
78
  # CSS processing dependencies for webpack
70
79
  CSS_DEPENDENCIES = %w[
71
- css-loader
72
- css-minimizer-webpack-plugin
73
- mini-css-extract-plugin
74
- style-loader
80
+ css-loader@^7.0.0
81
+ css-minimizer-webpack-plugin@^8.0.0
82
+ mini-css-extract-plugin@^2.0.0
83
+ style-loader@^4.0.0
75
84
  ].freeze
76
85
 
77
86
  # Development-only dependencies for hot reloading (Webpack)
87
+ # Both packages are pre-1.0, so left bare (see pinning note above).
78
88
  DEV_DEPENDENCIES = %w[
79
89
  @pmmmwh/react-refresh-webpack-plugin
80
90
  react-refresh
@@ -82,14 +92,15 @@ module ReactOnRails
82
92
 
83
93
  # Rspack core dependencies (only installed when --rspack flag is used)
84
94
  RSPACK_DEPENDENCIES = %w[
85
- @rspack/core
86
- rspack-manifest-plugin
95
+ @rspack/core@^1.0.0
96
+ rspack-manifest-plugin@^5.0.0
87
97
  ].freeze
88
98
 
89
99
  # Rspack development dependencies for hot reloading
100
+ # react-refresh is pre-1.0, so left bare (see pinning note above).
90
101
  RSPACK_DEV_DEPENDENCIES = %w[
91
- @rspack/cli
92
- @rspack/plugin-react-refresh
102
+ @rspack/cli@^1.0.0
103
+ @rspack/plugin-react-refresh@^1.0.0
93
104
  react-refresh
94
105
  ].freeze
95
106
 
@@ -100,16 +111,17 @@ module ReactOnRails
100
111
  # - If users choose javascript_transpiler: 'babel', they should manually add @babel/preset-typescript
101
112
  # and configure it in their babel.config.js
102
113
  TYPESCRIPT_DEPENDENCIES = %w[
103
- typescript
104
- @types/react
105
- @types/react-dom
114
+ typescript@^6.0.0
115
+ @types/react@^19.0.0
116
+ @types/react-dom@^19.0.0
106
117
  ].freeze
107
118
 
108
119
  # SWC transpiler dependencies (for Shakapacker 9.3.0+ default transpiler)
109
120
  # SWC is ~20x faster than Babel and is the default for new Shakapacker installations
121
+ # Version ranges match Shakapacker's own constraints.
110
122
  SWC_DEPENDENCIES = %w[
111
- @swc/core
112
- swc-loader
123
+ @swc/core@^1.3.0
124
+ swc-loader@^0.2.0
113
125
  ].freeze
114
126
 
115
127
  # React on Rails Pro dependencies (only installed when --pro or --rsc flag is used)
@@ -222,7 +234,8 @@ module ReactOnRails
222
234
  # RSC requires React 19.0.x specifically (not 19.1.x or later)
223
235
  # Pin to ~19.0.4 to allow patch updates while staying within 19.0.x
224
236
  react_deps = if respond_to?(:use_rsc?) && use_rsc?
225
- ["react@#{RSC_REACT_VERSION_RANGE}", "react-dom@#{RSC_REACT_VERSION_RANGE}", "prop-types"]
237
+ ["react@#{RSC_REACT_VERSION_RANGE}", "react-dom@#{RSC_REACT_VERSION_RANGE}",
238
+ "prop-types@^15.0.0"]
226
239
  else
227
240
  REACT_DEPENDENCIES
228
241
  end
@@ -147,28 +147,25 @@ module ReactOnRails
147
147
 
148
148
  base_gem_entry_found = true
149
149
 
150
+ declaration = consume_non_parenthesized_base_gem_declaration(
151
+ gemfile_lines,
152
+ line_index,
153
+ match.end(0)
154
+ )
155
+
150
156
  unless pro_entry_added
151
157
  indentation = match[1]
152
158
  quote = match[2]
153
159
  updated_lines << build_pro_gem_replacement_line(
154
160
  indentation: indentation,
155
161
  quote: quote,
156
- suffix: line[match.end(0)..],
162
+ suffix: declaration[:trailing_suffix],
157
163
  parenthesized_gem_call: match[0].include?("(")
158
164
  )
159
165
  pro_entry_added = true
160
166
  end
161
167
 
162
- # Consume multiline gem declarations that continue with trailing commas.
163
- line_index += 1
164
- current_line = line
165
- while line_index < gemfile_lines.length &&
166
- line_continues_with_comma?(current_line) &&
167
- gem_declaration_continues_on_next_line?(gemfile_lines[line_index])
168
- next_line = gemfile_lines[line_index]
169
- current_line = next_line unless comment_or_blank_line?(next_line)
170
- line_index += 1
171
- end
168
+ line_index = declaration[:next_index]
172
169
  end
173
170
 
174
171
  updated_content = updated_lines.join
@@ -476,17 +473,18 @@ module ReactOnRails
476
473
  pending_multiline_static_import_specifier
477
474
  ) { |line_fragment| yield line_fragment }
478
475
  in_multiline_template_literal = updated_template_literal_state
479
- in_block_comment = true if unclosed_block_comment_starts?(rewritten_line)
476
+ in_block_comment = unclosed_block_comment_starts?(rewritten_line)
480
477
  rewritten_line
481
478
  elsif line_contains_unescaped_backtick
482
479
  rewritten_line, pending_multiline_module_call_depth, pending_multiline_static_import_specifier =
483
480
  rewrite_line_before_template_literal_open(
484
481
  line,
485
482
  pending_multiline_module_call_depth,
486
- pending_multiline_static_import_specifier
483
+ pending_multiline_static_import_specifier,
484
+ in_block_comment: in_block_comment
487
485
  ) { |line_fragment| yield line_fragment }
488
486
  in_multiline_template_literal = updated_template_literal_state
489
- in_block_comment = true if unclosed_block_comment_starts?(rewritten_line)
487
+ in_block_comment = unclosed_block_comment_starts?(rewritten_line)
490
488
  rewritten_line
491
489
  else
492
490
  in_multiline_template_literal = updated_template_literal_state
@@ -648,7 +646,7 @@ module ReactOnRails
648
646
 
649
647
  rewritten_line = yield line_without_inline_templates
650
648
  template_placeholders.each do |placeholder, template_literal|
651
- rewritten_line = rewritten_line.sub(placeholder, template_literal)
649
+ rewritten_line = rewritten_line.sub(placeholder) { template_literal }
652
650
  end
653
651
  rewritten_line
654
652
  end
@@ -742,8 +740,13 @@ module ReactOnRails
742
740
  ["#{template_literal_prefix}#{rewritten_fragment}", pending_depth, pending_multiline_static_import_specifier]
743
741
  end
744
742
 
745
- def rewrite_line_before_template_literal_open(line, pending_depth, pending_multiline_static_import_specifier)
746
- opening_index = first_unescaped_backtick_index(line)
743
+ def rewrite_line_before_template_literal_open(
744
+ line,
745
+ pending_depth,
746
+ pending_multiline_static_import_specifier,
747
+ in_block_comment: false
748
+ )
749
+ opening_index = opening_backtick_index_for_multiline_start(line, in_block_comment: in_block_comment)
747
750
  return [line, pending_depth, pending_multiline_static_import_specifier] unless opening_index&.positive?
748
751
 
749
752
  line_prefix = line[0, opening_index]
@@ -757,17 +760,56 @@ module ReactOnRails
757
760
  end
758
761
 
759
762
  def first_unescaped_backtick_index(line)
763
+ unescaped_backtick_indexes(line, skip_comments: true).first
764
+ end
765
+
766
+ def opening_backtick_index_for_multiline_start(line, in_block_comment: false)
767
+ backtick_indexes = unescaped_backtick_indexes(line, in_block_comment: in_block_comment)
768
+ return nil if backtick_indexes.empty? || backtick_indexes.length.even?
769
+
770
+ backtick_indexes.last
771
+ end
772
+
773
+ # rubocop:disable Metrics/CyclomaticComplexity
774
+ def unescaped_backtick_indexes(line, in_block_comment: false, skip_comments: false)
760
775
  quote_state = nil
776
+ backtick_indexes = []
777
+
778
+ scan_index = 0
779
+ while scan_index < line.length
780
+ if in_block_comment
781
+ closing_index = line.index("*/", scan_index)
782
+ break unless closing_index
783
+
784
+ in_block_comment = false
785
+ scan_index = closing_index + 2
786
+ next
787
+ end
761
788
 
762
- line.each_char.with_index do |char, index|
763
- quote_state = next_quote_state(quote_state, char, line, index)
764
- next if quote_state
765
- return nil if line[index, 2] == "//"
789
+ char = line[scan_index]
790
+ quote_state = next_quote_state(quote_state, char, line, scan_index)
791
+ if quote_state
792
+ scan_index += 1
793
+ next
794
+ end
795
+
796
+ unless skip_comments
797
+ break if line[scan_index, 2] == "//"
798
+
799
+ if line[scan_index, 2] == "/*"
800
+ in_block_comment = true
801
+ scan_index += 2
802
+ next
803
+ end
804
+ end
766
805
 
767
- return index if char == "`" && !character_escaped?(line, index)
806
+ backtick_indexes << scan_index if char == "`" && !character_escaped?(line, scan_index)
807
+ scan_index += 1
768
808
  end
769
- nil
809
+
810
+ backtick_indexes
770
811
  end
812
+ # rubocop:enable Metrics/CyclomaticComplexity
771
813
 
772
814
  def next_quote_state(current_state, char, line, index)
773
815
  if current_state
@@ -830,13 +872,36 @@ module ReactOnRails
830
872
  end
831
873
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
832
874
 
875
+ def consume_non_parenthesized_base_gem_declaration(lines, start_index, match_end)
876
+ line_index = start_index
877
+ current_line = lines[line_index]
878
+ declaration_lines = [current_line]
879
+ line_index += 1
880
+
881
+ while line_index < lines.length &&
882
+ line_continues_with_comma?(current_line) &&
883
+ gem_declaration_continues_on_next_line?(lines[line_index])
884
+ next_line = lines[line_index]
885
+ declaration_lines << next_line
886
+ current_line = next_line unless comment_or_blank_line?(next_line)
887
+ line_index += 1
888
+ end
889
+
890
+ trailing_suffix = lines[start_index][match_end..].to_s + declaration_lines.drop(1).join
891
+ { trailing_suffix: trailing_suffix, next_index: line_index }
892
+ end
893
+
833
894
  def build_pro_gem_replacement_line(indentation:, quote:, suffix:, parenthesized_gem_call: false)
834
895
  normalized_suffix = suffix || "\n"
835
896
  normalized_suffix = "#{normalized_suffix}\n" unless normalized_suffix.end_with?("\n")
836
897
  version_arg_pattern = /\A(?<prefix>\s*,(?:\s*#.*\n|\s++)*)["'][^"']*["'](?<trailing_comma>\s*,)?/
837
898
  loop do
838
899
  updated_suffix = normalized_suffix.sub(version_arg_pattern) do
839
- Regexp.last_match[:trailing_comma] ? Regexp.last_match[:prefix] : ""
900
+ if Regexp.last_match[:trailing_comma]
901
+ Regexp.last_match[:prefix].sub(/\n[ \t]*\z/, "")
902
+ else
903
+ ""
904
+ end
840
905
  end
841
906
  break if updated_suffix == normalized_suffix
842
907
 
@@ -170,7 +170,7 @@ module ReactOnRails
170
170
  ⚠️ Procfile.dev not found. Skipping RSC bundle watcher addition.
171
171
 
172
172
  You'll need to add the RSC bundle watcher to your process manager manually:
173
- rsc-bundle: RSC_BUNDLE_ONLY=yes bin/shakapacker-watch --watch
173
+ rsc-bundle: RSC_BUNDLE_ONLY=true bin/shakapacker-watch --watch
174
174
  MSG
175
175
  return
176
176
  end
@@ -185,7 +185,7 @@ module ReactOnRails
185
185
  rsc_watcher_line = <<~PROCFILE
186
186
 
187
187
  # React on Rails Pro - RSC bundle watcher
188
- rsc-bundle: RSC_BUNDLE_ONLY=yes bin/shakapacker-watch --watch
188
+ rsc-bundle: RSC_BUNDLE_ONLY=true bin/shakapacker-watch --watch
189
189
  PROCFILE
190
190
 
191
191
  append_to_file("Procfile.dev", rsc_watcher_line)
@@ -6,4 +6,4 @@
6
6
  # SHAKAPACKER_DEV_SERVER_PORT=3036
7
7
  rails: bundle exec rails s -p ${PORT:-3000}
8
8
  dev-server: bin/shakapacker-dev-server
9
- server-bundle: SERVER_BUNDLE_ONLY=yes bin/shakapacker-watch --watch
9
+ server-bundle: SERVER_BUNDLE_ONLY=true bin/shakapacker-watch --watch
@@ -6,14 +6,17 @@ require "json"
6
6
 
7
7
  # Script to switch between webpack and rspack bundlers
8
8
  class BundlerSwitcher
9
+ # Pinned to ^major.0.0 to prevent peer dependency conflicts from major version bumps.
10
+ # Pre-1.0 packages are left bare since ^0.x pins to the minor version.
11
+ # webpack-cli pinned to ^6 (not ^7) to stay within Shakapacker's supported peer range.
9
12
  WEBPACK_DEPS = {
10
- dependencies: %w[webpack webpack-assets-manifest webpack-merge],
11
- dev_dependencies: %w[webpack-cli webpack-dev-server @pmmmwh/react-refresh-webpack-plugin]
13
+ dependencies: %w[webpack@^5.0.0 webpack-assets-manifest@^6.0.0 webpack-merge@^6.0.0],
14
+ dev_dependencies: %w[webpack-cli@^6.0.0 webpack-dev-server@^5.0.0 @pmmmwh/react-refresh-webpack-plugin]
12
15
  }.freeze
13
16
 
14
17
  RSPACK_DEPS = {
15
- dependencies: %w[@rspack/core rspack-manifest-plugin],
16
- dev_dependencies: %w[@rspack/cli @rspack/plugin-react-refresh]
18
+ dependencies: %w[@rspack/core@^1.0.0 rspack-manifest-plugin@^5.0.0],
19
+ dev_dependencies: %w[@rspack/cli@^1.0.0 @rspack/plugin-react-refresh@^1.0.0]
17
20
  }.freeze
18
21
 
19
22
  def initialize(target_bundler)
@@ -83,11 +86,14 @@ class BundlerSwitcher
83
86
  remove_deps = @target_bundler == "rspack" ? WEBPACK_DEPS : RSPACK_DEPS
84
87
 
85
88
  # Remove old bundler dependencies
89
+ # Strip version suffix (e.g., "webpack@^5.0.0" -> "webpack") since package.json keys are bare names.
90
+ # The regex handles scoped (@scope/name@ver) and unscoped (name@ver) packages, and is a no-op for
91
+ # bare names without a version suffix (e.g., "@pmmmwh/react-refresh-webpack-plugin" stays unchanged).
86
92
  remove_deps[:dependencies].each do |dep|
87
- package_json["dependencies"]&.delete(dep)
93
+ package_json["dependencies"]&.delete(dep[%r{\A(@[^/]+/[^@]+|[^@]+)}])
88
94
  end
89
95
  remove_deps[:dev_dependencies].each do |dep|
90
- package_json["devDependencies"]&.delete(dep)
96
+ package_json["devDependencies"]&.delete(dep[%r{\A(@[^/]+/[^@]+|[^@]+)}])
91
97
  end
92
98
 
93
99
  puts "✅ Removed #{@target_bundler == 'rspack' ? 'webpack' : 'rspack'} dependencies"
@@ -94,51 +94,6 @@ module ReactOnRails
94
94
  :server_bundle_output_path, :enforce_private_server_bundles,
95
95
  :check_database_on_dev_start
96
96
 
97
- # Class instance variable and mutex to track if deprecation warning has been shown
98
- # Using mutex to ensure thread-safety in multi-threaded environments
99
- @immediate_hydration_warned = false
100
- @immediate_hydration_mutex = Mutex.new
101
-
102
- class << self
103
- attr_accessor :immediate_hydration_warned, :immediate_hydration_mutex
104
- end
105
-
106
- # Deprecated: immediate_hydration configuration has been removed
107
- def immediate_hydration=(value)
108
- warned = false
109
- self.class.immediate_hydration_mutex.synchronize do
110
- warned = self.class.immediate_hydration_warned
111
- self.class.immediate_hydration_warned = true unless warned
112
- end
113
-
114
- return if warned
115
-
116
- Rails.logger.warn <<~WARNING
117
- [REACT ON RAILS] The 'config.immediate_hydration' configuration option is deprecated and no longer used.
118
- Immediate hydration is now automatically enabled for React on Rails Pro users.
119
- Please remove 'config.immediate_hydration = #{value}' from your config/initializers/react_on_rails.rb file.
120
- See CHANGELOG.md for migration instructions.
121
- WARNING
122
- end
123
-
124
- def immediate_hydration
125
- warned = false
126
- self.class.immediate_hydration_mutex.synchronize do
127
- warned = self.class.immediate_hydration_warned
128
- self.class.immediate_hydration_warned = true unless warned
129
- end
130
-
131
- return nil if warned
132
-
133
- Rails.logger.warn <<~WARNING
134
- [REACT ON RAILS] The 'config.immediate_hydration' configuration option is deprecated and no longer used.
135
- Immediate hydration is now automatically enabled for React on Rails Pro users.
136
- Please remove any references to 'config.immediate_hydration' from your config/initializers/react_on_rails.rb file.
137
- See CHANGELOG.md for migration instructions.
138
- WARNING
139
- nil
140
- end
141
-
142
97
  # rubocop:disable Metrics/AbcSize
143
98
  def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
144
99
  replay_console: nil, make_generated_server_bundle_the_entrypoint: nil,
@@ -257,12 +212,14 @@ module ReactOnRails
257
212
  Rails.logger.warn("**WARNING** #{msg}")
258
213
  self.generated_component_packs_loading_strategy = :sync
259
214
  elsif generated_component_packs_loading_strategy == :async
260
- raise ReactOnRails::Error, "**ERROR** #{msg}"
215
+ raise ReactOnRails::Error, "**ERROR** #{msg}\n\n#{ReactOnRails::DOCTOR_RECOMMENDATION}"
261
216
  end
262
217
 
263
218
  return if %i[async defer sync].include?(generated_component_packs_loading_strategy)
264
219
 
265
- raise ReactOnRails::Error, "generated_component_packs_loading_strategy must be either :async, :defer, or :sync"
220
+ raise ReactOnRails::Error,
221
+ "generated_component_packs_loading_strategy must be either :async, :defer, or :sync. " \
222
+ "#{ReactOnRails::DOCTOR_RECOMMENDATION}"
266
223
  end
267
224
 
268
225
  def validate_enforce_private_server_bundles
@@ -272,7 +229,8 @@ module ReactOnRails
272
229
  if server_bundle_output_path.nil?
273
230
  raise ReactOnRails::Error, "enforce_private_server_bundles is set to true, but " \
274
231
  "server_bundle_output_path is nil. Please set server_bundle_output_path " \
275
- "to a directory outside of the public directory."
232
+ "to a directory outside of the public directory. " \
233
+ "#{ReactOnRails::DOCTOR_RECOMMENDATION}"
276
234
  end
277
235
 
278
236
  # Check if server_bundle_output_path is inside public directory
@@ -286,7 +244,8 @@ module ReactOnRails
286
244
 
287
245
  raise ReactOnRails::Error, "enforce_private_server_bundles is set to true, but " \
288
246
  "server_bundle_output_path (#{server_bundle_output_path}) is inside " \
289
- "the public directory. Please set it to a directory outside of public."
247
+ "the public directory. Please set it to a directory outside of public. " \
248
+ "#{ReactOnRails::DOCTOR_RECOMMENDATION}"
290
249
  end
291
250
 
292
251
  # Auto-detect server_bundle_output_path from Shakapacker 9.0+ private_output_path
@@ -401,6 +360,8 @@ module ReactOnRails
401
360
  that does not match the value for public_output_path specified in
402
361
  shakapacker.yml = #{packer_public_output_path}. You should remove the configuration
403
362
  value for "generated_assets_dir" from your config/initializers/react_on_rails.rb file.
363
+
364
+ #{ReactOnRails::DOCTOR_RECOMMENDATION}
404
365
  MSG
405
366
  raise ReactOnRails::Error, msg
406
367
  end
@@ -465,7 +426,9 @@ module ReactOnRails
465
426
  msg = <<~MSG
466
427
  **ERROR** ReactOnRails: auto_load_bundle is set to true, yet components_subdirectory is not configured.\
467
428
  Please set components_subdirectory to the desired directory. For more information, please see \
468
- https://reactonrails.com/docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation/
429
+ https://reactonrails.com/docs/core-concepts/auto-bundling/
430
+
431
+ #{ReactOnRails::DOCTOR_RECOMMENDATION}
469
432
  MSG
470
433
 
471
434
  raise ReactOnRails::Error, msg
@@ -482,6 +445,7 @@ module ReactOnRails
482
445
  Alternatively, remove the config/react_on_rails.rb config.build_production_command and the
483
446
  default bin/shakapacker script will be used for assets:precompile.
484
447
 
448
+ #{ReactOnRails::DOCTOR_RECOMMENDATION}
485
449
  MSG
486
450
  end
487
451
  end
@@ -9,16 +9,22 @@ module ReactOnRails
9
9
  # JavaScript code.
10
10
  # props: Named parameter props which is a Ruby Hash or JSON string which contains the properties
11
11
  # to pass to the redux store.
12
- # immediate_hydration: React on Rails Pro (licensed) feature. When nil (default), Pro users get
13
- # immediate hydration, non-Pro users don't. Can be explicitly overridden.
14
12
  #
15
13
  # Be sure to include view helper `redux_store_hydration_data` at the end of your layout or view
16
14
  # or else there will be no client side hydration of your stores.
17
- def redux_store(store_name, props: {}, immediate_hydration: nil)
18
- immediate_hydration = ReactOnRails::Utils.normalize_immediate_hydration(immediate_hydration, store_name, "Store")
15
+ def redux_store(store_name, props: {}, **rest)
16
+ immediate_hydration_present = rest.key?(:immediate_hydration)
17
+ unknown_keys = rest.keys - [:immediate_hydration]
18
+ if unknown_keys.any?
19
+ plural = unknown_keys.one? ? "" : "s"
20
+ unknown_options = unknown_keys.map { |key| ":#{key}" }.join(", ")
21
+ raise ArgumentError, "unknown keyword#{plural}: #{unknown_options}"
22
+ end
23
+
24
+ ReactOnRails::Helper.warn_removed_immediate_hydration_option("redux_store") if immediate_hydration_present
25
+
19
26
  redux_store_data = { store_name: store_name,
20
- props: props,
21
- immediate_hydration: immediate_hydration }
27
+ props: props }
22
28
  @registered_stores_defer_render ||= []
23
29
  @registered_stores_defer_render << redux_store_data
24
30
  end
@@ -290,7 +290,7 @@ module ReactOnRails
290
290
 
291
291
  env = { "RAILS_ENV" => "test" }
292
292
  if resolved_mode == "client-only"
293
- env["CLIENT_BUNDLE_ONLY"] = "yes"
293
+ env["CLIENT_BUNDLE_ONLY"] = "true"
294
294
  puts Rainbow("🧪 Starting test watch (client-only mode)...").cyan
295
295
  puts Rainbow(" Reusing server bundle from existing watcher if available.").cyan
296
296
  else
@@ -320,7 +320,9 @@ module ReactOnRails
320
320
  def shakapacker_watch_process_running?
321
321
  # Detect existing shakapacker watcher processes (from either bin/dev or bin/dev static).
322
322
  # If one is already running, client-only test watch avoids duplicate server-bundle rebuilds.
323
- server_only_watchers = find_process_pids("SERVER_BUNDLE_ONLY=yes bin/shakapacker --watch")
323
+ # Also detect legacy =yes convention during transition
324
+ server_only_watchers = find_process_pids("SERVER_BUNDLE_ONLY=true bin/shakapacker --watch")
325
+ server_only_watchers |= find_process_pids("SERVER_BUNDLE_ONLY=yes bin/shakapacker --watch")
324
326
  if server_only_watchers.any?
325
327
  return true if shared_private_output_paths?
326
328