react_on_rails 16.2.0.beta.3 → 16.2.0.beta.4

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/CLAUDE.md +59 -0
  4. data/CONTRIBUTING.md +48 -0
  5. data/Gemfile.development_dependencies +1 -0
  6. data/Gemfile.lock +25 -2
  7. data/SWITCHING_CI_CONFIGS.md +55 -6
  8. data/Steepfile +51 -0
  9. data/bin/ci-rerun-failures +34 -11
  10. data/bin/ci-run-failed-specs +25 -1
  11. data/bin/ci-switch-config +254 -32
  12. data/bin/lefthook/check-trailing-newlines +2 -12
  13. data/bin/lefthook/eslint-lint +0 -10
  14. data/bin/lefthook/prettier-format +0 -10
  15. data/bin/lefthook/ruby-autofix +1 -5
  16. data/lib/react_on_rails/configuration.rb +56 -12
  17. data/lib/react_on_rails/controller.rb +3 -3
  18. data/lib/react_on_rails/doctor.rb +4 -2
  19. data/lib/react_on_rails/helper.rb +3 -3
  20. data/lib/react_on_rails/pro_helper.rb +2 -44
  21. data/lib/react_on_rails/react_component/render_options.rb +7 -7
  22. data/lib/react_on_rails/utils.rb +40 -0
  23. data/lib/react_on_rails/version.rb +1 -1
  24. data/react_on_rails_pro/CHANGELOG.md +135 -29
  25. data/react_on_rails_pro/Gemfile.development_dependencies +1 -0
  26. data/react_on_rails_pro/Gemfile.lock +6 -3
  27. data/react_on_rails_pro/README.md +559 -38
  28. data/react_on_rails_pro/docs/installation.md +40 -22
  29. data/react_on_rails_pro/docs/node-renderer/basics.md +26 -19
  30. data/react_on_rails_pro/docs/node-renderer/js-configuration.md +24 -22
  31. data/react_on_rails_pro/docs/node-renderer/troubleshooting.md +2 -0
  32. data/react_on_rails_pro/lib/react_on_rails_pro/version.rb +1 -1
  33. data/react_on_rails_pro/package.json +1 -1
  34. data/react_on_rails_pro/packages/node-renderer/src/master/restartWorkers.ts +39 -17
  35. data/react_on_rails_pro/packages/node-renderer/src/master.ts +15 -4
  36. data/react_on_rails_pro/packages/node-renderer/src/shared/configBuilder.ts +44 -5
  37. data/react_on_rails_pro/packages/node-renderer/src/shared/utils.ts +4 -2
  38. data/react_on_rails_pro/packages/node-renderer/src/worker/handleGracefulShutdown.ts +49 -0
  39. data/react_on_rails_pro/packages/node-renderer/src/worker/vm.ts +3 -3
  40. data/react_on_rails_pro/packages/node-renderer/src/worker.ts +5 -2
  41. data/react_on_rails_pro/packages/node-renderer/tests/helper.ts +8 -8
  42. data/react_on_rails_pro/packages/node-renderer/tests/testingNodeRendererConfigs.js +1 -1
  43. data/react_on_rails_pro/packages/node-renderer/tests/worker.test.ts +19 -19
  44. data/react_on_rails_pro/rakelib/rbs.rake +47 -0
  45. data/react_on_rails_pro/sig/react_on_rails_pro/cache.rbs +13 -0
  46. data/react_on_rails_pro/sig/react_on_rails_pro/configuration.rbs +100 -0
  47. data/react_on_rails_pro/sig/react_on_rails_pro/error.rbs +4 -0
  48. data/react_on_rails_pro/sig/react_on_rails_pro/utils.rbs +7 -0
  49. data/react_on_rails_pro/sig/react_on_rails_pro.rbs +5 -0
  50. data/react_on_rails_pro/spec/dummy/Gemfile.lock +6 -3
  51. data/react_on_rails_pro/spec/dummy/client/node-renderer.js +1 -1
  52. data/react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb +16 -17
  53. data/sig/react_on_rails/controller.rbs +1 -1
  54. data/sig/react_on_rails/error.rbs +4 -0
  55. data/sig/react_on_rails/helper.rbs +2 -2
  56. data/sig/react_on_rails/json_parse_error.rbs +10 -0
  57. data/sig/react_on_rails/prerender_error.rbs +21 -0
  58. data/sig/react_on_rails/smart_error.rbs +28 -0
  59. data/sig/react_on_rails.rbs +3 -24
  60. metadata +14 -3
  61. data/lib/react_on_rails/pro_utils.rb +0 -37
