react_on_rails 16.0.1.rc.2 → 16.1.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.
@@ -40,7 +40,9 @@ module ReactOnRails
40
40
  if installation_prerequisites_met? || options.ignore_warnings?
41
41
  invoke_generators
42
42
  add_bin_scripts
43
- add_post_install_message
43
+ # Only add the post install message if not using Redux
44
+ # Redux generator handles its own messages
45
+ add_post_install_message unless options.redux?
44
46
  else
45
47
  error = <<~MSG.strip
46
48
  🚫 React on Rails generator prerequisites not met!
@@ -77,6 +79,14 @@ module ReactOnRails
77
79
  else
78
80
  invoke "react_on_rails:react_no_redux", [], { typescript: options.typescript? }
79
81
  end
82
+ setup_react_dependencies
83
+ end
84
+
85
+ def setup_react_dependencies
86
+ @added_dependencies_to_package_json ||= false
87
+ @ran_direct_installs ||= false
88
+ add_js_dependencies
89
+ install_js_dependencies if @added_dependencies_to_package_json && !@ran_direct_installs
80
90
  end
81
91
 
82
92
  # NOTE: other requirements for existing files such as .gitignore or application.
@@ -410,6 +420,134 @@ module ReactOnRails
410
420
  puts Rainbow("✅ Created tsconfig.json").green
411
421
  end
412
422
 
423
+ def add_js_dependencies
424
+ add_react_on_rails_package
425
+ add_react_dependencies
426
+ add_css_dependencies
427
+ add_dev_dependencies
428
+ end
429
+
430
+ def add_react_on_rails_package
431
+ major_minor_patch_only = /\A\d+\.\d+\.\d+\z/
432
+
433
+ # Try to use package_json gem first, fall back to direct npm commands
434
+ react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
435
+ ["react-on-rails@#{ReactOnRails::VERSION}"]
436
+ else
437
+ puts "Adding the latest react-on-rails NPM module. " \
438
+ "Double check this is correct in package.json"
439
+ ["react-on-rails"]
440
+ end
441
+
442
+ puts "Installing React on Rails package..."
443
+ if add_npm_dependencies(react_on_rails_pkg)
444
+ @added_dependencies_to_package_json = true
445
+ return
446
+ end
447
+
448
+ puts "Using direct npm commands as fallback"
449
+ success = system("npm", "install", *react_on_rails_pkg)
450
+ @ran_direct_installs = true if success
451
+ handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
452
+ end
453
+
454
+ def add_react_dependencies
455
+ puts "Installing React dependencies..."
456
+ react_deps = %w[
457
+ react
458
+ react-dom
459
+ @babel/preset-react
460
+ prop-types
461
+ babel-plugin-transform-react-remove-prop-types
462
+ babel-plugin-macros
463
+ ]
464
+ if add_npm_dependencies(react_deps)
465
+ @added_dependencies_to_package_json = true
466
+ return
467
+ end
468
+
469
+ success = system("npm", "install", *react_deps)
470
+ @ran_direct_installs = true if success
471
+ handle_npm_failure("React dependencies", react_deps) unless success
472
+ end
473
+
474
+ def add_css_dependencies
475
+ puts "Installing CSS handling dependencies..."
476
+ css_deps = %w[
477
+ css-loader
478
+ css-minimizer-webpack-plugin
479
+ mini-css-extract-plugin
480
+ style-loader
481
+ ]
482
+ if add_npm_dependencies(css_deps)
483
+ @added_dependencies_to_package_json = true
484
+ return
485
+ end
486
+
487
+ success = system("npm", "install", *css_deps)
488
+ @ran_direct_installs = true if success
489
+ handle_npm_failure("CSS dependencies", css_deps) unless success
490
+ end
491
+
492
+ def add_dev_dependencies
493
+ puts "Installing development dependencies..."
494
+ dev_deps = %w[
495
+ @pmmmwh/react-refresh-webpack-plugin
496
+ react-refresh
497
+ ]
498
+ if add_npm_dependencies(dev_deps, dev: true)
499
+ @added_dependencies_to_package_json = true
500
+ return
501
+ end
502
+
503
+ success = system("npm", "install", "--save-dev", *dev_deps)
504
+ @ran_direct_installs = true if success
505
+ handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
506
+ end
507
+
508
+ def install_js_dependencies
509
+ # Detect which package manager to use
510
+ success = if File.exist?(File.join(destination_root, "yarn.lock"))
511
+ system("yarn", "install")
512
+ elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
513
+ system("pnpm", "install")
514
+ elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
515
+ File.exist?(File.join(destination_root, "package.json"))
516
+ # Use npm for package-lock.json or as default fallback
517
+ system("npm", "install")
518
+ else
519
+ true # No package manager detected, skip
520
+ end
521
+
522
+ unless success
523
+ GeneratorMessages.add_warning(<<~MSG.strip)
524
+ ⚠️ JavaScript dependencies installation failed.
525
+
526
+ This could be due to network issues or missing package manager.
527
+ You can install dependencies manually later by running:
528
+ • npm install (if using npm)
529
+ • yarn install (if using yarn)
530
+ • pnpm install (if using pnpm)
531
+ MSG
532
+ end
533
+
534
+ success
535
+ end
536
+
537
+ def handle_npm_failure(dependency_type, packages, dev: false)
538
+ install_command = dev ? "npm install --save-dev" : "npm install"
539
+ GeneratorMessages.add_warning(<<~MSG.strip)
540
+ ⚠️ Failed to install #{dependency_type}.
541
+
542
+ The following packages could not be installed automatically:
543
+ #{packages.map { |pkg| " • #{pkg}" }.join("\n")}
544
+
545
+ This could be due to network issues or missing package manager.
546
+ You can install them manually later by running:
547
+ #{install_command} #{packages.join(' ')}
548
+ MSG
549
+ end
550
+
413
551
  # Removed: Shakapacker auto-installation logic (now explicit dependency)
