react_on_rails 16.2.0.beta.4 → 16.2.0.beta.10

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -8
  3. data/CONTRIBUTING.md +1 -1
  4. data/Gemfile.development_dependencies +0 -1
  5. data/Gemfile.lock +1 -9
  6. data/bin/ci-rerun-failures +39 -16
  7. data/bin/ci-run-failed-specs +1 -1
  8. data/bin/ci-switch-config +8 -2
  9. data/bin/lefthook/ruby-autofix +2 -1
  10. data/knip.ts +35 -9
  11. data/lib/generators/react_on_rails/base_generator.rb +3 -118
  12. data/lib/generators/react_on_rails/install_generator.rb +5 -180
  13. data/lib/generators/react_on_rails/js_dependency_manager.rb +332 -0
  14. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +32 -52
  15. data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml +14 -3
  16. data/lib/react_on_rails/dev/server_manager.rb +11 -4
  17. data/lib/react_on_rails/doctor.rb +245 -0
  18. data/lib/react_on_rails/engine.rb +2 -5
  19. data/lib/react_on_rails/helper.rb +9 -0
  20. data/lib/react_on_rails/version.rb +1 -1
  21. data/react_on_rails_pro/CHANGELOG.md +7 -0
  22. data/react_on_rails_pro/CONTRIBUTING.md +2 -13
  23. data/react_on_rails_pro/Gemfile.lock +21 -3
  24. data/react_on_rails_pro/docs/code-splitting-loadable-components.md +1 -1
  25. data/react_on_rails_pro/docs/contributors-info/releasing.md +2 -2
  26. data/react_on_rails_pro/docs/installation.md +106 -104
  27. data/react_on_rails_pro/docs/node-renderer/basics.md +3 -3
  28. data/react_on_rails_pro/docs/node-renderer/error-reporting-and-tracing.md +8 -8
  29. data/react_on_rails_pro/docs/node-renderer/js-configuration.md +1 -1
  30. data/react_on_rails_pro/docs/updating.md +209 -15
  31. data/react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb +58 -4
  32. data/react_on_rails_pro/lib/react_on_rails_pro/configuration.rb +17 -3
  33. data/react_on_rails_pro/lib/react_on_rails_pro/license_public_key.rb +9 -9
  34. data/react_on_rails_pro/lib/react_on_rails_pro/request.rb +41 -25
  35. data/react_on_rails_pro/lib/react_on_rails_pro/stream_request.rb +27 -7
  36. data/react_on_rails_pro/lib/react_on_rails_pro/utils.rb +3 -3
  37. data/react_on_rails_pro/lib/react_on_rails_pro/version.rb +1 -1
  38. data/react_on_rails_pro/package-scripts.yml +1 -1
  39. data/react_on_rails_pro/package.json +5 -8
  40. data/react_on_rails_pro/packages/node-renderer/src/integrations/api.ts +1 -1
  41. data/react_on_rails_pro/rakelib/public_key_management.rake +6 -5
  42. data/react_on_rails_pro/react_on_rails_pro.gemspec +1 -0
  43. data/react_on_rails_pro/spec/dummy/Gemfile.lock +20 -3
  44. data/react_on_rails_pro/spec/dummy/app/controllers/pages_controller.rb +3 -3
  45. data/react_on_rails_pro/spec/dummy/bin/dev +4 -8
  46. data/react_on_rails_pro/spec/dummy/bin/shakapacker-precompile-hook +19 -0
  47. data/react_on_rails_pro/spec/dummy/client/node-renderer.js +3 -3
  48. data/react_on_rails_pro/spec/dummy/config/environments/production.rb +1 -1
  49. data/react_on_rails_pro/spec/dummy/config/initializers/react_on_rails.rb +28 -12
  50. data/react_on_rails_pro/spec/dummy/config/shakapacker.yml +5 -0
  51. data/react_on_rails_pro/spec/dummy/config.ru +1 -1
  52. data/react_on_rails_pro/spec/dummy/package.json +2 -2
  53. data/react_on_rails_pro/spec/dummy/spec/helpers/react_on_rails_pro_helper_spec.rb +40 -11
  54. data/react_on_rails_pro/spec/dummy/spec/rails_helper.rb +1 -1
  55. data/react_on_rails_pro/spec/dummy/spec/requests/renderer_console_logging_spec.rb +5 -5
  56. data/react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb +20 -14
  57. data/react_on_rails_pro/spec/dummy/spec/system/renderer_integration_spec.rb +3 -3
  58. data/react_on_rails_pro/spec/dummy/yarn.lock +4 -4
  59. data/react_on_rails_pro/spec/execjs-compatible-dummy/config/environments/production.rb +1 -1
  60. data/react_on_rails_pro/spec/execjs-compatible-dummy/config/initializers/react_on_rails.rb +16 -43
  61. data/react_on_rails_pro/spec/react_on_rails_pro/assets_precompile_spec.rb +15 -18
  62. data/react_on_rails_pro/spec/react_on_rails_pro/cache_spec.rb +1 -1
  63. data/react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb +5 -3
  64. data/react_on_rails_pro/spec/react_on_rails_pro/license_validator_spec.rb +27 -12
  65. data/react_on_rails_pro/spec/react_on_rails_pro/request_spec.rb +0 -27
  66. data/react_on_rails_pro/spec/react_on_rails_pro/spec_helper.rb +1 -1
  67. data/react_on_rails_pro/spec/react_on_rails_pro/stream_decorator_spec.rb +89 -0
  68. data/react_on_rails_pro/spec/react_on_rails_pro/stream_spec.rb +144 -0
  69. data/react_on_rails_pro/spec/react_on_rails_pro/support/caching.rb +1 -1
  70. data/react_on_rails_pro/spec/react_on_rails_pro/support/mock_block_helper.rb +4 -2
  71. data/sig/react_on_rails/generators/js_dependency_manager.rbs +123 -0
  72. metadata +5 -3
  73. data/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/TestingStreamableComponent.jsx +0 -15
