diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ccc24d7db..aceeaf57bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,11 @@ Changes since the last non-beta release. #### Bug Fixes - **Doctor rake task**: Fixed LoadError in `rake react_on_rails:doctor` when using packaged gem. The task was trying to require excluded `rakelib/task_helpers` file. [PR 1795](https://github.com/shakacode/react_on_rails/pull/1795) +- **Shakapacker version requirements**: Fixed inconsistent version requirements between basic pack generation (6.5.1+) and advanced auto-registration features (7.0.0+). Added backward compatibility for users on Shakapacker 6.5.1-6.9.x while providing clear upgrade guidance for advanced features. Added new constants `MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION` and improved version checking performance with caching. [PR 1798](https://github.com/shakacode/react_on_rails/pull/1798) + +#### Code Cleanup + +- **PackerUtils abstraction removal**: Removed unnecessary `PackerUtils.packer` abstraction method and replaced all calls with direct `::Shakapacker` usage. This simplifies the codebase by eliminating an abstraction layer that was originally created to support multiple webpack tools but is no longer needed since we only support Shakapacker. All tests updated accordingly. [PR 1798](https://github.com/shakacode/react_on_rails/pull/1798) by [claude-code](https://claude.ai/code) ### [16.0.1-rc.0] - 2025-09-19 diff --git a/Gemfile.lock b/Gemfile.lock index ae5aea02cd..edf0dcbc8f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - react_on_rails (16.0.1.rc.0) + react_on_rails (16.0.1.rc.2) addressable connection_pool execjs (~> 2.5) diff --git a/docs/contributor-info/linters.md b/docs/contributor-info/linters.md index c14b9ab392..e0edd65a0a 100644 --- a/docs/contributor-info/linters.md +++ b/docs/contributor-info/linters.md @@ -10,7 +10,7 @@ If you haven't tried the autofix options for `eslint` and `rubocop`, you're seri 2. **Rubocop:** Be sure to be in the correct directory where you have Ruby files, usually the top level of your Rails project. ```bash -rubocop -a +bundle exec rubocop -a ``` 3. **ESLint:** Be sure to be in the correct directory where you have JS files. diff --git a/docs/guides/configuration.md b/docs/guides/configuration.md index af31ff5b61..82f6731351 100644 --- a/docs/guides/configuration.md +++ b/docs/guides/configuration.md @@ -195,6 +195,19 @@ ReactOnRails.configure do |config| # `render_component` and `render_component_hash` view helper methods can # auto-load the bundle for the generated component, to avoid having to specify the # bundle manually for each view with the component. + # + # SHAKAPACKER VERSION REQUIREMENTS: + # - Basic pack generation: Shakapacker 6.5.1+ + # - Advanced auto-registration with nested entries: Shakapacker 7.0.0+ + # - Async loading support: Shakapacker 8.2.0+ + # + # Feature Compatibility Matrix: + # | Shakapacker Version | Basic Pack Generation | Auto-Registration | Nested Entries | Async Loading | + # |-------------------|----------------------|-------------------|----------------|---------------| + # | 6.5.1 - 6.9.x | ✅ Yes | ❌ No | ❌ No | ❌ No | + # | 7.0.0 - 8.1.x | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No | + # | 8.2.0+ | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | + # ################################################################################ # components_subdirectory is the name of the subdirectory matched to detect and register components automatically # The default is nil. You can enable the feature by updating it in the next line. @@ -205,6 +218,8 @@ ReactOnRails.configure do |config| # Default is false. # The default can be overridden as an option in calls to view helpers # `render_component` and `render_component_hash`. You may set to true to change the default to auto loading. + # NOTE: Requires Shakapacker 6.5.1+ for basic functionality, 7.0.0+ for full auto-registration features. + # See version requirements matrix above for complete feature compatibility. config.auto_load_bundle = false # Default is false diff --git a/lib/generators/react_on_rails/base_generator.rb b/lib/generators/react_on_rails/base_generator.rb index ab98a7a928..2b3a197c67 100644 --- a/lib/generators/react_on_rails/base_generator.rb +++ b/lib/generators/react_on_rails/base_generator.rb @@ -41,7 +41,7 @@ def copy_base_files base_templates = %w[config/initializers/react_on_rails.rb] base_files.each { |file| copy_file("#{base_path}#{file}", file) } base_templates.each do |file| - template("#{base_path}/#{file}.tt", file, { packer_type: ReactOnRails::PackerUtils.packer_type }) + template("#{base_path}/#{file}.tt", file) end end diff --git a/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt b/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt index f07388e23e..223169639a 100644 --- a/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +++ b/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt @@ -24,8 +24,8 @@ ReactOnRails.configure do |config| # to automatically refresh your webpack assets on every test run. # # Alternately, you can remove the `ReactOnRails::TestHelper.configure_rspec_to_compile_assets` - # and set the config/<%= config[:packer_type] %>.yml option for test to true. - config.build_test_command = "RAILS_ENV=test bin/<%= config[:packer_type] %>" + # and set the config/shakapacker.yml option for test to true. + config.build_test_command = "RAILS_ENV=test bin/shakapacker" ################################################################################ ################################################################################ diff --git a/lib/react_on_rails/configuration.rb b/lib/react_on_rails/configuration.rb index b2a67b451f..d3047a59ed 100644 --- a/lib/react_on_rails/configuration.rb +++ b/lib/react_on_rails/configuration.rb @@ -180,7 +180,7 @@ def validate_generated_component_packs_loading_strategy 1. Use :sync or :defer loading strategy instead of :async 2. Upgrade to Shakapacker v8.2.0 or above to enable async script loading MSG - if PackerUtils.shakapacker_version_requirement_met?("8.2.0") + if PackerUtils.supports_async_loading? self.generated_component_packs_loading_strategy ||= :async elsif generated_component_packs_loading_strategy.nil? Rails.logger.warn("**WARNING** #{msg}") @@ -198,12 +198,19 @@ def check_autobundling_requirements raise_missing_components_subdirectory if auto_load_bundle && !components_subdirectory.present? return unless components_subdirectory.present? - ReactOnRails::PackerUtils.raise_shakapacker_not_installed unless ReactOnRails::PackerUtils.using_packer? - ReactOnRails::PackerUtils.raise_shakapacker_version_incompatible_for_autobundling unless - ReactOnRails::PackerUtils.shakapacker_version_requirement_met?( - ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION - ) - ReactOnRails::PackerUtils.raise_nested_entries_disabled unless ReactOnRails::PackerUtils.nested_entries? + # Check basic pack generation support for auto_load_bundle + ReactOnRails::PackerUtils.raise_shakapacker_version_incompatible_for_basic_pack_generation unless + ReactOnRails::PackerUtils.supports_basic_pack_generation? + + # Additional checks for advanced features requiring nested entries + if ReactOnRails::PackerUtils.supports_autobundling? + ReactOnRails::PackerUtils.raise_nested_entries_disabled unless ReactOnRails::PackerUtils.nested_entries? + else + # Warn users about missing advanced features but don't block basic functionality + min_version = ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION + Rails.logger.warn("React on Rails: Basic pack generation enabled. " \ + "Upgrade to Shakapacker #{min_version}+ for advanced auto-registration features.") + end end def adjust_precompile_task @@ -221,8 +228,8 @@ def adjust_precompile_task # We set it very big so that it is not used, and then clean just # removes files older than 1 hour. versions = 100_000 - puts "Invoking task #{ReactOnRails::PackerUtils.packer_type}:clean from React on Rails" - Rake::Task["#{ReactOnRails::PackerUtils.packer_type}:clean"].invoke(versions) + puts "Invoking task shakapacker:clean from React on Rails" + Rake::Task["shakapacker:clean"].invoke(versions) } if Rake::Task.task_defined?("assets:precompile") @@ -237,23 +244,21 @@ def adjust_precompile_task end def error_if_using_packer_and_generated_assets_dir_not_match_public_output_path - return unless ReactOnRails::PackerUtils.using_packer? - return if generated_assets_dir.blank? packer_public_output_path = ReactOnRails::PackerUtils.packer_public_output_path if File.expand_path(generated_assets_dir) == packer_public_output_path.to_s Rails.logger.warn("You specified generated_assets_dir in `config/initializers/react_on_rails.rb` " \ - "with #{ReactOnRails::PackerUtils.packer_type}. " \ + "with shakapacker. " \ "Remove this line from your configuration file.") else msg = <<~MSG - Error configuring /config/initializers/react_on_rails.rb: You are using #{ReactOnRails::PackerUtils.packer_type} - and your specified value for generated_assets_dir = #{generated_assets_dir} - that does not match the value for public_output_path specified in - #{ReactOnRails::PackerUtils.packer_type}.yml = #{packer_public_output_path}. You should remove the configuration - value for "generated_assets_dir" from your config/initializers/react_on_rails.rb file. + Configuration mismatch in config/initializers/react_on_rails.rb: + + Your generated_assets_dir setting (#{generated_assets_dir}) does not match the value for public_output_path (#{packer_public_output_path}). + + Remove the generated_assets_dir configuration and let Shakapacker manage the output path. MSG raise ReactOnRails::Error, msg end @@ -272,36 +277,22 @@ def check_server_render_method_is_only_execjs end def ensure_generated_assets_dir_present - return if generated_assets_dir.present? || ReactOnRails::PackerUtils.using_packer? + return if generated_assets_dir.present? - self.generated_assets_dir = DEFAULT_GENERATED_ASSETS_DIR - Rails.logger.warn "ReactOnRails: Set generated_assets_dir to default: #{DEFAULT_GENERATED_ASSETS_DIR}" + # When using Shakapacker, don't set a default generated_assets_dir since + # Shakapacker manages its own public_output_path configuration + # This prevents configuration mismatches between ReactOnRails and Shakapacker + Rails.logger.warn "ReactOnRails: No generated_assets_dir specified, using Shakapacker public_output_path" end def configure_generated_assets_dirs_deprecation return if generated_assets_dirs.blank? - if ReactOnRails::PackerUtils.using_packer? - packer_public_output_path = ReactOnRails::PackerUtils.packer_public_output_path - # rubocop:disable Layout/LineLength - packer_name = ReactOnRails::PackerUtils.packer_type&.upcase_first - - Rails.logger.warn "Error configuring config/initializers/react_on_rails. Define neither the generated_assets_dirs nor " \ - "the generated_assets_dir when using #{packer_name}. This is defined by " \ - "public_output_path specified in #{ReactOnRails::PackerUtils.packer_type}.yml = #{packer_public_output_path}." - # rubocop:enable Layout/LineLength - return - end - - Rails.logger.warn "[DEPRECATION] ReactOnRails: Use config.generated_assets_dir rather than " \ - "generated_assets_dirs" - if generated_assets_dir.blank? - self.generated_assets_dir = generated_assets_dirs - else - Rails.logger.warn "[DEPRECATION] ReactOnRails. You have both generated_assets_dirs and " \ - "generated_assets_dir defined. Define ONLY generated_assets_dir if NOT using Shakapacker " \ - "and define neither if using Webpacker" - end + packer_public_output_path = ReactOnRails::PackerUtils.packer_public_output_path + Rails.logger.warn "You specified generated_assets_dirs in `config/initializers/react_on_rails.rb` " \ + "with Shakapacker. Remove this configuration as the output path is automatically " \ + "determined by `public_output_path` in shakapacker.yml " \ + "(currently: #{packer_public_output_path})." end def ensure_webpack_generated_files_exists @@ -333,17 +324,15 @@ def raise_missing_components_subdirectory end def compile_command_conflict_message - packer_name = ReactOnRails::PackerUtils.packer_type.upcase_first - packer_type = ReactOnRails::PackerUtils.packer_type <<~MSG - React on Rails and #{packer_name} error in configuration! + React on Rails and Shakapacker error in configuration! In order to use config/react_on_rails.rb config.build_production_command, - you must edit config/#{packer_type}.yml to include this value in the default configuration: - '#{packer_type}_precompile: false' + you must edit config/shakapacker.yml to include this value in the default configuration: + 'shakapacker_precompile: false' Alternatively, remove the config/react_on_rails.rb config.build_production_command and the - default bin/#{packer_type} script will be used for assets:precompile. + default bin/shakapacker script will be used for assets:precompile. MSG end diff --git a/lib/react_on_rails/packer_utils.rb b/lib/react_on_rails/packer_utils.rb index 6239fc7af1..9e78e272e0 100644 --- a/lib/react_on_rails/packer_utils.rb +++ b/lib/react_on_rails/packer_utils.rb @@ -1,44 +1,19 @@ # frozen_string_literal: true +require "shakapacker" + module ReactOnRails module PackerUtils - def self.using_packer? - using_shakapacker_const? - end - - def self.using_shakapacker_const? - return @using_shakapacker_const if defined?(@using_shakapacker_const) - - @using_shakapacker_const = ReactOnRails::Utils.gem_available?("shakapacker") && - shakapacker_version_requirement_met?("8.2.0") - end - - def self.packer_type - return "shakapacker" if using_shakapacker_const? - - nil - end - - def self.packer - return nil unless using_packer? - - require "shakapacker" - ::Shakapacker - end - def self.dev_server_running? - return false unless using_packer? - - packer.dev_server.running? + Shakapacker.dev_server.running? end def self.dev_server_url - "#{packer.dev_server.protocol}://#{packer.dev_server.host_with_port}" + "#{Shakapacker.dev_server.protocol}://#{Shakapacker.dev_server.host_with_port}" end def self.shakapacker_version return @shakapacker_version if defined?(@shakapacker_version) - return nil unless ReactOnRails::Utils.gem_available?("shakapacker") @shakapacker_version = Gem.loaded_specs["shakapacker"].version.to_s end @@ -53,14 +28,28 @@ def self.shakapacker_version_as_array end def self.shakapacker_version_requirement_met?(required_version) - Gem::Version.new(shakapacker_version) >= Gem::Version.new(required_version) + @version_checks ||= {} + @version_checks[required_version] ||= Gem::Version.new(shakapacker_version) >= Gem::Version.new(required_version) + end + + def self.supports_async_loading? + shakapacker_version_requirement_met?("8.2.0") + end + + def self.supports_basic_pack_generation? + shakapacker_version_requirement_met?(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION) + end + + def self.supports_autobundling? + min_version = ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION + ::Shakapacker.config.respond_to?(:nested_entries?) && shakapacker_version_requirement_met?(min_version) end # This returns either a URL for the webpack-dev-server, non-server bundle or # the hashed server bundle if using the same bundle for the client. # Otherwise returns a file path. def self.bundle_js_uri_from_packer(bundle_name) - hashed_bundle_name = packer.manifest.lookup!(bundle_name) + hashed_bundle_name = ::Shakapacker.manifest.lookup!(bundle_name) # Support for hashing the server-bundle and having that built # the webpack-dev-server is provided by the config value @@ -69,7 +58,7 @@ def self.bundle_js_uri_from_packer(bundle_name) is_bundle_running_on_server = (bundle_name == ReactOnRails.configuration.server_bundle_js_file) || (bundle_name == ReactOnRails.configuration.rsc_bundle_js_file) - if packer.dev_server.running? && (!is_bundle_running_on_server || + if ::Shakapacker.dev_server.running? && (!is_bundle_running_on_server || ReactOnRails.configuration.same_bundle_for_client_and_server) "#{dev_server_url}#{hashed_bundle_name}" else @@ -78,7 +67,7 @@ def self.bundle_js_uri_from_packer(bundle_name) end def self.public_output_uri_path - "#{packer.config.public_output_path.relative_path_from(packer.config.public_path)}/" + "#{::Shakapacker.config.public_output_path.relative_path_from(::Shakapacker.config.public_path)}/" end # The function doesn't ensure that the asset exists. @@ -93,42 +82,40 @@ def self.asset_uri_from_packer(asset_name) end def self.precompile? - return ::Shakapacker.config.shakapacker_precompile? if using_shakapacker_const? - - false + ::Shakapacker.config.shakapacker_precompile? end def self.packer_source_path - packer.config.source_path + ::Shakapacker.config.source_path end def self.packer_source_entry_path - packer.config.source_entry_path + ::Shakapacker.config.source_entry_path end def self.nested_entries? - packer.config.nested_entries? + ::Shakapacker.config.nested_entries? end def self.packer_public_output_path - packer.config.public_output_path.to_s + ::Shakapacker.config.public_output_path.to_s end def self.manifest_exists? - packer.config.public_manifest_path.exist? + ::Shakapacker.config.public_manifest_path.exist? end def self.packer_source_path_explicit? - packer.config.send(:data)[:source_path].present? + ::Shakapacker.config.send(:data)[:source_path].present? end def self.check_manifest_not_cached - return unless using_packer? && packer.config.cache_manifest? + return unless ::Shakapacker.config.cache_manifest? msg = <<-MSG.strip_heredoc ERROR: you have enabled cache_manifest in the #{Rails.env} env when using the ReactOnRails::TestHelper.configure_rspec_to_compile_assets helper - To fix this: edit your config/#{packer_type}.yml file and set cache_manifest to false for test. + To fix this: edit your config/shaka::Shakapacker.yml file and set cache_manifest to false for test. MSG puts wrap_message(msg) exit! @@ -148,8 +135,8 @@ def self.webpack_assets_status_checker def self.raise_nested_entries_disabled msg = <<~MSG - **ERROR** ReactOnRails: `nested_entries` is configured to be disabled in shakapacker. Please update \ - config/#{packer_type}.yml to enable nested entries. for more information read + **ERROR** ReactOnRails: `nested_entries` is configured to be disabled in shaka::Shakapacker. Please update \ + config/shaka::Shakapacker.yml to enable nested entries. for more information read https://www.shakacode.com/react-on-rails/docs/guides/file-system-based-automated-bundle-generation.md#enable-nested_entries-for-shakapacker MSG @@ -158,9 +145,19 @@ def self.raise_nested_entries_disabled def self.raise_shakapacker_version_incompatible_for_autobundling msg = <<~MSG - **ERROR** ReactOnRails: Please upgrade Shakapacker to version #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or \ - above to use the automated bundle generation feature. The currently installed version is \ - #{ReactOnRails::PackerUtils.shakapacker_version}. + **ERROR** ReactOnRails: Please upgrade ::Shakapacker to version #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION} or \ + above to use the automated bundle generation feature (which requires nested_entries support). \ + The currently installed version is #{ReactOnRails::PackerUtils.shakapacker_version}. \ + Basic pack generation requires ::Shakapacker #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or above. + MSG + + raise ReactOnRails::Error, msg + end + + def self.raise_shakapacker_version_incompatible_for_basic_pack_generation + msg = <<~MSG + **ERROR** ReactOnRails: Please upgrade ::Shakapacker to version #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or \ + above to use basic pack generation features. The currently installed version is #{ReactOnRails::PackerUtils.shakapacker_version}. MSG raise ReactOnRails::Error, msg @@ -168,7 +165,7 @@ def self.raise_shakapacker_version_incompatible_for_autobundling def self.raise_shakapacker_not_installed msg = <<~MSG - **ERROR** ReactOnRails: Missing Shakapacker gem. Please upgrade to use Shakapacker \ + **ERROR** ReactOnRails: Missing ::Shakapacker gem. Please upgrade to use ::Shakapacker \ #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or above to use the \ automated bundle generation feature. MSG diff --git a/lib/react_on_rails/packs_generator.rb b/lib/react_on_rails/packs_generator.rb index a2628caa91..83b3894022 100644 --- a/lib/react_on_rails/packs_generator.rb +++ b/lib/react_on_rails/packs_generator.rb @@ -9,6 +9,8 @@ class PacksGenerator CONTAINS_CLIENT_OR_SERVER_REGEX = /\.(server|client)($|\.)/ COMPONENT_EXTENSIONS = /\.(jsx?|tsx?)$/ MINIMUM_SHAKAPACKER_VERSION = "6.5.1" + # Auto-registration requires nested_entries support which was added in 7.0.0 + MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION = "7.0.0" def self.instance @instance ||= PacksGenerator.new diff --git a/lib/react_on_rails/system_checker.rb b/lib/react_on_rails/system_checker.rb index 891dad21b0..935a2b8d0c 100644 --- a/lib/react_on_rails/system_checker.rb +++ b/lib/react_on_rails/system_checker.rb @@ -618,14 +618,14 @@ def report_shakapacker_version_with_threshold version = shakapacker_match[1].strip begin - # Use proper semantic version comparison - version_obj = Gem::Version.new(version) - threshold_version = Gem::Version.new("8.2") + # Validate version string format + Gem::Version.new(version) - if version_obj >= threshold_version + if ReactOnRails::PackerUtils.supports_autobundling? add_success("✅ Shakapacker #{version} (supports React on Rails auto-registration)") else - add_warning("⚠️ Shakapacker #{version} - Version 8.2+ needed for React on Rails auto-registration") + add_warning("⚠️ Shakapacker #{version} - Version 7.0+ with nested_entries support needed " \ + "for React on Rails auto-registration") end rescue ArgumentError # Fallback for invalid version strings diff --git a/lib/react_on_rails/test_helper.rb b/lib/react_on_rails/test_helper.rb index a8cb1f5891..d50ed62ca7 100644 --- a/lib/react_on_rails/test_helper.rb +++ b/lib/react_on_rails/test_helper.rb @@ -86,10 +86,9 @@ def self.ensure_assets_compiled(webpack_assets_status_checker: nil, puts @printed_once = true - if ReactOnRails::PackerUtils.using_packer? && - ReactOnRails::Utils.using_packer_source_path_is_not_defined_and_custom_node_modules? + if ReactOnRails::Utils.using_packer_source_path_is_not_defined_and_custom_node_modules? msg = <<-MSG.strip_heredoc - WARNING: Define config/#{ReactOnRails::PackerUtils.packer_type}.yml to include sourcePath to configure + WARNING: Define config/shakapacker.yml to include sourcePath to configure the location of your JavaScript source for React on Rails. Default location of #{source_path} is used. MSG diff --git a/lib/react_on_rails/test_helper/webpack_assets_compiler.rb b/lib/react_on_rails/test_helper/webpack_assets_compiler.rb index bf87b8e9dc..4fad9e6d51 100644 --- a/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +++ b/lib/react_on_rails/test_helper/webpack_assets_compiler.rb @@ -16,7 +16,7 @@ def compile_assets React on Rails is aborting your test run - If you wish to use the config/#{ReactOnRails::PackerUtils.packer_type}.yml compile option for tests + If you wish to use the config/shakapacker.yml compile option for tests them remove your call to the ReactOnRails test helper. MSG puts Rainbow(msg).red diff --git a/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb b/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb index 6a3d7f2721..35d200efb5 100644 --- a/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +++ b/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb @@ -31,8 +31,7 @@ def stale_generated_webpack_files end def stale_generated_files(files) - manifest_needed = ReactOnRails::PackerUtils.using_packer? && - !ReactOnRails::PackerUtils.manifest_exists? + manifest_needed = !ReactOnRails::PackerUtils.manifest_exists? return ["manifest.json"] if manifest_needed diff --git a/lib/react_on_rails/utils.rb b/lib/react_on_rails/utils.rb index 3243ab473d..6ec3e03368 100644 --- a/lib/react_on_rails/utils.rb +++ b/lib/react_on_rails/utils.rb @@ -7,7 +7,7 @@ require "active_support/core_ext/string" module ReactOnRails - module Utils # rubocop:disable Metrics/ModuleLength + module Utils TRUNCATION_FILLER = "\n... TRUNCATED #{ Rainbow('To see the full output, set FULL_TEXT_ERRORS=true.').red } ...\n".freeze @@ -78,22 +78,20 @@ def self.bundle_js_file_path(bundle_name) # a. The webpack manifest plugin would have a race condition where the same manifest.json # is edited by both the webpack-dev-server # b. There is no good reason to hash the server bundle name. - if ReactOnRails::PackerUtils.using_packer? && bundle_name != "manifest.json" + if bundle_name == "manifest.json" + # Default to the non-hashed name in the specified output directory, which, for legacy + # React on Rails, this is the output directory picked up by the asset pipeline. + # For Shakapacker, this is the public output path defined in the (shaka/web)packer.yml file. + File.join(generated_assets_full_path, bundle_name) + else begin ReactOnRails::PackerUtils.bundle_js_uri_from_packer(bundle_name) - rescue Object.const_get( - ReactOnRails::PackerUtils.packer_type.capitalize - )::Manifest::MissingEntryError + rescue Shakapacker::Manifest::MissingEntryError File.expand_path( File.join(ReactOnRails::PackerUtils.packer_public_output_path, bundle_name) ) end - else - # Default to the non-hashed name in the specified output directory, which, for legacy - # React on Rails, this is the output directory picked up by the asset pipeline. - # For Shakapacker, this is the public output path defined in the (shaka/web)packer.yml file. - File.join(generated_assets_full_path, bundle_name) end end @@ -115,11 +113,7 @@ def self.react_client_manifest_file_path return @react_client_manifest_path if @react_client_manifest_path && !Rails.env.development? file_name = ReactOnRails.configuration.react_client_manifest_file - @react_client_manifest_path = if ReactOnRails::PackerUtils.using_packer? - ReactOnRails::PackerUtils.asset_uri_from_packer(file_name) - else - File.join(generated_assets_full_path, file_name) - end + @react_client_manifest_path = ReactOnRails::PackerUtils.asset_uri_from_packer(file_name) end # React Server Manifest is generated by the server bundle. @@ -161,26 +155,16 @@ def self.prepend_cd_node_modules_directory(cmd) end def self.source_path - if ReactOnRails::PackerUtils.using_packer? - ReactOnRails::PackerUtils.packer_source_path - else - ReactOnRails.configuration.node_modules_location - end + ReactOnRails::PackerUtils.packer_source_path end def self.using_packer_source_path_is_not_defined_and_custom_node_modules? - return false unless ReactOnRails::PackerUtils.using_packer? - !ReactOnRails::PackerUtils.packer_source_path_explicit? && ReactOnRails.configuration.node_modules_location.present? end def self.generated_assets_full_path - if ReactOnRails::PackerUtils.using_packer? - ReactOnRails::PackerUtils.packer_public_output_path - else - File.expand_path(ReactOnRails.configuration.generated_assets_dir) - end + ReactOnRails::PackerUtils.packer_public_output_path end def self.gem_available?(name) diff --git a/spec/dummy/spec/helpers/react_on_rails_helper_spec.rb b/spec/dummy/spec/helpers/react_on_rails_helper_spec.rb index 5d6ff737eb..706e58068a 100644 --- a/spec/dummy/spec/helpers/react_on_rails_helper_spec.rb +++ b/spec/dummy/spec/helpers/react_on_rails_helper_spec.rb @@ -3,8 +3,6 @@ require "rails_helper" require "support/script_tag_utils" -Packer = Object.const_get(ReactOnRails::PackerUtils.packer_type.capitalize) - class PlainReactOnRailsHelper include ReactOnRailsHelper include ActionView::Helpers::TagHelper @@ -12,7 +10,7 @@ class PlainReactOnRailsHelper # rubocop:disable Metrics/BlockLength describe ReactOnRailsHelper do - include Packer::Helper + include Shakapacker::Helper before do allow(self).to receive(:request) { diff --git a/spec/dummy/spec/rake/assets_precompile_rake_spec.rb b/spec/dummy/spec/rake/assets_precompile_rake_spec.rb index 6204df9d37..55a68090e8 100644 --- a/spec/dummy/spec/rake/assets_precompile_rake_spec.rb +++ b/spec/dummy/spec/rake/assets_precompile_rake_spec.rb @@ -15,7 +15,7 @@ ReactOnRails.configure do |config| config.build_production_command = "RAILS_ENV=production NODE_ENV=production / - bin/#{ReactOnRails::PackerUtils.packer_type}" + bin/shakapacker" end expect do diff --git a/spec/lib/react_on_rails/doctor_spec.rb b/spec/lib/react_on_rails/doctor_spec.rb index 79ce410bfb..beab9b83dd 100644 --- a/spec/lib/react_on_rails/doctor_spec.rb +++ b/spec/lib/react_on_rails/doctor_spec.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -# rubocop:disable RSpec/VerifiedDoubles - require_relative "../../react_on_rails/spec_helper" require_relative "../../../lib/react_on_rails/doctor" @@ -89,13 +87,15 @@ describe "#determine_server_bundle_path" do context "when Shakapacker gem is available with relative paths" do - let(:shakapacker_config) { double(source_path: "client/app", source_entry_path: "packs") } + let(:shakapacker_config) do + instance_double(Shakapacker::Configuration, source_path: "client/app", source_entry_path: "packs") + end before do - shakapacker_module = double("Shakapacker", config: shakapacker_config) + shakapacker_module = instance_double(Shakapacker, config: shakapacker_config) stub_const("Shakapacker", shakapacker_module) allow(doctor).to receive(:require).with("shakapacker").and_return(true) - allow(doctor).to receive(:get_server_bundle_filename).and_return("server-bundle.js") + allow(doctor).to receive(:server_bundle_filename).and_return("server-bundle.js") end it "uses Shakapacker API configuration with relative paths" do @@ -106,13 +106,16 @@ context "when Shakapacker gem is available with absolute paths" do let(:rails_root) { "/Users/test/myapp" } - let(:shakapacker_config) { double(source_path: "#{rails_root}/client/app", source_entry_path: "packs") } + let(:shakapacker_config) do + instance_double(Shakapacker::Configuration, source_path: "#{rails_root}/client/app", + source_entry_path: "packs") + end before do - shakapacker_module = double("Shakapacker", config: shakapacker_config) + shakapacker_module = instance_double(Shakapacker, config: shakapacker_config) stub_const("Shakapacker", shakapacker_module) allow(doctor).to receive(:require).with("shakapacker").and_return(true) - allow(doctor).to receive(:get_server_bundle_filename).and_return("server-bundle.js") + allow(doctor).to receive(:server_bundle_filename).and_return("server-bundle.js") allow(Dir).to receive(:pwd).and_return(rails_root) end @@ -125,14 +128,15 @@ context "when Shakapacker gem returns nested absolute paths" do let(:rails_root) { "/Users/test/myapp" } let(:shakapacker_config) do - double(source_path: "#{rails_root}/client/app", source_entry_path: "#{rails_root}/client/app/packs") + instance_double(Shakapacker::Configuration, source_path: "#{rails_root}/client/app", + source_entry_path: "#{rails_root}/client/app/packs") end before do - shakapacker_module = double("Shakapacker", config: shakapacker_config) + shakapacker_module = instance_double(Shakapacker, config: shakapacker_config) stub_const("Shakapacker", shakapacker_module) allow(doctor).to receive(:require).with("shakapacker").and_return(true) - allow(doctor).to receive(:get_server_bundle_filename).and_return("server-bundle.js") + allow(doctor).to receive(:server_bundle_filename).and_return("server-bundle.js") allow(Dir).to receive(:pwd).and_return(rails_root) end @@ -145,7 +149,7 @@ context "when Shakapacker gem is not available" do before do allow(doctor).to receive(:require).with("shakapacker").and_raise(LoadError) - allow(doctor).to receive(:get_server_bundle_filename).and_return("server-bundle.js") + allow(doctor).to receive(:server_bundle_filename).and_return("server-bundle.js") end it "uses default path" do @@ -155,7 +159,7 @@ end end - describe "#get_server_bundle_filename" do + describe "#server_bundle_filename" do context "when react_on_rails.rb has custom filename" do let(:initializer_content) do 'config.server_bundle_js_file = "custom-server-bundle.js"' @@ -167,7 +171,7 @@ end it "extracts filename from initializer" do - filename = doctor.send(:get_server_bundle_filename) + filename = doctor.send(:server_bundle_filename) expect(filename).to eq("custom-server-bundle.js") end end @@ -178,12 +182,10 @@ end it "returns default filename" do - filename = doctor.send(:get_server_bundle_filename) + filename = doctor.send(:server_bundle_filename) expect(filename).to eq("server-bundle.js") end end end end end - -# rubocop:enable RSpec/VerifiedDoubles diff --git a/spec/react_on_rails/configuration_spec.rb b/spec/react_on_rails/configuration_spec.rb index 18627d3f4b..c3037546cf 100644 --- a/spec/react_on_rails/configuration_spec.rb +++ b/spec/react_on_rails/configuration_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require_relative "spec_helper" -require ReactOnRails::PackerUtils.packer_type +require "shakapacker" # rubocop:disable Metrics/ModuleLength @@ -9,10 +9,8 @@ module ReactOnRails RSpec.describe Configuration do let(:existing_path) { Pathname.new(Dir.mktmpdir) } let(:not_existing_path) { "/path/to/#{SecureRandom.hex(4)}" } - let(:using_packer) { false } before do - allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(using_packer) ReactOnRails.instance_variable_set(:@configuration, nil) end @@ -28,8 +26,8 @@ module ReactOnRails before do allow(Rails).to receive(:root).and_return(File.expand_path(".")) - allow(ReactOnRails::PackerUtils).to receive_message_chain("packer.config.public_output_path") - .and_return(packer_public_output_path) + allow(::Shakapacker).to receive_message_chain("config.public_output_path") + .and_return(Pathname.new(packer_public_output_path)) end it "does not throw if the generated assets dir is blank with shakapacker" do @@ -187,6 +185,13 @@ module ReactOnRails end describe "RSC configuration options" do + before do + allow(ReactOnRails::PackerUtils).to receive_messages( + supports_autobundling?: true, + nested_entries?: true + ) + end + it "has default values for RSC-related configuration options" do ReactOnRails.configure {} # rubocop:disable Lint/EmptyBlock @@ -284,7 +289,12 @@ module ReactOnRails end it "changes the configuration of the gem, such as setting the prerender option to false" do + test_path = File.expand_path("public/webpack/test") + allow(::Shakapacker).to receive_message_chain("config.public_output_path") + .and_return(Pathname.new(test_path)) + ReactOnRails.configure do |config| + config.generated_assets_dir = test_path config.server_bundle_js_file = "server.js" config.prerender = false end @@ -294,7 +304,12 @@ module ReactOnRails end it "changes the configuration of the gem, such as setting the prerender option to true" do + test_path = File.expand_path("public/webpack/test") + allow(::Shakapacker).to receive_message_chain("config.public_output_path") + .and_return(Pathname.new(test_path)) + ReactOnRails.configure do |config| + config.generated_assets_dir = test_path config.server_bundle_js_file = "something.js" config.prerender = true config.random_dom_id = false @@ -305,7 +320,25 @@ module ReactOnRails expect(ReactOnRails.configuration.random_dom_id).to be(false) end + it "works without specifying generated_assets_dir when using Shakapacker" do + allow(::Shakapacker).to receive_message_chain("config.public_output_path") + .and_return(Pathname.new("/tmp/public/packs")) + + expect do + ReactOnRails.configure do |config| + config.server_bundle_js_file = "server.js" + end + end.not_to raise_error + + expect(ReactOnRails.configuration.generated_assets_dir).to be_blank + end + it "calls raise_missing_components_subdirectory if auto_load_bundle = true & components_subdirectory is not set" do + allow(ReactOnRails::PackerUtils).to receive_messages( + supports_autobundling?: true, + nested_entries?: true + ) + expect do ReactOnRails.configure do |config| config.auto_load_bundle = true @@ -314,17 +347,18 @@ module ReactOnRails end it "checks that autobundling requirements are met if configuration options for autobundling are set" do - allow(ReactOnRails::PackerUtils).to receive_messages(using_packer?: true, - shakapacker_version_requirement_met?: true, - nested_entries?: true) + allow(ReactOnRails::PackerUtils).to receive_messages( + shakapacker_version_requirement_met?: true, + nested_entries?: true, + supports_autobundling?: true + ) ReactOnRails.configure do |config| config.auto_load_bundle = true config.components_subdirectory = "something" end - expect(ReactOnRails::PackerUtils).to have_received(:using_packer?).thrice - expect(ReactOnRails::PackerUtils).to have_received(:shakapacker_version_requirement_met?).twice + expect(ReactOnRails::PackerUtils).to have_received(:supports_autobundling?) expect(ReactOnRails::PackerUtils).to have_received(:nested_entries?) end diff --git a/spec/react_on_rails/locales_to_js_spec.rb b/spec/react_on_rails/locales_to_js_spec.rb index d076dc3ce0..991a6760cf 100644 --- a/spec/react_on_rails/locales_to_js_spec.rb +++ b/spec/react_on_rails/locales_to_js_spec.rb @@ -9,10 +9,6 @@ module ReactOnRails let(:translations_path) { "#{i18n_dir}/translations.js" } let(:default_path) { "#{i18n_dir}/default.js" } - before do - allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(false) - end - shared_examples "locale to js" do context "with obsolete js files" do before do diff --git a/spec/react_on_rails/packer_utils_spec.rb b/spec/react_on_rails/packer_utils_spec.rb index 97da892979..4f94a7384a 100644 --- a/spec/react_on_rails/packer_utils_spec.rb +++ b/spec/react_on_rails/packer_utils_spec.rb @@ -42,18 +42,18 @@ module ReactOnRails context "when dev server is running" do before do - allow(described_class.packer).to receive(:dev_server).and_return( + allow(::Shakapacker).to receive(:dev_server).and_return( instance_double( - ReactOnRails::PackerUtils.packer::DevServer, + ::Shakapacker::DevServer, running?: true, protocol: "http", host_with_port: "localhost:3035" ) ) - allow(described_class.packer).to receive_message_chain("config.public_output_path") + allow(::Shakapacker).to receive_message_chain("config.public_output_path") .and_return(Pathname.new(public_output_path)) - allow(described_class.packer).to receive_message_chain("config.public_path") + allow(::Shakapacker).to receive_message_chain("config.public_path") .and_return(Pathname.new("/path/to/public")) end @@ -65,8 +65,8 @@ module ReactOnRails context "when dev server is not running" do before do - allow(described_class.packer).to receive_message_chain("dev_server.running?").and_return(false) - allow(described_class.packer).to receive_message_chain("config.public_output_path") + allow(::Shakapacker).to receive_message_chain("dev_server.running?").and_return(false) + allow(::Shakapacker).to receive_message_chain("config.public_output_path") .and_return(Pathname.new(public_output_path)) end @@ -76,5 +76,99 @@ module ReactOnRails end end end + + describe ".supports_async_loading?" do + it "returns true when ::Shakapacker >= 8.2.0" do + allow(described_class).to receive(:shakapacker_version_requirement_met?).with("8.2.0").and_return(true) + + expect(described_class.supports_async_loading?).to be(true) + end + + it "returns false when ::Shakapacker < 8.2.0" do + allow(described_class).to receive(:shakapacker_version_requirement_met?).with("8.2.0").and_return(false) + + expect(described_class.supports_async_loading?).to be(false) + end + end + + describe ".supports_basic_pack_generation?" do + it "returns true when ::Shakapacker >= 6.5.1" do + allow(described_class).to receive(:shakapacker_version_requirement_met?) + .with(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION).and_return(true) + + expect(described_class.supports_basic_pack_generation?).to be(true) + end + + it "returns false when ::Shakapacker < 6.5.1" do + allow(described_class).to receive(:shakapacker_version_requirement_met?) + .with(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION).and_return(false) + + expect(described_class.supports_basic_pack_generation?).to be(false) + end + end + + describe ".supports_autobundling?" do + let(:mock_config) { instance_double("::Shakapacker::Config") } # rubocop:disable RSpec/VerifiedDoubleReference + let(:mock_packer) { instance_double("::Shakapacker", config: mock_config) } # rubocop:disable RSpec/VerifiedDoubleReference + + before do + allow(::Shakapacker).to receive(:config).and_return(mock_config) + end + + it "returns true when ::Shakapacker >= 7.0.0 with nested_entries support" do + allow(mock_config).to receive(:respond_to?).with(:nested_entries?).and_return(true) + allow(described_class).to receive(:shakapacker_version_requirement_met?) + .with(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION).and_return(true) + + expect(described_class.supports_autobundling?).to be(true) + end + + it "returns false when ::Shakapacker < 7.0.0" do + allow(mock_config).to receive(:respond_to?).with(:nested_entries?).and_return(true) + allow(described_class).to receive(:shakapacker_version_requirement_met?) + .with(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION).and_return(false) + + expect(described_class.supports_autobundling?).to be(false) + end + + it "returns false when nested_entries method is not available" do + allow(mock_config).to receive(:respond_to?).with(:nested_entries?).and_return(false) + allow(described_class).to receive(:shakapacker_version_requirement_met?) + .with(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION).and_return(true) + + expect(described_class.supports_autobundling?).to be(false) + end + end + end + + describe "version constants validation" do + it "ensures MINIMUM_SHAKAPACKER_VERSION constants are properly defined" do + expect(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION).to eq("6.5.1") + expect(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION).to eq("7.0.0") + end + + it "ensures version requirements are logically consistent" do + basic_version = Gem::Version.new(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION) + auto_reg_version = Gem::Version.new( + ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_REGISTRATION + ) + + expect(auto_reg_version).to be >= basic_version, + "Auto-registration version should be >= basic pack generation version" + end + + it "validates version checks are cached properly" do + # Mock the shakapacker_version to avoid dependency on actual version + allow(ReactOnRails::PackerUtils).to receive(:shakapacker_version).and_return("7.1.0") + + # First call should compute and cache + result1 = ReactOnRails::PackerUtils.shakapacker_version_requirement_met?("6.5.1") + + # Second call should use cached result + result2 = ReactOnRails::PackerUtils.shakapacker_version_requirement_met?("6.5.1") + + expect(result1).to eq(result2) + expect(result1).to be true # 7.1.0 >= 6.5.1 + end end end diff --git a/spec/react_on_rails/test_helper/webpack_assets_status_checker_spec.rb b/spec/react_on_rails/test_helper/webpack_assets_status_checker_spec.rb index 85ed00eb0f..3e48778c9d 100644 --- a/spec/react_on_rails/test_helper/webpack_assets_status_checker_spec.rb +++ b/spec/react_on_rails/test_helper/webpack_assets_status_checker_spec.rb @@ -22,13 +22,14 @@ before do allow(ReactOnRails::PackerUtils).to receive(:check_manifest_not_cached).and_return(nil) allow(ReactOnRails::Utils).to receive(:generated_assets_full_path).and_return(generated_assets_full_path) + allow(ReactOnRails::PackerUtils).to receive_messages( + packer_public_output_path: generated_assets_full_path, + supports_autobundling?: true, + nested_entries?: true + ) end context "with Webpacker" do - before do - allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(true) - end - context "when compiled assets with manifest exist and are up-to-date" do let(:fixture_dirname) { "assets_with_manifest_exist" } @@ -61,7 +62,7 @@ let(:fixture_dirname) { "assets_with_manifest_exist_server_bundle_separate" } before do - Packer = ReactOnRails::PackerUtils.packer # rubocop:disable Lint/ConstantDefinitionInBlock, RSpec/LeakyConstantDeclaration + Packer = Shakapacker # rubocop:disable Lint/ConstantDefinitionInBlock, RSpec/LeakyConstantDeclaration allow(ReactOnRails::PackerUtils).to receive_messages( manifest_exists?: true, packer_public_output_path: generated_assets_full_path @@ -87,7 +88,10 @@ let(:webpack_generated_files) { %w[client-bundle.js server-bundle.js] } before do - allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(false) + allow(ReactOnRails::PackerUtils).to receive(:manifest_exists?).and_return(true) + allow(ReactOnRails::Utils).to receive(:bundle_js_file_path) do |bundle_name| + File.join(generated_assets_full_path, bundle_name) + end end context "when compiled assets exist and are up-to-date" do diff --git a/spec/react_on_rails/utils_spec.rb b/spec/react_on_rails/utils_spec.rb index 11bf2bca05..dae9850b83 100644 --- a/spec/react_on_rails/utils_spec.rb +++ b/spec/react_on_rails/utils_spec.rb @@ -1,27 +1,26 @@ # frozen_string_literal: true require_relative "spec_helper" -require ReactOnRails::PackerUtils.packer_type +require "shakapacker" # rubocop:disable Metrics/ModuleLength, Metrics/BlockLength module ReactOnRails RSpec.describe Utils do - # Since React on Rails v15+ requires Shakapacker as an explicit dependency, - # we only test with Shakapacker + # Since React on Rails v15+ requires ::Shakapacker as an explicit dependency, + # we only test with ::Shakapacker packers_to_test = ["shakapacker"] shared_context "with packer enabled" do + let(:mock_packer) { instance_double(::Shakapacker::Instance) } + let(:mock_config) { instance_double(::Shakapacker::Configuration) } + let(:mock_dev_server) { instance_double(::Shakapacker::DevServer) } + before do allow(ReactOnRails).to receive_message_chain(:configuration, :generated_assets_dir) .and_return("") - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("dev_server.running?") - .and_return(false) - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("config.public_output_path") - .and_return(packer_public_output_path) - end - - it "uses packer" do - expect(ReactOnRails::PackerUtils.using_packer?).to be(true) + allow(::Shakapacker).to receive_messages(dev_server: mock_dev_server, config: mock_config) + allow(mock_dev_server).to receive(:running?).and_return(false) + allow(mock_config).to receive(:public_output_path).and_return(packer_public_output_path) end end @@ -30,40 +29,24 @@ module ReactOnRails # We don't need to mock anything here because the shakapacker gem is already installed and will be used by default it "uses shakapacker" do - expect(ReactOnRails::PackerUtils.packer_type).to eq("shakapacker") - expect(ReactOnRails::PackerUtils.packer).to eq(::Shakapacker) - end - end - - shared_context "without packer enabled" do - before do - allow(ReactOnRails).to receive_message_chain(:configuration, :generated_assets_dir) - .and_return("public/webpack/dev") - allow(described_class).to receive(:gem_available?).with("shakapacker").and_return(false) - end - - it "does not use packer" do - expect(ReactOnRails::PackerUtils.using_packer?).to be(false) - expect(ReactOnRails::PackerUtils.packer_type).to be_nil - expect(ReactOnRails::PackerUtils.packer).to be_nil + # PackerUtils now uses ::Shakapacker directly + expect(::Shakapacker).to be_present end end def mock_bundle_in_manifest(bundle_name, hashed_bundle) - mock_manifest = instance_double(Object.const_get(ReactOnRails::PackerUtils.packer_type.capitalize)::Manifest) + mock_manifest = instance_double(::Shakapacker::Manifest) allow(mock_manifest).to receive(:lookup!) .with(bundle_name) .and_return(hashed_bundle) - allow(ReactOnRails::PackerUtils.packer).to receive(:manifest).and_return(mock_manifest) + allow(::Shakapacker).to receive(:manifest).and_return(mock_manifest) end def mock_missing_manifest_entry(bundle_name) - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("manifest.lookup!") + allow(::Shakapacker).to receive_message_chain("manifest.lookup!") .with(bundle_name) - .and_raise(Object.const_get( - ReactOnRails::PackerUtils.packer_type.capitalize - )::Manifest::MissingEntryError) + .and_raise(::Shakapacker::Manifest::MissingEntryError) end def random_bundle_name @@ -81,11 +64,11 @@ def mock_bundle_configs(server_bundle_name: random_bundle_name, rsc_bundle_name: end def mock_dev_server_running - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("dev_server.running?") + allow(::Shakapacker).to receive_message_chain("dev_server.running?") .and_return(true) - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("dev_server.protocol") + allow(::Shakapacker).to receive_message_chain("dev_server.protocol") .and_return("http") - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("dev_server.host_with_port") + allow(::Shakapacker).to receive_message_chain("dev_server.host_with_port") .and_return("localhost:3035") end @@ -136,20 +119,14 @@ def mock_dev_server_running end end end - - context "without a packer enabled" do - include_context "without packer enabled" - - it { is_expected.to eq(File.expand_path(File.join(Rails.root, "public/webpack/dev/webpack-bundle.js"))) } - end end describe ".source_path_is_not_defined_and_custom_node_modules?" do it "returns false if node_modules is blank" do allow(ReactOnRails).to receive_message_chain("configuration.node_modules_location") .and_return("") - allow(ReactOnRails::PackerUtils).to receive_message_chain("packer.config.send").with(:data) - .and_return({}) + allow(::Shakapacker).to receive_message_chain("config.send").with(:data) + .and_return({}) expect(described_class.using_packer_source_path_is_not_defined_and_custom_node_modules?).to be(false) end @@ -157,7 +134,7 @@ def mock_dev_server_running it "returns false if source_path is defined in the config/webpacker.yml and node_modules defined" do allow(ReactOnRails).to receive_message_chain("configuration.node_modules_location") .and_return("client") - allow(ReactOnRails::PackerUtils).to receive_message_chain("packer.config.send") + allow(::Shakapacker).to receive_message_chain("config.send") .with(:data).and_return(source_path: "client/app") expect(described_class.using_packer_source_path_is_not_defined_and_custom_node_modules?).to be(false) @@ -166,8 +143,8 @@ def mock_dev_server_running it "returns true if node_modules is not blank and the source_path is not defined in config/webpacker.yml" do allow(ReactOnRails).to receive_message_chain("configuration.node_modules_location") .and_return("node_modules") - allow(ReactOnRails::PackerUtils).to receive_message_chain("packer.config.send").with(:data) - .and_return({}) + allow(::Shakapacker).to receive_message_chain("config.send").with(:data) + .and_return({}) expect(described_class.using_packer_source_path_is_not_defined_and_custom_node_modules?).to be(true) end @@ -193,7 +170,7 @@ def mock_dev_server_running context "with server file in the manifest, used for client", packer_type.to_sym do it "returns the correct path hashed server path" do - packer = ReactOnRails::PackerUtils.packer + packer = ::Shakapacker mock_bundle_configs(server_bundle_name: "webpack-bundle.js") allow(ReactOnRails).to receive_message_chain("configuration.same_bundle_for_client_and_server") .and_return(true) @@ -256,7 +233,7 @@ def mock_dev_server_running context "with server file in the manifest, used for client", packer_type.to_sym do it "returns the correct path hashed server path" do - packer = ReactOnRails::PackerUtils.packer + packer = ::Shakapacker mock_bundle_configs(rsc_bundle_name: "webpack-bundle.js") allow(ReactOnRails).to receive_message_chain("configuration.same_bundle_for_client_and_server") .and_return(true) @@ -504,18 +481,17 @@ def mock_dev_server_running let(:public_output_path) { "/path/to/public/webpack/dev" } before do - allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(true) - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("config.public_output_path") + allow(::Shakapacker).to receive_message_chain("config.public_output_path") .and_return(Pathname.new(public_output_path)) - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("config.public_path") + allow(::Shakapacker).to receive_message_chain("config.public_path") .and_return(Pathname.new("/path/to/public")) end context "when dev server is running" do before do - allow(ReactOnRails::PackerUtils.packer).to receive(:dev_server).and_return( + allow(::Shakapacker).to receive(:dev_server).and_return( instance_double( - Object.const_get(ReactOnRails::PackerUtils.packer_type.capitalize)::DevServer, + ::Shakapacker::DevServer, running?: true, protocol: "http", host_with_port: "localhost:3035" @@ -531,7 +507,7 @@ def mock_dev_server_running context "when dev server is not running" do before do - allow(ReactOnRails::PackerUtils.packer).to receive_message_chain("dev_server.running?") + allow(::Shakapacker).to receive_message_chain("dev_server.running?") .and_return(false) end @@ -541,19 +517,6 @@ def mock_dev_server_running end end end - - context "when not using packer" do - before do - allow(ReactOnRails::PackerUtils).to receive(:using_packer?).and_return(false) - allow(described_class).to receive(:generated_assets_full_path) - .and_return("/path/to/generated/assets") - end - - it "returns joined path with generated_assets_full_path" do - expect(described_class.react_client_manifest_file_path) - .to eq("/path/to/generated/assets/react-client-manifest.json") - end - end end describe ".react_server_client_manifest_file_path" do