diff --git a/lib/react_on_rails/configuration.rb b/lib/react_on_rails/configuration.rb index 82f76bb76b..6d89cd071e 100644 --- a/lib/react_on_rails/configuration.rb +++ b/lib/react_on_rails/configuration.rb @@ -154,9 +154,9 @@ def check_component_registry_timeout raise ReactOnRails::Error, "component_registry_timeout must be a positive integer" end - # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def validate_generated_component_packs_loading_strategy - # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity if defer_generated_component_packs if %i[async sync].include?(generated_component_packs_loading_strategy) @@ -176,11 +176,12 @@ def validate_generated_component_packs_loading_strategy 1. Use :defer or :sync loading strategy instead of :async 2. Upgrade to Shakapacker v8.2.0 or above to enable async script loading MSG - if generated_component_packs_loading_strategy.nil? - # Use defer as the default to ensure generated component packs load and register - # components before main bundle executes, avoiding race conditions with async loading - self.generated_component_packs_loading_strategy = :defer - elsif generated_component_packs_loading_strategy == :async && !PackerUtils.supports_async_loading? + if PackerUtils.supports_async_loading? + self.generated_component_packs_loading_strategy ||= :async + elsif generated_component_packs_loading_strategy.nil? + Rails.logger.warn("**WARNING** #{msg}") + self.generated_component_packs_loading_strategy = :sync + elsif generated_component_packs_loading_strategy == :async raise ReactOnRails::Error, "**ERROR** #{msg}" end diff --git a/spec/dummy/app/views/layouts/application.html.erb b/spec/dummy/app/views/layouts/application.html.erb index 8c7bc06bb0..0e25174d52 100644 --- a/spec/dummy/app/views/layouts/application.html.erb +++ b/spec/dummy/app/views/layouts/application.html.erb @@ -9,10 +9,16 @@ <%= yield :head %> - <%# Use defer: true to ensure proper script execution order. - When using generated component packs (auto_load_bundle), defer ensures - component registrations complete before React hydration begins. %> - <%= javascript_pack_tag('client-bundle', 'data-turbo-track': 'reload', defer: true) %> + <%# Conditionally use defer: true for pages with Redux shared stores (inline registration). + Modern apps should use async: true for optimal performance. See docs for details: + docs/building-features/streaming-server-rendering.md %> + <% if uses_redux_shared_store? %> + <%# defer: true required for Redux shared stores with inline component registration %> + <%= javascript_pack_tag('client-bundle', 'data-turbo-track': 'reload', defer: true) %> + <% else %> + <%# async: true is the recommended approach for modern apps (Shakapacker >= 8.2.0) %> + <%= javascript_pack_tag('client-bundle', 'data-turbo-track': 'reload', async: true) %> + <% end %> <%= csrf_meta_tags %> diff --git a/spec/dummy/config/initializers/react_on_rails.rb b/spec/dummy/config/initializers/react_on_rails.rb index 7578a995df..54c2f40d5c 100644 --- a/spec/dummy/config/initializers/react_on_rails.rb +++ b/spec/dummy/config/initializers/react_on_rails.rb @@ -42,6 +42,5 @@ def self.adjust_props_for_client_side_hydration(component_name, props) config.components_subdirectory = "startup" config.auto_load_bundle = true config.immediate_hydration = false - # Don't explicitly set generated_component_packs_loading_strategy - let it default to :defer - # which ensures generated component packs load and register components before main bundle executes + config.generated_component_packs_loading_strategy = :defer end diff --git a/spec/react_on_rails/configuration_spec.rb b/spec/react_on_rails/configuration_spec.rb index e4198b8d94..e3123fcdb0 100644 --- a/spec/react_on_rails/configuration_spec.rb +++ b/spec/react_on_rails/configuration_spec.rb @@ -284,9 +284,9 @@ module ReactOnRails .with("8.2.0").and_return(true) end - it "defaults to :defer" do + it "defaults to :async" do ReactOnRails.configure {} # rubocop:disable Lint/EmptyBlock - expect(ReactOnRails.configuration.generated_component_packs_loading_strategy).to eq(:defer) + expect(ReactOnRails.configuration.generated_component_packs_loading_strategy).to eq(:async) end it "accepts :async value" do @@ -332,9 +332,10 @@ module ReactOnRails allow(Rails.logger).to receive(:warn) end - it "defaults to :defer" do + it "defaults to :sync and logs a warning" do ReactOnRails.configure {} # rubocop:disable Lint/EmptyBlock - expect(ReactOnRails.configuration.generated_component_packs_loading_strategy).to eq(:defer) + expect(ReactOnRails.configuration.generated_component_packs_loading_strategy).to eq(:sync) + expect(Rails.logger).to have_received(:warn).with(/does not support async script loading/) end it "accepts :defer value" do