@@ -4,12 +4,14 @@ require "rails/generators"
4
4
  require "json"
5
5
  require_relative "generator_helper"
6
6
  require_relative "generator_messages"
7
+ require_relative "js_dependency_manager"
7
8
 
8
9
  module ReactOnRails
9
10
  module Generators
10
11
  # rubocop:disable Metrics/ClassLength
11
12
  class InstallGenerator < Rails::Generators::Base
12
13
  include GeneratorHelper
14
+ include JsDependencyManager
13
15
 
14
16
  # fetch USAGE file for details generator description
15
17
  source_root(File.expand_path(__dir__))
@@ -113,10 +115,7 @@ module ReactOnRails
113
115
  end
114
116
 
115
117
  def setup_react_dependencies
116
- @added_dependencies_to_package_json ||= false
117
- @ran_direct_installs ||= false
118
- add_js_dependencies
119
- install_js_dependencies if @added_dependencies_to_package_json && !@ran_direct_installs
118
+ setup_js_dependencies
120
119
  end
121
120
 
122
121
  # NOTE: other requirements for existing files such as .gitignore or application.
@@ -366,29 +365,8 @@ module ReactOnRails
366
365
 
367
366
  def install_typescript_dependencies
368
367
  puts Rainbow("📝 Installing TypeScript dependencies...").yellow
369
-
370
- # Install TypeScript and React type definitions
371
- typescript_packages = %w[
372
- typescript
373
- @types/react
374
- @types/react-dom
375
- @babel/preset-typescript
376
- ]
377
-
378
- # Try using GeneratorHelper first (package manager agnostic)
379
- return if add_npm_dependencies(typescript_packages, dev: true)
380
-
381
- # Fallback to npm if GeneratorHelper fails
382
- success = system("npm", "install", "--save-dev", *typescript_packages)
383
- return if success
384
-
385
- warning = <<~MSG.strip
386
- ⚠️ Failed to install TypeScript dependencies automatically.
387
-
388
- Please run manually:
389
- npm install --save-dev #{typescript_packages.join(' ')}
390
- MSG
391
- GeneratorMessages.add_warning(warning)
368
+ # Delegate to shared module for consistent dependency management
369
+ add_typescript_dependencies
392
370
  end
393
371
 
394
372
  def create_css_module_types
@@ -450,159 +428,6 @@ module ReactOnRails
450
428
  puts Rainbow("✅ Created tsconfig.json").green
451
429
  end
452
430
 