data/bin/ci-switch-config CHANGED
@@ -39,14 +39,120 @@ check_version_manager() {
39
39
  echo "mise"
40
40
  elif command -v asdf &> /dev/null; then
41
41
  echo "asdf"
42
+ elif command -v rvm &> /dev/null && command -v nvm &> /dev/null; then
43
+ echo "rvm+nvm"
44
+ elif command -v rvm &> /dev/null; then
45
+ echo "rvm"
46
+ elif command -v nvm &> /dev/null; then
47
+ echo "nvm"
42
48
  else
43
- print_error "No version manager found. Please install mise or asdf:"
49
+ print_error "No version manager found. Please install one of:"
44
50
  echo " mise (recommended): https://mise.jdx.dev/"
45
- echo " asdf (legacy): https://asdf-vm.com/"
51
+ echo " asdf: https://asdf-vm.com/"
52
+ echo " rvm + nvm: https://rvm.io/ + https://github.com/nvm-sh/nvm"
46
53
  exit 1
47
54
  fi
48
55
  }
49
56
 
57
+ set_ruby_version() {
58
+ local version="$1"
59
+ local version_manager="$2"
60
+
61
+ case "$version_manager" in
62
+ mise|asdf)
63
+ # Handled via .tool-versions
64
+ ;;
65
+ rvm|rvm+nvm)
66
+ print_header "Setting Ruby $version with rvm"
67
+ # Check if version exists using rvm list rubies for consistent output
68
+ # Anchor to start of line to avoid false matches (e.g., 3.2.8 shouldn't match 13.2.8)
69
+ # Allow optional leading whitespace and ruby- prefix, no end anchor to allow patch suffixes
70
+ if ! rvm list rubies | grep -qE "^[[:space:]]*(ruby-)?${version}"; then
71
+ print_warning "Ruby $version not installed. Installing..."
72
+ if ! rvm install "$version"; then
73
+ print_error "Failed to install Ruby $version with rvm"
74
+ print_warning "Make sure rvm is properly configured. Try running: source ~/.rvm/scripts/rvm"
75
+ exit 1
76
+ fi
77
+ fi
78
+ if ! rvm use "$version"; then
79
+ print_error "Failed to switch to Ruby $version"
80
+ print_warning "Make sure rvm is properly configured. Try running: source ~/.rvm/scripts/rvm"
81
+ exit 1
82
+ fi
83
+ print_success "Switched to Ruby $version"
84
+ ;;
85
+ nvm)
86
+ print_error "Cannot set Ruby version: nvm doesn't manage Ruby"
87
+ echo "Please install one of the following to manage Ruby versions:"
88
+ echo " - rvm: https://rvm.io/"
89
+ echo " - mise: https://mise.jdx.dev/ (recommended, manages both Ruby and Node)"
90
+ echo " - asdf: https://asdf-vm.com/ (manages both Ruby and Node)"
91
+ exit 1
92
+ ;;
93
+ esac
94
+ }
95
+
96
+ set_node_version() {
97
+ local version="$1"
98
+ local version_manager="$2"
99
+
100
+ case "$version_manager" in
101
+ mise|asdf)
102
+ # Handled via .tool-versions
103
+ ;;
104
+ nvm|rvm+nvm)
105
+ print_header "Setting Node $version with nvm"
106
+
107
+ # Source nvm if not already loaded - try multiple common locations
108
+ if ! command -v nvm &> /dev/null; then
109
+ # Try standard nvm location
110
+ if [ -s "$HOME/.nvm/nvm.sh" ]; then
111
+ export NVM_DIR="$HOME/.nvm"
112
+ \. "$NVM_DIR/nvm.sh"
113
+ # Try Homebrew location (macOS)
114
+ elif [ -s "/opt/homebrew/opt/nvm/nvm.sh" ]; then
115
+ export NVM_DIR="/opt/homebrew/opt/nvm"
116
+ \. "/opt/homebrew/opt/nvm/nvm.sh"
117
+ # Try XDG config location
118
+ elif [ -s "${XDG_CONFIG_HOME:-$HOME/.config}/nvm/nvm.sh" ]; then
119
+ export NVM_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nvm"
120
+ \. "$NVM_DIR/nvm.sh"
121
+ else
122
+ print_error "Could not find nvm installation"
123
+ print_warning "Tried locations: ~/.nvm, /opt/homebrew/opt/nvm, ~/.config/nvm"
124
+ echo "Please source nvm manually or install it from: https://github.com/nvm-sh/nvm"
125
+ exit 1
126
+ fi
127
+ fi
128
+
129
+ # Check if version is already installed using nvm version for reliability
130
+ if ! nvm version "$version" &> /dev/null; then
131
+ print_warning "Node $version not installed. Installing..."
132
+ if ! nvm install "$version"; then
133
+ print_error "Failed to install Node $version with nvm"
134
+ exit 1
135
+ fi
136
+ fi
137
+
138
+ if ! nvm use "$version"; then
139
+ print_error "Failed to switch to Node $version"
140
+ print_warning "Make sure nvm is properly configured. Try running: nvm use $version"
141
+ exit 1
142
+ fi
143
+ print_success "Switched to Node $version"
144
+ ;;
145
+ rvm)
146
+ print_error "Cannot set Node version: rvm doesn't manage Node"
147
+ echo "Please install one of the following to manage Node versions:"
148
+ echo " - nvm: https://github.com/nvm-sh/nvm"
149
+ echo " - mise: https://mise.jdx.dev/ (recommended, manages both Ruby and Node)"
150
+ echo " - asdf: https://asdf-vm.com/ (manages both Ruby and Node)"
151
+ exit 1
152
+ ;;
153
+ esac
154
+ }
155
+
50
156
  show_status() {
51
157
  print_header "Current Configuration"
52
158
  echo ""
@@ -121,12 +227,32 @@ switch_to_minimum() {
121
227
  fi
122
228
 
123
229
  # Set Ruby and Node versions
124
- print_header "Setting runtime versions in .tool-versions"
125
- cat > "$PROJECT_ROOT/.tool-versions" <<EOF
230
+ case "$VERSION_MANAGER" in
231
+ mise|asdf)
232
+ print_header "Setting runtime versions in .tool-versions"
233
+ cat > "$PROJECT_ROOT/.tool-versions" <<EOF
126
234
  ruby 3.2.8
127
235
  nodejs 20.18.1
128
236
  EOF
129
- print_success "Created .tool-versions with Ruby 3.2.8 and Node 20.18.1"
237
+ print_success "Created .tool-versions with Ruby 3.2.8 and Node 20.18.1"
238
+ ;;
239
+ rvm|rvm+nvm)
240
+ print_header "Creating .ruby-version for rvm"
241
+ echo "3.2.8" > "$PROJECT_ROOT/.ruby-version"
242
+ print_success "Created .ruby-version with Ruby 3.2.8"
243
+ ;;
244
+ esac
245
+
246
+ case "$VERSION_MANAGER" in
247
+ nvm|rvm+nvm)
248
+ print_header "Creating .nvmrc for nvm"
249
+ echo "20.18.1" > "$PROJECT_ROOT/.nvmrc"
250
+ print_success "Created .nvmrc with Node 20.18.1"
251
+ ;;
252
+ esac
253
+
254
+ set_ruby_version "3.2.8" "$VERSION_MANAGER"
255
+ set_node_version "20.18.1" "$VERSION_MANAGER"
130
256
 