414
552
 
415
553
  # Removed: Shakapacker 8+ is now required as explicit dependency
@@ -19,7 +19,7 @@ module ReactOnRails
19
19
  aliases: "-T"
20
20
 
21
21
  def create_redux_directories
22
- # Create auto-registration directory structure for Redux
22
+ # Create auto-bundling directory structure for Redux
23
23
  empty_directory("app/javascript/src/HelloWorldApp/ror_components")
24
24
 
25
25
  # Create Redux support directories within the component directory
@@ -31,7 +31,7 @@ module ReactOnRails
31
31
  base_js_path = "redux/base"
32
32
  ext = component_extension(options)
33
33
 
34
- # Copy Redux-connected component to auto-registration structure
34
+ # Copy Redux-connected component to auto-bundling structure
35
35
  copy_file("#{base_js_path}/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.client.#{ext}",
36
36
  "app/javascript/src/HelloWorldApp/ror_components/HelloWorldApp.client.#{ext}")
37
37
  copy_file("#{base_js_path}/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.server.#{ext}",
@@ -89,6 +89,13 @@ module ReactOnRails
89
89
  install_packages_with_fallback(regular_packages, dev: false, package_manager: package_manager)
90
90
  end
91
91
 
92
+ def add_redux_specific_messages
93
+ # Append Redux-specific post-install instructions
94
+ GeneratorMessages.add_info(
95
+ GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world")
96
+ )
97
+ end
98
+
92
99
  private
93
100
 
94
101
  def install_packages_with_fallback(packages, dev:, package_manager:)
@@ -132,14 +139,6 @@ module ReactOnRails
132
139
  when "yarn", "bun" then "--dev"
133
140
  end
134
141
  end
135
-
136
- def add_redux_specific_messages
137
- # Override the generic messages with Redux-specific instructions
138
- GeneratorMessages.output.clear
139
- GeneratorMessages.add_info(
140
- GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world")
141
- )
142
- end
143
142
  end
144
143
  end
145
144
  end
@@ -24,8 +24,8 @@ ReactOnRails.configure do |config|
24
24
  # to automatically refresh your webpack assets on every test run.
25
25
  #
26
26
  # Alternately, you can remove the `ReactOnRails::TestHelper.configure_rspec_to_compile_assets`
27
- # and set the config/<%= config[:packer_type] %>.yml option for test to true.
28
- config.build_test_command = "RAILS_ENV=test bin/<%= config[:packer_type] %>"
27
+ # and set the config/shakapacker.yml option for test to true.
28
+ config.build_test_command = "RAILS_ENV=test bin/shakapacker"
29
29
 
30
30
  ################################################################################
31
31
  ################################################################################
@@ -43,6 +43,15 @@ ReactOnRails.configure do |config|
43
43
  #
44
44
  config.server_bundle_js_file = "server-bundle.js"
45
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
54
+
46
55
  ################################################################################
47
56
  ################################################################################
48
57
  # FILE SYSTEM BASED COMPONENT REGISTRY
@@ -44,13 +44,14 @@ const configureServer = () => {
44
44
 
45
45
  // Custom output for the server-bundle that matches the config in
46
46
  // config/initializers/react_on_rails.rb
47
+ // Server bundles are output to a private directory (not public) for security
47
48
  serverWebpackConfig.output = {
48
49
  filename: 'server-bundle.js',
49
50
  globalObject: 'this',
50
51
  // If using the React on Rails Pro node server renderer, uncomment the next line
51
52
  // libraryTarget: 'commonjs2',
52
- path: config.outputPath,
53
- publicPath: config.publicPath,
53
+ path: require('path').resolve(__dirname, '../../ssr-generated'),
54
+ // No publicPath needed since server bundles are not served via web
54
55
  // https://webpack.js.org/configuration/output/#outputglobalobject
55
56
  };
56
57
 
@@ -52,8 +52,13 @@ module ReactOnRails
52
52
  # If exceeded, an error will be thrown for server-side rendered components not registered on the client.
53
53
  # Set to 0 to disable the timeout and wait indefinitely for component registration.
54
54
  component_registry_timeout: DEFAULT_COMPONENT_REGISTRY_TIMEOUT,
55
- generated_component_packs_loading_strategy: nil
55
+ generated_component_packs_loading_strategy: nil,
56
+ server_bundle_output_path: "ssr-generated",
57
+ enforce_private_server_bundles: false
56
58
  )
59
+ # TODO: Add automatic detection of server_bundle_output_path from shakapacker.yml
60
+ # See feature/shakapacker-yml-integration branch for implementation
61
+ # Requires Shakapacker v8.5.0+ and semantic version checking
57
62
  end
58
63
 
59
64
  class Configuration
@@ -68,7 +73,8 @@ module ReactOnRails
68
73
  :same_bundle_for_client_and_server, :rendering_props_extension,
69
74
  :make_generated_server_bundle_the_entrypoint,
70
75
  :generated_component_packs_loading_strategy, :immediate_hydration, :rsc_bundle_js_file,
71
- :react_client_manifest_file, :react_server_client_manifest_file, :component_registry_timeout
76
+ :react_client_manifest_file, :react_server_client_manifest_file, :component_registry_timeout,
77
+ :server_bundle_output_path, :enforce_private_server_bundles
72
78
 
73
79
  # rubocop:disable Metrics/AbcSize
74
80
  def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
@@ -85,7 +91,7 @@ module ReactOnRails
85
91
  random_dom_id: nil, server_render_method: nil, rendering_props_extension: nil,
86
92
  components_subdirectory: nil, auto_load_bundle: nil, immediate_hydration: nil,
87
93
  rsc_bundle_js_file: nil, react_client_manifest_file: nil, react_server_client_manifest_file: nil,
88
- component_registry_timeout: nil)
94
+ component_registry_timeout: nil, server_bundle_output_path: nil, enforce_private_server_bundles: nil)
89
95
  self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