453
- def add_js_dependencies
454
- add_react_on_rails_package
455
- add_react_dependencies
456
- add_css_dependencies
457
- add_rspack_dependencies if options.rspack?
458
- add_dev_dependencies
459
- end
460
-
461
- def add_react_on_rails_package
462
- major_minor_patch_only = /\A\d+\.\d+\.\d+\z/
463
-
464
- # Try to use package_json gem first, fall back to direct npm commands
465
- react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
466
- ["react-on-rails@#{ReactOnRails::VERSION}"]
467
- else
468
- puts "Adding the latest react-on-rails NPM module. " \
469
- "Double check this is correct in package.json"
470
- ["react-on-rails"]
471
- end
472
-
473
- puts "Installing React on Rails package..."
474
- if add_npm_dependencies(react_on_rails_pkg)
475
- @added_dependencies_to_package_json = true
476
- return
477
- end
478
-
479
- puts "Using direct npm commands as fallback"
480
- success = system("npm", "install", *react_on_rails_pkg)
481
- @ran_direct_installs = true if success
482
- handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
483
- end
484
-
485
- def add_react_dependencies
486
- puts "Installing React dependencies..."
487
- react_deps = %w[
488
- react
489
- react-dom
490
- @babel/preset-react
491
- prop-types
492
- babel-plugin-transform-react-remove-prop-types
493
- babel-plugin-macros
494
- ]
495
- if add_npm_dependencies(react_deps)
496
- @added_dependencies_to_package_json = true
497
- return
498
- end
499
-
500
- success = system("npm", "install", *react_deps)
501
- @ran_direct_installs = true if success
502
- handle_npm_failure("React dependencies", react_deps) unless success
503
- end
504
-
505
- def add_css_dependencies
506
- puts "Installing CSS handling dependencies..."
507
- css_deps = %w[
508
- css-loader
509
- css-minimizer-webpack-plugin
510
- mini-css-extract-plugin
511
- style-loader
512
- ]
513
- if add_npm_dependencies(css_deps)
514
- @added_dependencies_to_package_json = true
515
- return
516
- end
517
-
518
- success = system("npm", "install", *css_deps)
519
- @ran_direct_installs = true if success
520
- handle_npm_failure("CSS dependencies", css_deps) unless success
521
- end
522
-
523
- def add_rspack_dependencies
524
- puts "Installing Rspack core dependencies..."
525
- rspack_deps = %w[
526
- @rspack/core
527
- rspack-manifest-plugin
528
- ]
529
- if add_npm_dependencies(rspack_deps)
530
- @added_dependencies_to_package_json = true
531
- return
532
- end
533
-
534
- success = system("npm", "install", *rspack_deps)
535
- @ran_direct_installs = true if success
536
- handle_npm_failure("Rspack dependencies", rspack_deps) unless success
537
- end
538
-
539
- def add_dev_dependencies
540
- puts "Installing development dependencies..."
541
- dev_deps = if options.rspack?
542
- %w[
543
- @rspack/cli
544
- @rspack/plugin-react-refresh
545
- react-refresh
546
- ]
547
- else
548
- %w[
549
- @pmmmwh/react-refresh-webpack-plugin
550
- react-refresh
551
- ]
552
- end
553
- if add_npm_dependencies(dev_deps, dev: true)
554
- @added_dependencies_to_package_json = true
555
- return
556
- end
557
-
558
- success = system("npm", "install", "--save-dev", *dev_deps)
559
- @ran_direct_installs = true if success
560
- handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
561
- end
562
-
563
- def install_js_dependencies
564
- # Detect which package manager to use
565
- success = if File.exist?(File.join(destination_root, "yarn.lock"))
566
- system("yarn", "install")
567
- elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
568
- system("pnpm", "install")
569
- elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
570
- File.exist?(File.join(destination_root, "package.json"))
571
- # Use npm for package-lock.json or as default fallback
572
- system("npm", "install")
573
- else
574
- true # No package manager detected, skip
575
- end
576
-
577
- unless success
578
- GeneratorMessages.add_warning(<<~MSG.strip)
579
- ⚠️ JavaScript dependencies installation failed.
580
-
581
- This could be due to network issues or missing package manager.
582
- You can install dependencies manually later by running:
583
- • npm install (if using npm)
584
- • yarn install (if using yarn)
585
- • pnpm install (if using pnpm)
586
- MSG
587
- end
588
-
589
- success
590
- end
591
-
592
- def handle_npm_failure(dependency_type, packages, dev: false)
593
- install_command = dev ? "npm install --save-dev" : "npm install"
594
- GeneratorMessages.add_warning(<<~MSG.strip)
595
- ⚠️ Failed to install #{dependency_type}.
596
-
597
- The following packages could not be installed automatically:
598
- #{packages.map { |pkg| " • #{pkg}" }.join("\n")}
599
-
600
- This could be due to network issues or missing package manager.
601
- You can install them manually later by running:
602
- #{install_command} #{packages.join(' ')}
603
- MSG
604
- end
605
-
606
431
  # Removed: Shakapacker auto-installation logic (now explicit dependency)