131
257
  # Run conversion script
132
258
  print_header "Running script/convert to downgrade dependencies"
@@ -158,22 +284,60 @@ EOF
158
284
 
159
285
  # Reload version manager to pick up new versions
160
286
  print_header "Reloading $VERSION_MANAGER to use new versions"
161
- if [[ "$VERSION_MANAGER" == "mise" ]]; then
162
- # mise will auto-detect .tool-versions on next cd
163
- :
164
- elif [ -f "$HOME/.asdf/asdf.sh" ]; then
165
- source "$HOME/.asdf/asdf.sh"
166
- fi
287
+ case "$VERSION_MANAGER" in
288
+ mise)
289
+ # mise will auto-detect .tool-versions on next cd
290
+ ;;
291
+ asdf)
292
+ # Note: This only affects the script's subshell, not the user's current shell
293
+ if [ -f "$HOME/.asdf/asdf.sh" ]; then
294
+ source "$HOME/.asdf/asdf.sh"
295
+ fi
296
+ ;;
297
+ rvm|rvm+nvm)
298
+ # Versions already set via rvm use
299
+ ;;
300
+ nvm)
301
+ # Version already set via nvm use
302
+ ;;
303
+ esac
167
304
 
168
305
  echo ""
169
306
  print_success "Switched to MINIMUM configuration"