90
96
  self.generated_assets_dirs = generated_assets_dirs
91
97
  self.generated_assets_dir = generated_assets_dir
@@ -130,6 +136,8 @@ module ReactOnRails
130
136
  self.defer_generated_component_packs = defer_generated_component_packs
131
137
  self.immediate_hydration = immediate_hydration
132
138
  self.generated_component_packs_loading_strategy = generated_component_packs_loading_strategy
139
+ self.server_bundle_output_path = server_bundle_output_path
140
+ self.enforce_private_server_bundles = enforce_private_server_bundles
133
141
  end
134
142
  # rubocop:enable Metrics/AbcSize
135
143
 
@@ -139,13 +147,13 @@ module ReactOnRails
139
147
  ensure_webpack_generated_files_exists
140
148
  configure_generated_assets_dirs_deprecation
141
149
  configure_skip_display_none_deprecation
142
- ensure_generated_assets_dir_present
143
150
  check_server_render_method_is_only_execjs
144
151
  error_if_using_packer_and_generated_assets_dir_not_match_public_output_path
145
152
  # check_deprecated_settings
146
153
  adjust_precompile_task
147
154
  check_component_registry_timeout
148
155
  validate_generated_component_packs_loading_strategy
156
+ validate_enforce_private_server_bundles
149
157
  end