607
432
 
608
433
  # Removed: Shakapacker 8+ is now required as explicit dependency
@@ -0,0 +1,332 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "generator_messages"
4
+
5
+ # rubocop:disable Metrics/ModuleLength
6
+ module ReactOnRails
7
+ module Generators
8
+ # Shared module for managing JavaScript dependencies across generators
9
+ # This module provides common functionality for adding and installing
10
+ # JS dependencies to avoid code duplication between generators.
11
+ #
12
+ # Since react_on_rails requires shakapacker, and shakapacker includes
13
+ # package_json as a dependency, the package_json gem is always available.
14
+ #
15
+ # == Required Methods
16
+ # Including classes must include GeneratorHelper module which provides:
17
+ # - add_npm_dependencies(packages, dev: false): Add packages via package_json gem
18
+ # - package_json: Access to PackageJson instance (always available via shakapacker)
19
+ # - destination_root: Generator destination directory
20
+ #
21
+ # == Optional Methods
22
+ # Including classes may define:
23
+ # - options.rspack?: Returns true if --rspack flag is set (for Rspack support)
24
+ # - options.typescript?: Returns true if --typescript flag is set (for TypeScript support)
25
+ #
26
+ # == Installation Behavior
27
+ # The module ALWAYS runs package manager install after adding dependencies.
28
+ # This is safe because package_json gem's install method is idempotent - it only
29
+ # installs what's actually needed from package.json. This prevents edge cases
30
+ # where package.json was modified but dependencies weren't installed.
31
+ #
32
+ # == Error Handling Philosophy
33
+ # All dependency addition methods use a graceful degradation approach:
34
+ # - Methods return false on failure instead of raising exceptions
35
+ # - StandardError is caught at the lowest level (add_package) and higher levels (add_*_dependencies)
36
+ # - Failures trigger user-facing warnings via GeneratorMessages
37
+ # - Warnings provide clear manual installation instructions
38
+ #
39
+ # This ensures the generator ALWAYS completes successfully, even when:
40
+ # - Network connectivity issues prevent package downloads
41
+ # - Package manager (npm/yarn/pnpm) has permission errors
42
+ # - package_json gem encounters unexpected states
43
+ #
44
+ # Users can manually run package installation commands after generator completion.
45
+ # This is preferable to generator crashes that leave Rails apps in incomplete states.
46
+ #
47
+ # == Usage
48
+ # Include this module in generator classes and call setup_js_dependencies
49
+ # to handle all JS dependency installation via package_json gem.
50
+ module JsDependencyManager
51
+ # Core React dependencies required for React on Rails
52
+ # Note: @babel/preset-react and babel plugins are NOT included here because:
53
+ # - Shakapacker handles JavaScript transpiler configuration (babel, swc, or esbuild)
54
+ # - Users configure their preferred transpiler via shakapacker.yml javascript_transpiler setting
55
+ # - SWC is now the default and doesn't need Babel presets
56
+ # - For Babel users, shakapacker will install babel-loader and its dependencies
57
+ REACT_DEPENDENCIES = %w[
58
+ react
59
+ react-dom
60
+ prop-types
61
+ ].freeze
62
+
63
+ # CSS processing dependencies for webpack
64
+ CSS_DEPENDENCIES = %w[
65
+ css-loader
66
+ css-minimizer-webpack-plugin
67
+ mini-css-extract-plugin
68
+ style-loader
69
+ ].freeze
70
+
71
+ # Development-only dependencies for hot reloading (Webpack)
72
+ DEV_DEPENDENCIES = %w[
73
+ @pmmmwh/react-refresh-webpack-plugin
74
+ react-refresh
75
+ ].freeze
76
+
77
+ # Rspack core dependencies (only installed when --rspack flag is used)
78
+ RSPACK_DEPENDENCIES = %w[
79
+ @rspack/core
80
+ rspack-manifest-plugin
81
+ ].freeze
82
+
83
+ # Rspack development dependencies for hot reloading
84
+ RSPACK_DEV_DEPENDENCIES = %w[
85
+ @rspack/cli
86
+ @rspack/plugin-react-refresh
87
+ react-refresh
88
+ ].freeze
89
+
90
+ # TypeScript dependencies (only installed when --typescript flag is used)
91
+ # Note: @babel/preset-typescript is NOT included because:
92
+ # - SWC is now the default javascript_transpiler (has built-in TypeScript support)
93
+ # - Shakapacker handles the transpiler configuration via shakapacker.yml
94
+ # - If users choose javascript_transpiler: 'babel', they should manually add @babel/preset-typescript
95
+ # and configure it in their babel.config.js
96
+ TYPESCRIPT_DEPENDENCIES = %w[
97
+ typescript
98
+ @types/react
99
+ @types/react-dom
100
+ ].freeze
101
+
102
+ private
103
+
104
+ def setup_js_dependencies
105
+ add_js_dependencies
106
+
107
+ # Always run install to ensure all dependencies are properly installed.
108
+ # The package_json gem's install method is idempotent and safe to call
109
+ # even if packages were already added - it will only install what's needed.
110
+ # This ensures edge cases where package.json was modified but install wasn't
111
+ # run are handled correctly.
112
+ install_js_dependencies
113
+ end
114
+
115
+ def add_js_dependencies
116
+ add_react_on_rails_package
117
+ add_react_dependencies
118
+ add_css_dependencies
119
+ # Rspack dependencies are only added when --rspack flag is used
120
+ add_rspack_dependencies if respond_to?(:options) && options&.rspack?
121
+ # Dev dependencies vary based on bundler choice
122
+ add_dev_dependencies
123
+ end
124
+
125
+ def add_react_on_rails_package
126
+ # Use exact version match between gem and npm package for stable releases
127
+ # For pre-release versions (e.g., 16.1.0-rc.1), use latest to avoid installing
128
+ # a version that may not exist in the npm registry
129
+ major_minor_patch_only = /\A\d+\.\d+\.\d+\z/
130
+ react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
131
+ "react-on-rails@#{ReactOnRails::VERSION}"
132
+ else
133
+ puts "Adding the latest react-on-rails NPM module. " \
134
+ "Double check this is correct in package.json"
135
+ "react-on-rails"
136
+ end
137
+
138
+ puts "Installing React on Rails package..."
139
+ return if add_package(react_on_rails_pkg)
140
+
141
+ GeneratorMessages.add_warning(<<~MSG.strip)
142
+ ⚠️ Failed to add react-on-rails package.
143
+
144
+ You can install it manually by running:
145
+ npm install #{react_on_rails_pkg}
146
+ MSG
147
+ rescue StandardError => e
148
+ GeneratorMessages.add_warning(<<~MSG.strip)
149
+ ⚠️ Error adding react-on-rails package: #{e.message}
150
+
151
+ You can install it manually by running:
152
+ npm install #{react_on_rails_pkg}
153
+ MSG
154
+ end
155
+
156
+ def add_react_dependencies
157
+ puts "Installing React dependencies..."
158
+ return if add_packages(REACT_DEPENDENCIES)
159
+
160
+ GeneratorMessages.add_warning(<<~MSG.strip)
161
+ ⚠️ Failed to add React dependencies.
162
+
163
+ You can install them manually by running:
164
+ npm install #{REACT_DEPENDENCIES.join(' ')}
165
+ MSG
166
+ rescue StandardError => e
167
+ GeneratorMessages.add_warning(<<~MSG.strip)
168
+ ⚠️ Error adding React dependencies: #{e.message}
169
+
170
+ You can install them manually by running:
171
+ npm install #{REACT_DEPENDENCIES.join(' ')}
172
+ MSG
173
+ end
174
+
175
+ def add_css_dependencies
176
+ puts "Installing CSS handling dependencies..."
177
+ return if add_packages(CSS_DEPENDENCIES)
178
+
179
+ GeneratorMessages.add_warning(<<~MSG.strip)
180
+ ⚠️ Failed to add CSS dependencies.
181
+
182
+ You can install them manually by running:
183
+ npm install #{CSS_DEPENDENCIES.join(' ')}
184
+ MSG
185
+ rescue StandardError => e
186
+ GeneratorMessages.add_warning(<<~MSG.strip)
187
+ ⚠️ Error adding CSS dependencies: #{e.message}
188
+
189
+ You can install them manually by running:
190
+ npm install #{CSS_DEPENDENCIES.join(' ')}
191
+ MSG
192
+ end
193
+
194
+ def add_rspack_dependencies
195
+ puts "Installing Rspack core dependencies..."
196
+ return if add_packages(RSPACK_DEPENDENCIES)
197
+
198
+ GeneratorMessages.add_warning(<<~MSG.strip)
199
+ ⚠️ Failed to add Rspack dependencies.
200
+
201
+ You can install them manually by running:
202
+ npm install #{RSPACK_DEPENDENCIES.join(' ')}
203
+ MSG
204
+ rescue StandardError => e
205
+ GeneratorMessages.add_warning(<<~MSG.strip)
206
+ ⚠️ Error adding Rspack dependencies: #{e.message}
207
+
208
+ You can install them manually by running:
209
+ npm install #{RSPACK_DEPENDENCIES.join(' ')}
210
+ MSG
211
+ end
212
+
213
+ def add_typescript_dependencies
214
+ puts "Installing TypeScript dependencies..."
215
+ return if add_packages(TYPESCRIPT_DEPENDENCIES, dev: true)
216
+
217
+ GeneratorMessages.add_warning(<<~MSG.strip)
218
+ ⚠️ Failed to add TypeScript dependencies.
219
+
220
+ You can install them manually by running:
221
+ npm install --save-dev #{TYPESCRIPT_DEPENDENCIES.join(' ')}
222
+ MSG
223
+ rescue StandardError => e
224
+ GeneratorMessages.add_warning(<<~MSG.strip)
225
+ ⚠️ Error adding TypeScript dependencies: #{e.message}
226
+
227
+ You can install them manually by running:
228
+ npm install --save-dev #{TYPESCRIPT_DEPENDENCIES.join(' ')}
229
+ MSG
230
+ end
231
+
232
+ def add_dev_dependencies
233
+ puts "Installing development dependencies..."
234
+
235
+ # Use Rspack-specific dev dependencies if --rspack flag is set
236
+ dev_deps = if respond_to?(:options) && options&.rspack?
237
+ RSPACK_DEV_DEPENDENCIES
238
+ else
239
+ DEV_DEPENDENCIES
240
+ end
241
+
242
+ return if add_packages(dev_deps, dev: true)
243
+
244
+ GeneratorMessages.add_warning(<<~MSG.strip)
245
+ ⚠️ Failed to add development dependencies.
246
+
247
+ You can install them manually by running:
248
+ npm install --save-dev #{dev_deps.join(' ')}
249
+ MSG
250
+ rescue StandardError => e
251
+ GeneratorMessages.add_warning(<<~MSG.strip)
252
+ ⚠️ Error adding development dependencies: #{e.message}
253
+
254
+ You can install them manually by running:
255
+ npm install --save-dev #{dev_deps.join(' ')}
256
+ MSG
257
+ end
258
+
259
+ # Add a single dependency using package_json gem
260
+ #
261
+ # This method is used internally for adding the react-on-rails package
262
+ # with version-specific handling (react-on-rails@VERSION).
263
+ # For batch operations, use add_packages instead.
264
+ #
265
+ # The exact: true flag ensures version pinning aligns with the gem version,
266
+ # preventing version mismatches between the Ruby gem and NPM package.
267
+ #
268
+ # @param package [String] Package specifier (e.g., "react-on-rails@16.0.0")
269
+ # @param dev [Boolean] Whether to add as dev dependency
270
+ # @return [Boolean] true if successful, false otherwise
271
+ def add_package(package, dev: false)
272
+ pj = package_json
273
+ return false unless pj
274
+
275
+ begin
276
+ # Ensure package is in array format for package_json gem
277
+ packages_array = [package]
278
+ if dev
279
+ pj.manager.add(packages_array, type: :dev, exact: true)
280
+ else
281
+ pj.manager.add(packages_array, exact: true)
282
+ end
283
+ true
284
+ rescue StandardError
285
+ # Return false to trigger warning in calling method
286
+ false
287
+ end
288
+ end
289
+
290
+ # Add multiple dependencies at once using package_json gem
291
+ #
292
+ # This method delegates to GeneratorHelper's add_npm_dependencies for
293
+ # better package manager abstraction and batch processing efficiency.
294
+ #
295
+ # @param packages [Array<String>] Package names to add
296
+ # @param dev [Boolean] Whether to add as dev dependencies
297
+ # @return [Boolean] true if successful, false otherwise
298
+ def add_packages(packages, dev: false)
299
+ # Use the add_npm_dependencies helper from GeneratorHelper
300
+ add_npm_dependencies(packages, dev: dev)
301
+ end
302
+
303
+ def install_js_dependencies
304
+ # Use package_json gem's install method (always available via shakapacker)
305
+ # package_json is guaranteed to be available because:
306
+ # 1. react_on_rails gemspec requires shakapacker
307
+ # 2. shakapacker gemspec requires package_json
308
+ # 3. GeneratorHelper provides package_json method
309
+ pj = package_json
310
+ unless pj
311
+ GeneratorMessages.add_warning("package_json not available, skipping dependency installation")
312
+ return false
313
+ end
314
+
315
+ pj.manager.install
316
+ true
317
+ rescue StandardError => e
318
+ GeneratorMessages.add_warning(<<~MSG.strip)
319
+ ⚠️ JavaScript dependencies installation failed: #{e.message}
320
+
321
+ This could be due to network issues or package manager problems.
322
+ You can install dependencies manually later by running:
323
+ • npm install (if using npm)
324
+ • yarn install (if using yarn)
325
+ • pnpm install (if using pnpm)
326
+ MSG
327
+ false
328
+ end
329
+ end
330
+ end
331
+ end
332
+ # rubocop:enable Metrics/ModuleLength
@@ -1,67 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # See https://github.com/shakacode/react_on_rails/blob/master/docs/guides/configuration.md
4
- # for many more options.
3
+ # React on Rails configuration
4
+ # See https://github.com/shakacode/react_on_rails/blob/master/docs/api-reference/configuration.md
5
+ # for complete documentation of all configuration options.
5
6
 
