diff --git a/docs/building-features/turbolinks.md b/docs/building-features/turbolinks.md index 5c8fa53945..2948ed9751 100644 --- a/docs/building-features/turbolinks.md +++ b/docs/building-features/turbolinks.md @@ -52,6 +52,79 @@ Turbo Frames work with React components without any special configuration: <%# Clicking a link that responds with another turbo_frame_tag will update just that frame %> ``` +### Turbo with Auto-Bundling + +When using React on Rails' [auto-bundling feature](../core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md) (`auto_load_bundle: true`) with Turbo, there's a specific ordering requirement to address: + +**The Challenge:** + +1. **Turbo's requirement**: Turbo must be loaded in the `` to avoid script re-evaluation warnings during page navigation +2. **Auto-registration's behavior**: `react_component` with `auto_load_bundle: true` calls `append_javascript_pack_tag` during body rendering +3. **Shakapacker's requirement**: All `append_javascript_pack_tag` calls must occur before the final `javascript_pack_tag` + +This creates a conflict: the `` (with `javascript_pack_tag`) renders before the `` (where `react_component` triggers auto-appends). + +**The Solution: `content_for :body_content` Pattern** + +Use `content_for` to render your body content first, capturing auto-appends before the head renders: + +```erb +<%# Step 1: Capture body content FIRST - this triggers all auto-appends %> +<% content_for :body_content do %> + <%= react_component "NavigationBarApp", prerender: true %> + +
+ <%= yield %> +
+ + <%= react_component "Footer", prerender: true %> + <%= redux_store_hydration_data %> +<% end %> + + + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%# Optional: Explicitly load non-React packs (Stimulus, shared stores, etc.) %> + <%# React component bundles are already auto-appended by react_component calls above %> + <%# Do NOT manually append component bundles here - they're already included %> + <%= append_stylesheet_pack_tag('stimulus-bundle') %> + <%= append_javascript_pack_tag('stimulus-bundle') %> + <%= append_javascript_pack_tag('stores-registration') %> + + <%# Step 2: Pack tags now include all component bundles from auto-appends above %> + <%= stylesheet_pack_tag(media: 'all') %> + <%= javascript_pack_tag(defer: true) %> + + + <%# Step 3: Output the captured body content %> + <%= yield :body_content %> + + +``` + +**Why This Works:** + +1. Rails processes the `content_for` block first, which executes all `react_component` calls +2. Each `react_component` with `auto_load_bundle: true` triggers `append_javascript_pack_tag` +3. When the `` renders, `javascript_pack_tag` includes all accumulated appends +4. Turbo loads early in ``, satisfying its requirement +5. Component bundles load in the correct order + +**Note:** While defining body content before `` may look unusual, Rails processes `content_for` blocks during template evaluation, not document output order. The final HTML is correctly structured. + +**Common Pitfalls:** + +- ❌ Don't place `javascript_pack_tag` before `content_for` blocks that call `react_component` +- ❌ Don't manually append component bundles if using `auto_load_bundle: true` +- ✅ Do let `react_component` handle bundle appending automatically + +**Additional Resources:** + +- [Shakapacker Preventing FOUC guide](https://github.com/shakacode/shakapacker/blob/main/docs/preventing_fouc.md#the-content_for-body_content-pattern) +- [Turbo Handbook - Working with Script Elements](https://turbo.hotwired.dev/handbook/building#working-with-script-elements) + ### Turbo Streams (Requires React on Rails Pro) > **⚡️ React on Rails Pro Feature** diff --git a/docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md b/docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md index 9fabdd51a9..17fbab85ab 100644 --- a/docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md +++ b/docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md @@ -569,7 +569,8 @@ config.auto_load_bundle = false **Additional Resources**: -- **Complete FOUC prevention guide**: [Shakapacker Preventing FOUC documentation](https://github.com/shakacode/shakapacker/blob/master/docs/preventing_fouc.md) +- **Complete FOUC prevention guide**: [Shakapacker Preventing FOUC documentation](https://github.com/shakacode/shakapacker/blob/main/docs/preventing_fouc.md) +- **Turbo/Hotwire integration**: [Using auto-bundling with Turbo](../building-features/turbolinks.md#turbo-with-auto-bundling) - same pattern required for Turbo compatibility - **Working example**: [react-webpack-rails-tutorial PR #686](https://github.com/shakacode/react-webpack-rails-tutorial/pull/686) - **Related issue**: [Shakapacker #720](https://github.com/shakacode/shakapacker/issues/720)