150
158
 
151
159
  private
@@ -180,7 +188,7 @@ module ReactOnRails
180
188
  1. Use :sync or :defer loading strategy instead of :async
181
189
  2. Upgrade to Shakapacker v8.2.0 or above to enable async script loading
182
190
  MSG
183
- if PackerUtils.shakapacker_version_requirement_met?("8.2.0")
191
+ if PackerUtils.supports_async_loading?
184
192
  self.generated_component_packs_loading_strategy ||= :async
185
193
  elsif generated_component_packs_loading_strategy.nil?
186
194
  Rails.logger.warn("**WARNING** #{msg}")
@@ -194,15 +202,40 @@ module ReactOnRails
194
202
  raise ReactOnRails::Error, "generated_component_packs_loading_strategy must be either :async, :defer, or :sync"
195
203
  end
196
204
 
205
+ def validate_enforce_private_server_bundles
206
+ return unless enforce_private_server_bundles
207
+
208
+ # Check if server_bundle_output_path is nil
209
+ if server_bundle_output_path.nil?
210
+ raise ReactOnRails::Error, "enforce_private_server_bundles is set to true, but " \
211
+ "server_bundle_output_path is nil. Please set server_bundle_output_path " \
212
+ "to a directory outside of the public directory."
213
+ end
214
+
215
+ # Check if server_bundle_output_path is inside public directory
216
+ # Skip validation if Rails.root is not available (e.g., in tests)
217
+ return unless defined?(Rails) && Rails.root
218
+
219
+ public_path = Rails.root.join("public").to_s
220
+ server_output_path = File.expand_path(server_bundle_output_path, Rails.root.to_s)
221
+
222
+ return unless server_output_path.start_with?(public_path)
223
+
224
+ raise ReactOnRails::Error, "enforce_private_server_bundles is set to true, but " \
225
+ "server_bundle_output_path (#{server_bundle_output_path}) is inside " \
226
+ "the public directory. Please set it to a directory outside of public."
227
+ end
228
+
229
+ def check_minimum_shakapacker_version
230
+ ReactOnRails::PackerUtils.raise_shakapacker_version_incompatible_for_basic_pack_generation unless
231
+ ReactOnRails::PackerUtils.supports_basic_pack_generation?
232
+ end
233
+
197
234
  def check_autobundling_requirements
198
- raise_missing_components_subdirectory if auto_load_bundle && !components_subdirectory.present?
199
- return unless components_subdirectory.present?
235
+ raise_missing_components_subdirectory unless components_subdirectory.present?
200
236
 