6
7
  ReactOnRails.configure do |config|
7
- # This configures the script to run to build the production assets by webpack. Set this to nil
8
- # if you don't want react_on_rails building this file for you.
9
- # If nil, then the standard shakacode/shakapacker assets:precompile will run
10
- # config.build_production_command = nil
11
-
12
- ################################################################################
13
8
  ################################################################################
14
- # TEST CONFIGURATION OPTIONS
15
- # Below options are used with the use of this test helper:
16
- # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
9
+ # Server Rendering (Recommended)
17
10
  ################################################################################
18
-
19
- # If you are using this in your spec_helper.rb (or rails_helper.rb):
20
- #
21
- # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
22
- #
23
- # with rspec then this controls what npm command is run
24
- # to automatically refresh your webpack assets on every test run.
25
- #
26
- # Alternately, you can remove the `ReactOnRails::TestHelper.configure_rspec_to_compile_assets`
27
- # and set the config/shakapacker.yml option for test to true.
28
- config.build_test_command = "RAILS_ENV=test bin/shakapacker"
11
+ # Configure server bundle for server-side rendering with `prerender: true`
12
+ # Set to "" if you're not using server rendering
13
+ config.server_bundle_js_file = "server-bundle.js"
29
14
 
30
15
  ################################################################################
16
+ # Test Configuration (Optional)
31
17
  ################################################################################