170
- print_warning "Run these commands to reload your shell and verify:"
307
+
308
+ case "$VERSION_MANAGER" in
309
+ rvm+nvm|rvm|nvm)
310
+ print_warning "IMPORTANT: Version changes in this script don't persist to your current shell."
311
+ print_warning "The rvm/nvm commands run in a subshell and cannot affect your terminal."
312
+ echo ""
313
+ print_warning "Choose one of these options to activate the new versions:"
314
+ echo " Option 1 (Recommended): Open a new terminal and cd into the project"
315
+ echo " Option 2: Source your shell config:"
316
+ [ "$VERSION_MANAGER" = "rvm" ] || [ "$VERSION_MANAGER" = "rvm+nvm" ] && echo " source ~/.rvm/scripts/rvm"
317
+ [ "$VERSION_MANAGER" = "nvm" ] || [ "$VERSION_MANAGER" = "rvm+nvm" ] && echo " source \$NVM_DIR/nvm.sh"
318
+ echo ""
319
+ ;;
320
+ esac
321
+
322
+ print_warning "After activating versions, verify with:"
171
323
  echo " cd $PROJECT_ROOT"
172
- if [[ "$VERSION_MANAGER" == "mise" ]]; then
173
- echo " mise current"
174
- else
175
- echo " asdf current"
176
- fi
324
+ case "$VERSION_MANAGER" in
325
+ mise)
326
+ echo " mise current"
327
+ ;;
328
+ asdf)
329
+ echo " asdf current"
330
+ ;;
331
+ rvm+nvm)
332
+ echo " rvm current && nvm current"
333
+ ;;
334
+ rvm)
335
+ echo " rvm current"
336
+ ;;
337
+ nvm)
338
+ echo " nvm current"
339
+ ;;
340
+ esac
177
341
  echo ""
178
342
  print_warning "Next steps to build and test:"
179
343
  echo " rake node_package"
@@ -201,12 +365,32 @@ restore_to_latest() {
201
365
  fi
202
366
 
203
367
  # Set Ruby and Node versions
204
- print_header "Setting runtime versions in .tool-versions"
205
- cat > "$PROJECT_ROOT/.tool-versions" <<EOF
368
+ case "$VERSION_MANAGER" in
369
+ mise|asdf)
370
+ print_header "Setting runtime versions in .tool-versions"
371
+ cat > "$PROJECT_ROOT/.tool-versions" <<EOF
206
372
  ruby 3.4.3
207
373
  nodejs 22.12.0
208
374
  EOF
209
- print_success "Created .tool-versions with Ruby 3.4.3 and Node 22.12.0"
375
+ print_success "Created .tool-versions with Ruby 3.4.3 and Node 22.12.0"
376
+ ;;
377
+ rvm|rvm+nvm)
378
+ print_header "Creating .ruby-version for rvm"
379
+ echo "3.4.3" > "$PROJECT_ROOT/.ruby-version"
380
+ print_success "Created .ruby-version with Ruby 3.4.3"
381
+ ;;
382
+ esac
383
+
384
+ case "$VERSION_MANAGER" in
385
+ nvm|rvm+nvm)
386
+ print_header "Creating .nvmrc for nvm"
387
+ echo "22.12.0" > "$PROJECT_ROOT/.nvmrc"
388
+ print_success "Created .nvmrc with Node 22.12.0"
389
+ ;;
390
+ esac
391
+
392
+ set_ruby_version "3.4.3" "$VERSION_MANAGER"
393
+ set_node_version "22.12.0" "$VERSION_MANAGER"
210
394
 
211
395
  # Restore files from git
212
396
  print_header "Restoring dependency files from git"
@@ -238,22 +422,60 @@ EOF
238
422
 
239
423
  # Reload version manager to pick up new versions
240
424
  print_header "Reloading $VERSION_MANAGER to use new versions"
241
- if [[ "$VERSION_MANAGER" == "mise" ]]; then
242
- # mise will auto-detect .tool-versions on next cd
243
- :
244
- elif [ -f "$HOME/.asdf/asdf.sh" ]; then
245
- source "$HOME/.asdf/asdf.sh"
246
- fi
425
+ case "$VERSION_MANAGER" in
426
+ mise)
427
+ # mise will auto-detect .tool-versions on next cd
428
+ ;;
429
+ asdf)
430
+ # Note: This only affects the script's subshell, not the user's current shell
431
+ if [ -f "$HOME/.asdf/asdf.sh" ]; then
432
+ source "$HOME/.asdf/asdf.sh"
433
+ fi
434
+ ;;
435
+ rvm|rvm+nvm)
436
+ # Versions already set via rvm use
437
+ ;;
438
+ nvm)
439
+ # Version already set via nvm use
440
+ ;;
441
+ esac
247
442
 
248
443
  echo ""
249
444
  print_success "Restored to LATEST configuration"