201
- ReactOnRails::PackerUtils.raise_shakapacker_not_installed unless ReactOnRails::PackerUtils.using_packer?
202
237
  ReactOnRails::PackerUtils.raise_shakapacker_version_incompatible_for_autobundling unless
203
- ReactOnRails::PackerUtils.shakapacker_version_requirement_met?(
204
- ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION
205
- )
238
+ ReactOnRails::PackerUtils.supports_autobundling?
206
239
  ReactOnRails::PackerUtils.raise_nested_entries_disabled unless ReactOnRails::PackerUtils.nested_entries?
207
240
  end
208
241
 
@@ -221,8 +254,8 @@ module ReactOnRails
221
254
  # We set it very big so that it is not used, and then clean just
222
255
  # removes files older than 1 hour.
223
256
  versions = 100_000
224
- puts "Invoking task #{ReactOnRails::PackerUtils.packer_type}:clean from React on Rails"
225
- Rake::Task["#{ReactOnRails::PackerUtils.packer_type}:clean"].invoke(versions)
257
+ puts "Invoking task shakapacker:clean from React on Rails"
258
+ Rake::Task["shakapacker:clean"].invoke(versions)
226
259
  }
227
260
 
228
261
  if Rake::Task.task_defined?("assets:precompile")
@@ -237,22 +270,20 @@ module ReactOnRails
237
270
  end
238
271
 
239
272
  def error_if_using_packer_and_generated_assets_dir_not_match_public_output_path
240
- return unless ReactOnRails::PackerUtils.using_packer?
241
-
242
273
  return if generated_assets_dir.blank?
243
274
 
244
275
  packer_public_output_path = ReactOnRails::PackerUtils.packer_public_output_path
245
276
 
246
277
  if File.expand_path(generated_assets_dir) == packer_public_output_path.to_s
247
278
  Rails.logger.warn("You specified generated_assets_dir in `config/initializers/react_on_rails.rb` " \
248
- "with #{ReactOnRails::PackerUtils.packer_type}. " \
279
+ "with Shakapacker. " \
249
280
  "Remove this line from your configuration file.")
250
281
  else
251
282
  msg = <<~MSG
252
- Error configuring /config/initializers/react_on_rails.rb: You are using #{ReactOnRails::PackerUtils.packer_type}
283
+ Error configuring /config/initializers/react_on_rails.rb: You are using Shakapacker
253
284
  and your specified value for generated_assets_dir = #{generated_assets_dir}
254
285
  that does not match the value for public_output_path specified in
255
- #{ReactOnRails::PackerUtils.packer_type}.yml = #{packer_public_output_path}. You should remove the configuration
286
+ shakapacker.yml = #{packer_public_output_path}. You should remove the configuration
256
287
  value for "generated_assets_dir" from your config/initializers/react_on_rails.rb file.
257
288
  MSG
258
289
  raise ReactOnRails::Error, msg
@@ -271,37 +302,21 @@ module ReactOnRails
271
302
  raise ReactOnRails::Error, msg
272
303
  end
273
304
 
274
- def ensure_generated_assets_dir_present
275
- return if generated_assets_dir.present? || ReactOnRails::PackerUtils.using_packer?
276
-
277
- self.generated_assets_dir = DEFAULT_GENERATED_ASSETS_DIR
278
- Rails.logger.warn "ReactOnRails: Set generated_assets_dir to default: #{DEFAULT_GENERATED_ASSETS_DIR}"
279
- end
280
-
281
305
  def configure_generated_assets_dirs_deprecation
282
306
  return if generated_assets_dirs.blank?
283
307
 
284
- if ReactOnRails::PackerUtils.using_packer?
285
- packer_public_output_path = ReactOnRails::PackerUtils.packer_public_output_path
286
- # rubocop:disable Layout/LineLength
287
- packer_name = ReactOnRails::PackerUtils.packer_type&.upcase_first
308
+ packer_public_output_path = ReactOnRails::PackerUtils.packer_public_output_path
288
309
 