32
- # SERVER RENDERING OPTIONS
33
- ################################################################################
34
- # This is the file used for server rendering of React when using `(prerender: true)`
35
- # If you are never using server rendering, you should set this to "".
36
- # Note, there is only one server bundle, unlike JavaScript where you want to minimize the size
37
- # of the JS sent to the client. For the server rendering, React on Rails creates a pool of
38
- # JavaScript execution instances which should handle any component requested.
18
+ # ⚠️ IMPORTANT: Two mutually exclusive approaches - use ONLY ONE:
39
19
  #
40
- # While you may configure this to be the same as your client bundle file, this file is typically
41
- # different. You should have ONE server bundle which can create all of your server rendered
42
- # React components.
20
+ # RECOMMENDED APPROACH: Set `compile: true` in config/shakapacker.yml test section
21
+ # - Simpler configuration (no additional setup needed)
22
+ # - Handled automatically by Shakapacker
43
23
  #
44
- config.server_bundle_js_file = "server-bundle.js"
45
-
46
- # Configure where server bundles are output. Defaults to "ssr-generated".
47
- # This should match your webpack configuration for server bundles.
48
- config.server_bundle_output_path = "ssr-generated"
49
-
50
- # Enforce that server bundles are only loaded from private (non-public) directories.
51
- # When true, server bundles will only be loaded from the configured server_bundle_output_path.
52
- # This is recommended for production to prevent server-side code from being exposed.
53
- config.enforce_private_server_bundles = true
24
+ # ALTERNATIVE APPROACH: Uncomment below AND configure ReactOnRails::TestHelper
25
+ # - Provides explicit control over test asset compilation timing
26
+ # - Requires adding ReactOnRails::TestHelper to spec/rails_helper.rb
27
+ # - See: https://github.com/shakacode/react_on_rails/blob/master/docs/guides/testing-configuration.md
28
+ #
29
+ config.build_test_command = "RAILS_ENV=test bin/shakapacker"
54
30
 