250
- print_warning "Run these commands to reload your shell and verify:"
445
+
446
+ case "$VERSION_MANAGER" in
447
+ rvm+nvm|rvm|nvm)
448
+ print_warning "IMPORTANT: Version changes in this script don't persist to your current shell."
449
+ print_warning "The rvm/nvm commands run in a subshell and cannot affect your terminal."
450
+ echo ""
451
+ print_warning "Choose one of these options to activate the new versions:"
452
+ echo " Option 1 (Recommended): Open a new terminal and cd into the project"
453
+ echo " Option 2: Source your shell config:"
454
+ [ "$VERSION_MANAGER" = "rvm" ] || [ "$VERSION_MANAGER" = "rvm+nvm" ] && echo " source ~/.rvm/scripts/rvm"
455
+ [ "$VERSION_MANAGER" = "nvm" ] || [ "$VERSION_MANAGER" = "rvm+nvm" ] && echo " source \$NVM_DIR/nvm.sh"
456
+ echo ""
457
+ ;;
458
+ esac
459
+
460
+ print_warning "After activating versions, verify with:"
251
461
  echo " cd $PROJECT_ROOT"
252
- if [[ "$VERSION_MANAGER" == "mise" ]]; then
253
- echo " mise current"
254
- else
255
- echo " asdf current"
256
- fi
462
+ case "$VERSION_MANAGER" in
463
+ mise)
464
+ echo " mise current"
465
+ ;;
466
+ asdf)
467
+ echo " asdf current"
468
+ ;;
469
+ rvm+nvm)
470
+ echo " rvm current && nvm current"
471
+ ;;
472
+ rvm)
473
+ echo " rvm current"
474
+ ;;
475
+ nvm)
476
+ echo " nvm current"
477
+ ;;
478
+ esac
257
479
  echo ""
258
480
  print_warning "Next steps to build and test:"
259
481
  echo " rake node_package"
@@ -16,23 +16,13 @@ else
16
16
  echo "🔍 Checking trailing newlines on $CONTEXT files..."
17
17
  fi
18
18
 
19
- failed_files=""
20
19
  for file in $files; do
21
20
  if [ -f "$file" ] && [ -s "$file" ]; then
22
21
  if ! tail -c 1 "$file" | grep -q '^$'; then
23
- echo " Missing trailing newline: $file"
24
- failed_files="$failed_files $file"
22
+ echo "🔧 Adding trailing newline to: $file"
23
+ echo >> "$file"
25
24
  fi
26
25
  fi
27
26
  done
28
27
 
29
- if [ -n "$failed_files" ]; then
30
- echo ""
31
- echo "❌ Trailing newline check failed!"
32
- echo "💡 Add trailing newlines to:$failed_files"
33
- echo "🔧 Quick fix: for file in$failed_files; do echo >> \"\$file\"; done"
34
- echo "🚫 Skip hook: git commit --no-verify"
35
- exit 1
36
- fi
37
-
38
28
  echo "✅ All files have proper trailing newlines"
@@ -34,11 +34,6 @@ if [ -n "$root_and_packages_pro_files" ]; then
34
34
  if ! yarn run eslint $root_and_packages_pro_files --fix; then
35
35
  exit_code=1
36
36
  fi
37
-
38
- # Re-stage files if running on staged or all-changed context
39
- if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
40
- echo $root_and_packages_pro_files | xargs -r git add
41
- fi
42
37
  fi
43
38
 
44
39
  # Lint react_on_rails_pro files (using Pro gem's ESLint config)
@@ -56,11 +51,6 @@ if [ -n "$react_on_rails_pro_files" ]; then
56
51
  if ! (cd react_on_rails_pro && yarn run eslint $react_on_rails_pro_files_relative --fix); then
57
52
  exit_code=1
58
53
  fi
59
-
60
- # Re-stage files if running on staged or all-changed context
61
- if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
62
- echo $react_on_rails_pro_files | xargs -r git add
63
- fi
64
54
  fi
65
55
 
66
56
  if [ $exit_code -eq 0 ]; then
@@ -24,11 +24,6 @@ if [ -n "$root_files" ]; then
24
24
  printf " %s\n" $root_files
25
25
 
26
26
  yarn run prettier --write $root_files
27
-
28
- # Re-stage files if running on staged or all-changed context
29
- if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
30
- echo $root_files | xargs -r git add
31
- fi
32
27
  fi
33
28
 
34
29
  # Format Pro files (using Pro's Prettier config)
@@ -44,11 +39,6 @@ if [ -n "$pro_files" ]; then
44
39
  pro_files_relative=$(echo "$pro_files" | sed 's|^react_on_rails_pro/||')
45
40
 
46
41
  (cd react_on_rails_pro && yarn run prettier --write $pro_files_relative)