289
- Rails.logger.warn "Error configuring config/initializers/react_on_rails. Define neither the generated_assets_dirs nor " \
290
- "the generated_assets_dir when using #{packer_name}. This is defined by " \
291
- "public_output_path specified in #{ReactOnRails::PackerUtils.packer_type}.yml = #{packer_public_output_path}."
292
- # rubocop:enable Layout/LineLength
293
- return
294
- end
310
+ msg = <<~MSG
311
+ ReactOnRails Configuration Warning: The 'generated_assets_dirs' configuration option is no longer supported.
312
+ Since Shakapacker is now required, public asset paths are automatically determined from your shakapacker.yml configuration.
313
+ Please remove 'config.generated_assets_dirs' from your config/initializers/react_on_rails.rb file.
314
+ Public assets will be loaded from: #{packer_public_output_path}
315
+ If you need to customize the public output path, configure it in config/shakapacker.yml under 'public_output_path'.
316
+ Note: Private server bundles are configured separately via server_bundle_output_path.
317
+ MSG
295
318
 
296
- Rails.logger.warn "[DEPRECATION] ReactOnRails: Use config.generated_assets_dir rather than " \
297
- "generated_assets_dirs"
298
- if generated_assets_dir.blank?
299
- self.generated_assets_dir = generated_assets_dirs
300
- else
301
- Rails.logger.warn "[DEPRECATION] ReactOnRails. You have both generated_assets_dirs and " \
302
- "generated_assets_dir defined. Define ONLY generated_assets_dir if NOT using Shakapacker " \
303
- "and define neither if using Webpacker"
304
- end
319
+ Rails.logger.warn msg
305
320
  end
306
321
 
307
322
  def ensure_webpack_generated_files_exists
@@ -333,17 +348,15 @@ module ReactOnRails
333
348
  end
334
349
 
335
350
  def compile_command_conflict_message
336
- packer_name = ReactOnRails::PackerUtils.packer_type.upcase_first
337
- packer_type = ReactOnRails::PackerUtils.packer_type
338
351
  <<~MSG
339
352
 
340
- React on Rails and #{packer_name} error in configuration!
353
+ React on Rails and Shakapacker error in configuration!
341
354
  In order to use config/react_on_rails.rb config.build_production_command,
342
- you must edit config/#{packer_type}.yml to include this value in the default configuration:
343
- '#{packer_type}_precompile: false'
355
+ you must edit config/shakapacker.yml to include this value in the default configuration:
356
+ 'shakapacker_precompile: false'
344
357
 
345
358
  Alternatively, remove the config/react_on_rails.rb config.build_production_command and the
346
- default bin/#{packer_type} script will be used for assets:precompile.
359
+ default bin/shakapacker script will be used for assets:precompile.
347
360
 
348
361
  MSG
349
362
  end
@@ -7,7 +7,12 @@ module ReactOnRails
7
7
  def initialize(parse_error:, json:)
8
8
  @json = json
9
9
  @original_error = parse_error
10
- super(parse_error.message)
10
+ message = <<~MSG
11
+ #{parse_error.message}
12
+
13
+ #{Utils.default_troubleshooting_section}
14
+ MSG
15
+ super(message)
11
16
  end
12
17
 
13
18
  def to_honeybadger_context
@@ -1,44 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "shakapacker"
4
+
3
5
  module ReactOnRails
4
6
  module PackerUtils
5
- def self.using_packer?
6
- using_shakapacker_const?
7
- end
8
-
9
- def self.using_shakapacker_const?
10
- return @using_shakapacker_const if defined?(@using_shakapacker_const)
11
-
12
- @using_shakapacker_const = ReactOnRails::Utils.gem_available?("shakapacker") &&
13
- shakapacker_version_requirement_met?("8.2.0")
14
- end
15
-
16
- def self.packer_type
17
- return "shakapacker" if using_shakapacker_const?
18
-
19
- nil
20
- end
21
-
22
- def self.packer
23
- return nil unless using_packer?
24
-
25
- require "shakapacker"
26
- ::Shakapacker
27
- end
28
-
29
7
  def self.dev_server_running?