55
- ################################################################################
56
- ################################################################################
57
- # FILE SYSTEM BASED COMPONENT REGISTRY
58
- ################################################################################
59
- # `components_subdirectory` is the name of the matching directories that contain automatically registered components
60
- # for use in the Rails views. The default is nil, you can enable the feature by updating it in the next line.
31
+ config.auto_load_bundle = true
61
32
  config.components_subdirectory = "ror_components"
33
+ ################################################################################
34
+ # Advanced Configuration
35
+ ################################################################################
36
+ # Most configuration options have sensible defaults and don't need to be set.
37
+ # For advanced options including:
38
+ # - File-based component registry (components_subdirectory, auto_load_bundle)
39
+ # - Component loading strategies (async/defer/sync)
40
+ # - Server bundle security and organization
41
+ # - I18n configuration
42
+ # - Server rendering pool configuration
43
+ # - Custom rendering extensions
44
+ # - And more...
62
45
  #
63
- # For automated component registry, `render_component` view helper method tries to load bundle for component from
64
- # generated directory. default is false, you can pass option at the time of individual usage or update the default
65
- # in the following line
66
- config.auto_load_bundle = true
46
+ # See: https://github.com/shakacode/react_on_rails/blob/master/docs/api-reference/configuration.md
67
47
  end