47
-
48
- # Re-stage files if running on staged or all-changed context
49
- if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
50
- echo $pro_files | xargs -r git add
51
- fi
52
42
  fi
53
43
 
54
44
  echo "✅ Prettier formatting complete"
@@ -19,8 +19,4 @@ printf " %s\n" $files
19
19
 
20
20
  bundle exec rake autofix
21
21
 
22
- # Re-stage files if running on staged or all-changed context
23
- if [ "$CONTEXT" = "staged" ] || [ "$CONTEXT" = "all-changed" ]; then
24
- echo $files | xargs -r git add
25
- echo "✅ Re-staged formatted files"
26
- fi
22
+ echo "✅ Auto-fix complete (fixed files staged automatically)"
@@ -41,8 +41,6 @@ module ReactOnRails
41
41
  components_subdirectory: nil,
42
42
  make_generated_server_bundle_the_entrypoint: false,
43
43
  defer_generated_component_packs: false,
44
- # React on Rails Pro (licensed) feature - enables immediate hydration of React components
45
- immediate_hydration: false,
46
44
  # Maximum time in milliseconds to wait for client-side component registration after page load.
47
45
  # If exceeded, an error will be thrown for server-side rendered components not registered on the client.
48
46
  # Set to 0 to disable the timeout and wait indefinitely for component registration.
@@ -64,10 +62,55 @@ module ReactOnRails
64
62
  :server_render_method, :random_dom_id, :auto_load_bundle,
65
63
  :same_bundle_for_client_and_server, :rendering_props_extension,
66
64
  :make_generated_server_bundle_the_entrypoint,
67
- :generated_component_packs_loading_strategy, :immediate_hydration,
65
+ :generated_component_packs_loading_strategy,
68
66
  :component_registry_timeout,
69
67
  :server_bundle_output_path, :enforce_private_server_bundles
70
68
 
69
+ # Class instance variable and mutex to track if deprecation warning has been shown
70
+ # Using mutex to ensure thread-safety in multi-threaded environments
71
+ @immediate_hydration_warned = false
72
+ @immediate_hydration_mutex = Mutex.new
73
+
74
+ class << self
75
+ attr_accessor :immediate_hydration_warned, :immediate_hydration_mutex
76
+ end
77
+
78
+ # Deprecated: immediate_hydration configuration has been removed
79
+ def immediate_hydration=(value)
80
+ warned = false
81
+ self.class.immediate_hydration_mutex.synchronize do
82
+ warned = self.class.immediate_hydration_warned
83
+ self.class.immediate_hydration_warned = true unless warned
84
+ end
85
+
86
+ return if warned
87
+
88
+ Rails.logger.warn <<~WARNING
89
+ [REACT ON RAILS] The 'config.immediate_hydration' configuration option is deprecated and no longer used.
90
+ Immediate hydration is now automatically enabled for React on Rails Pro users.
91
+ Please remove 'config.immediate_hydration = #{value}' from your config/initializers/react_on_rails.rb file.
92
+ See CHANGELOG.md for migration instructions.
93
+ WARNING
94
+ end
95
+
96
+ def immediate_hydration
97
+ warned = false
98
+ self.class.immediate_hydration_mutex.synchronize do
99
+ warned = self.class.immediate_hydration_warned
100
+ self.class.immediate_hydration_warned = true unless warned
101
+ end
102
+
103
+ return nil if warned
104
+
105
+ Rails.logger.warn <<~WARNING
106
+ [REACT ON RAILS] The 'config.immediate_hydration' configuration option is deprecated and no longer used.
107
+ Immediate hydration is now automatically enabled for React on Rails Pro users.
108
+ Please remove any references to 'config.immediate_hydration' from your config/initializers/react_on_rails.rb file.
109
+ See CHANGELOG.md for migration instructions.
110
+ WARNING
111
+ nil
112
+ end
113
+
71
114
  # rubocop:disable Metrics/AbcSize
72
115
  def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
73
116
  replay_console: nil, make_generated_server_bundle_the_entrypoint: nil,
@@ -81,7 +124,7 @@ module ReactOnRails
81
124
  same_bundle_for_client_and_server: nil,
82
125
  i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil, i18n_yml_safe_load_options: nil,
83
126
  random_dom_id: nil, server_render_method: nil, rendering_props_extension: nil,
84
- components_subdirectory: nil, auto_load_bundle: nil, immediate_hydration: nil,
127
+ components_subdirectory: nil, auto_load_bundle: nil,
85
128
  component_registry_timeout: nil, server_bundle_output_path: nil, enforce_private_server_bundles: nil)
86
129
  self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
87
130
  self.generated_assets_dirs = generated_assets_dirs