30
- return false unless using_packer?
31
-
32
- packer.dev_server.running?
8
+ Shakapacker.dev_server.running?
33
9
  end
34
10
 
35
11
  def self.dev_server_url
36
- "#{packer.dev_server.protocol}://#{packer.dev_server.host_with_port}"
12
+ "#{Shakapacker.dev_server.protocol}://#{Shakapacker.dev_server.host_with_port}"
37
13
  end
38
14
 
39
15
  def self.shakapacker_version
40
16
  return @shakapacker_version if defined?(@shakapacker_version)
41
- return nil unless ReactOnRails::Utils.gem_available?("shakapacker")
42
17
 
43
18
  @shakapacker_version = Gem.loaded_specs["shakapacker"].version.to_s
44
19
  end
@@ -53,14 +28,28 @@ module ReactOnRails
53
28
  end
54
29
 
55
30
  def self.shakapacker_version_requirement_met?(required_version)
56
- Gem::Version.new(shakapacker_version) >= Gem::Version.new(required_version)
31
+ @version_checks ||= {}
32
+ @version_checks[required_version] ||= Gem::Version.new(shakapacker_version) >= Gem::Version.new(required_version)
33
+ end
34
+
35
+ def self.supports_async_loading?
36
+ shakapacker_version_requirement_met?("8.2.0")
37
+ end
38
+
39
+ def self.supports_basic_pack_generation?
40
+ shakapacker_version_requirement_met?(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION)
41
+ end
42
+
43
+ def self.supports_autobundling?
44
+ min_version = ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_BUNDLING
45
+ ::Shakapacker.config.respond_to?(:nested_entries?) && shakapacker_version_requirement_met?(min_version)
57
46
  end
58
47
 
59
48
  # This returns either a URL for the webpack-dev-server, non-server bundle or
60
49
  # the hashed server bundle if using the same bundle for the client.
61
50
  # Otherwise returns a file path.
62
51
  def self.bundle_js_uri_from_packer(bundle_name)
63
- hashed_bundle_name = packer.manifest.lookup!(bundle_name)
52
+ hashed_bundle_name = ::Shakapacker.manifest.lookup!(bundle_name)
64
53
 
65
54
  # Support for hashing the server-bundle and having that built
66
55
  # the webpack-dev-server is provided by the config value
@@ -69,7 +58,7 @@ module ReactOnRails
69
58
  is_bundle_running_on_server = (bundle_name == ReactOnRails.configuration.server_bundle_js_file) ||
70
59
  (bundle_name == ReactOnRails.configuration.rsc_bundle_js_file)
71
60
 