@@ -36,8 +36,15 @@ default: &default
36
36
  # Reload manifest.json on all requests so we reload latest compiled packs
37
37
  cache_manifest: false
38
38
 
39
- # Select loader to use, available options are 'babel' (default), 'swc' or 'esbuild'
40
- webpack_loader: 'babel'
39
+ # Select JavaScript transpiler to use
40
+ # Available options: 'swc' (default, 20x faster), 'babel', 'esbuild', or 'none'
41
+ # Use 'none' when providing a completely custom webpack configuration
42
+ # Note: When using rspack, swc is used automatically regardless of this setting
43
+ javascript_transpiler: "swc"
44
+
45
+ # Select assets bundler to use
46
+ # Available options: 'webpack' (default) or 'rspack'
47
+ assets_bundler: "webpack"
41
48
 
42
49
  # Raises an error if there is a mismatch in the shakapacker gem and npm package being used
43
50
  ensure_consistent_versioning: true
@@ -55,6 +62,11 @@ default: &default
55
62
  # https://webpack.js.org/guides/build-performance/#avoid-production-specific-tooling
56
63
  useContentHash: false
57
64
 
65
+ # On-demand compilation of packs when modified. Defaults to false.
66
+ # Set to false if using bin/shakapacker-dev-server or bin/shakapacker --watch via Procfiles.
67
+ # Set to true only in test environment for on-demand compilation.
68
+ compile: false
69
+
58
70
  # Setting the asset host here will override Rails.application.config.asset_host.
59
71
  # Here, you can set different asset_host per environment. Note that
60
72
  # SHAKAPACKER_ASSET_HOST will override both configurations.
@@ -72,7 +84,6 @@ default: &default
72
84
 
73
85
  development:
74
86
  <<: *default
75
- compile: true
76
87
  compiler_strategy: mtime
77
88
 
78
89
  # Reference: https://webpack.js.org/configuration/dev-server/