@@ -122,7 +165,6 @@ module ReactOnRails
122
165
  self.auto_load_bundle = auto_load_bundle
123
166
  self.make_generated_server_bundle_the_entrypoint = make_generated_server_bundle_the_entrypoint
124
167
  self.defer_generated_component_packs = defer_generated_component_packs
125
- self.immediate_hydration = immediate_hydration
126
168
  self.generated_component_packs_loading_strategy = generated_component_packs_loading_strategy
127
169
  self.server_bundle_output_path = server_bundle_output_path
128
170
  self.enforce_private_server_bundles = enforce_private_server_bundles
@@ -154,9 +196,9 @@ module ReactOnRails
154
196
  raise ReactOnRails::Error, "component_registry_timeout must be a positive integer"
155
197
  end
156
198
 
157
- # rubocop:disable Metrics/CyclomaticComplexity
199
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
158
200
  def validate_generated_component_packs_loading_strategy
159
- # rubocop:enable Metrics/CyclomaticComplexity
201
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
160
202
 
161
203
  if defer_generated_component_packs
162
204
  if %i[async sync].include?(generated_component_packs_loading_strategy)
@@ -176,11 +218,13 @@ module ReactOnRails
176
218
  1. Use :defer or :sync loading strategy instead of :async
177
219
  2. Upgrade to Shakapacker v8.2.0 or above to enable async script loading
178
220
  MSG
179
- if generated_component_packs_loading_strategy.nil?
180
- # Use defer as the default to ensure generated component packs load and register
181
- # components before main bundle executes, avoiding race conditions with async loading
182
- self.generated_component_packs_loading_strategy = :defer
183
- elsif generated_component_packs_loading_strategy == :async && !PackerUtils.supports_async_loading?
221
+ if PackerUtils.supports_async_loading?
222
+ # Default based on Pro license: Pro users get :async, non-Pro users get :defer
223
+ self.generated_component_packs_loading_strategy ||= (Utils.react_on_rails_pro? ? :async : :defer)
224
+ elsif generated_component_packs_loading_strategy.nil?
225
+ Rails.logger.warn("**WARNING** #{msg}")
226
+ self.generated_component_packs_loading_strategy = :sync
227
+ elsif generated_component_packs_loading_strategy == :async
184
228
  raise ReactOnRails::Error, "**ERROR** #{msg}"
185
229
  end
186
230
 
@@ -9,13 +9,13 @@ 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. Pass as true if you wish to hydrate this
13
- # store immediately instead of waiting for the page to load.
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
14
  #
15
15
  # Be sure to include view helper `redux_store_hydration_data` at the end of your layout or view
16
16
  # or else there will be no client side hydration of your stores.
17
17
  def redux_store(store_name, props: {}, immediate_hydration: nil)
18
- immediate_hydration = ReactOnRails.configuration.immediate_hydration if immediate_hydration.nil?
18
+ immediate_hydration = ReactOnRails::Utils.normalize_immediate_hydration(immediate_hydration, store_name, "Store")
19
19
  redux_store_data = { store_name: store_name,
20
20
  props: props,
21
21
  immediate_hydration: immediate_hydration }
@@ -732,10 +732,12 @@ module ReactOnRails
732
732
  auto_load_match = content.match(/config\.auto_load_bundle\s*=\s*([^\s\n,]+)/)
733
733
  checker.add_info(" auto_load_bundle: #{auto_load_match[1]}") if auto_load_match
734
734
 
735
- # Immediate hydration (Pro feature)
735
+ # Deprecated immediate_hydration setting
736
736
  immediate_hydration_match = content.match(/config\.immediate_hydration\s*=\s*([^\s\n,]+)/)
737
737
  if immediate_hydration_match
738
- checker.add_info(" immediate_hydration: #{immediate_hydration_match[1]} (React on Rails Pro)")
738
+ checker.add_warning(" ⚠️ immediate_hydration: #{immediate_hydration_match[1]} (DEPRECATED)")
739
+ checker.add_info(" 💡 This setting is no longer used. Immediate hydration is now automatic for Pro users.")
740
+ checker.add_info(" 💡 Remove this line from your config/initializers/react_on_rails.rb file.")
739
741
  end
740
742
 
741
743
  # Component registry timeout
@@ -155,10 +155,10 @@ module ReactOnRails
155
155
  # props: Ruby Hash or JSON string which contains the properties to pass to the redux store.
156
156
  # Options
157
157
  # defer: false -- pass as true if you wish to render this below your component.