72
- if packer.dev_server.running? && (!is_bundle_running_on_server ||
61
+ if ::Shakapacker.dev_server.running? && (!is_bundle_running_on_server ||
73
62
  ReactOnRails.configuration.same_bundle_for_client_and_server)
74
63
  "#{dev_server_url}#{hashed_bundle_name}"
75
64
  else
@@ -78,7 +67,7 @@ module ReactOnRails
78
67
  end
79
68
 
80
69
  def self.public_output_uri_path
81
- "#{packer.config.public_output_path.relative_path_from(packer.config.public_path)}/"
70
+ "#{::Shakapacker.config.public_output_path.relative_path_from(::Shakapacker.config.public_path)}/"
82
71
  end
83
72
 
84
73
  # The function doesn't ensure that the asset exists.
@@ -93,42 +82,40 @@ module ReactOnRails
93
82
  end
94
83
 
95
84
  def self.precompile?
96
- return ::Shakapacker.config.shakapacker_precompile? if using_shakapacker_const?
97
-
98
- false
85
+ ::Shakapacker.config.shakapacker_precompile?
99
86
  end
100
87
 
101
88
  def self.packer_source_path
102
- packer.config.source_path
89
+ ::Shakapacker.config.source_path
103
90
  end
104
91
 
105
92
  def self.packer_source_entry_path
106
- packer.config.source_entry_path
93
+ ::Shakapacker.config.source_entry_path
107
94
  end
108
95
 
109
96
  def self.nested_entries?
110
- packer.config.nested_entries?
97
+ ::Shakapacker.config.nested_entries?
111
98
  end
112
99
 
113
100
  def self.packer_public_output_path
114
- packer.config.public_output_path.to_s
101
+ ::Shakapacker.config.public_output_path.to_s
115
102
  end
116
103
 
117
104
  def self.manifest_exists?
118
- packer.config.public_manifest_path.exist?
105
+ ::Shakapacker.config.public_manifest_path.exist?
119
106
  end
120
107
 
121
108
  def self.packer_source_path_explicit?
122
- packer.config.send(:data)[:source_path].present?
109
+ ::Shakapacker.config.send(:data)[:source_path].present?
123
110
  end
124
111
 
125
112
  def self.check_manifest_not_cached
126
- return unless using_packer? && packer.config.cache_manifest?
113
+ return unless ::Shakapacker.config.cache_manifest?
127
114
 
128
115
  msg = <<-MSG.strip_heredoc
129
116
  ERROR: you have enabled cache_manifest in the #{Rails.env} env when using the
130
117
  ReactOnRails::TestHelper.configure_rspec_to_compile_assets helper
131
- To fix this: edit your config/#{packer_type}.yml file and set cache_manifest to false for test.
118
+ To fix this: edit your config/shakapacker.yml file and set cache_manifest to false for test.
132
119
  MSG
133
120
  puts wrap_message(msg)
134
121
  exit!
@@ -149,7 +136,7 @@ module ReactOnRails
149
136
  def self.raise_nested_entries_disabled
150
137
  msg = <<~MSG
151
138
  **ERROR** ReactOnRails: `nested_entries` is configured to be disabled in shakapacker. Please update \
152
- config/#{packer_type}.yml to enable nested entries. for more information read
139
+ config/shakapacker.yml to enable nested entries. for more information read
153
140
  https://www.shakacode.com/react-on-rails/docs/guides/file-system-based-automated-bundle-generation.md#enable-nested_entries-for-shakapacker
154
141
  MSG
155
142
 
@@ -158,19 +145,19 @@ module ReactOnRails
158
145
 
159
146
  def self.raise_shakapacker_version_incompatible_for_autobundling
160
147
  msg = <<~MSG
161
- **ERROR** ReactOnRails: Please upgrade Shakapacker to version #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or \
162
- above to use the automated bundle generation feature. The currently installed version is \
163
- #{ReactOnRails::PackerUtils.shakapacker_version}.
148
+ **ERROR** ReactOnRails: Please upgrade ::Shakapacker to version #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_BUNDLING} or \
149
+ above to use the automated bundle generation feature (which requires nested_entries support). \
150
+ The currently installed version is #{ReactOnRails::PackerUtils.shakapacker_version}. \
151
+ Basic pack generation requires ::Shakapacker #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or above.
164
152
  MSG
165
153
 
166
154
  raise ReactOnRails::Error, msg
167
155
  end
168
156
 
169
- def self.raise_shakapacker_not_installed
157
+ def self.raise_shakapacker_version_incompatible_for_basic_pack_generation
170
158
  msg = <<~MSG
171
- **ERROR** ReactOnRails: Missing Shakapacker gem. Please upgrade to use Shakapacker \
172
- #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or above to use the \
173
- automated bundle generation feature.
159
+ **ERROR** ReactOnRails: Please upgrade ::Shakapacker to version #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or \
160
+ above to use basic pack generation features. The currently installed version is #{ReactOnRails::PackerUtils.shakapacker_version}.
174
161
  MSG
175
162
 
176
163
  raise ReactOnRails::Error, msg