158
- # immediate_hydration: false -- React on Rails Pro (licensed) feature. Pass as true if you wish to
159
- # hydrate this store immediately instead of waiting for the page to load.
158
+ # immediate_hydration: nil -- React on Rails Pro (licensed) feature. When nil (default), Pro users
159
+ # get immediate hydration, non-Pro users don't. Can be explicitly overridden.
160
160
  def redux_store(store_name, props: {}, defer: false, immediate_hydration: nil)
161
- immediate_hydration = ReactOnRails.configuration.immediate_hydration if immediate_hydration.nil?
161
+ immediate_hydration = ReactOnRails::Utils.normalize_immediate_hydration(immediate_hydration, store_name, "Store")
162
162
 
163
163
  redux_store_data = { store_name: store_name,
164
164
  props: props,
@@ -2,10 +2,6 @@
2
2
 
3
3
  module ReactOnRails
4
4
  module ProHelper
5
- IMMEDIATE_HYDRATION_PRO_WARNING = "[REACT ON RAILS] The 'immediate_hydration' feature requires a " \
6
- "React on Rails Pro license. " \
7
- "Please visit https://shakacode.com/react-on-rails-pro to learn more."
8
-
9
5
  # Generates the complete component specification script tag.
10
6
  # Handles both immediate hydration (Pro feature) and standard cases.
11
7
  def generate_component_script(render_options)
@@ -36,17 +32,12 @@ module ReactOnRails
36
32
  component_specification_tag
37
33
  end
38
34
 
39
- pro_warning_badge = pro_warning_badge_if_needed(render_options.explicitly_disabled_pro_options)
40
- "#{pro_warning_badge}\n#{spec_tag}".html_safe
35
+ spec_tag.html_safe
41
36
  end
42
37
 
43
38
  # Generates the complete store hydration script tag.
44
39
  # Handles both immediate hydration (Pro feature) and standard cases.
45
40
  def generate_store_script(redux_store_data)
46
- pro_options_check_result = ReactOnRails::ProUtils.disable_pro_render_options_if_not_licensed(redux_store_data)
47
- redux_store_data = pro_options_check_result[:raw_options]
48
- explicitly_disabled_pro_options = pro_options_check_result[:explicitly_disabled_pro_options]
49
-
50
41
  store_hydration_data = content_tag(:script,
51
42
  json_safe_and_pretty(redux_store_data[:props]).html_safe,
52
43
  type: "application/json",
@@ -67,40 +58,7 @@ module ReactOnRails
67
58
  store_hydration_data
68
59
  end
69
60
 
70
- pro_warning_badge = pro_warning_badge_if_needed(explicitly_disabled_pro_options)
71
- "#{pro_warning_badge}\n#{store_hydration_scripts}".html_safe
72
- end
73
-
74
- def pro_warning_badge_if_needed(explicitly_disabled_pro_options)
75
- return "" unless explicitly_disabled_pro_options.any?
76
-
77
- disabled_features_message = disabled_pro_features_message(explicitly_disabled_pro_options)
78
- warning_message = "[REACT ON RAILS] #{disabled_features_message}\n" \
79
- "Please visit https://shakacode.com/react-on-rails-pro to learn more."
80
- puts warning_message
81
- Rails.logger.warn warning_message
82
-
83
- tooltip_text = "#{disabled_features_message} Click to learn more."
84
-
85
- <<~HTML.strip
86
- <a href="https://shakacode.com/react-on-rails-pro" target="_blank" rel="noopener noreferrer" title="#{tooltip_text}">
87
- <div style="position: fixed; top: 0; right: 0; width: 180px; height: 180px; overflow: hidden; z-index: 9999; pointer-events: none;">
88
- <div style="position: absolute; top: 50px; right: -40px; transform: rotate(45deg); background-color: rgba(220, 53, 69, 0.85); color: white; padding: 7px 40px; text-align: center; font-weight: bold; font-family: sans-serif; font-size: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.3); pointer-events: auto;">
89
- React On Rails Pro Required
90
- </div>
91
- </div>
92
- </a>
93
- HTML
94
- end
95
-
96
- def disabled_pro_features_message(explicitly_disabled_pro_options)
97
- return "".html_safe unless explicitly_disabled_pro_options.any?
98
-
99
- feature_list = explicitly_disabled_pro_options.join(", ")
100
- feature_word = explicitly_disabled_pro_options.size == 1 ? "feature" : "features"
101
- "The '#{feature_list}' #{feature_word} " \
102
- "#{explicitly_disabled_pro_options.size == 1 ? 'requires' : 'require'} a " \
103
- "React on Rails Pro license. "
61
+ store_hydration_scripts.html_safe
104
62
  end
105
63
  end
106
64
  end