Skip to content

Commit 32c22aa

Browse files
justin808claude
andcommitted
Document content_for pattern to prevent FOUC with SSR and auto_load_bundle
Fixes #1864 When using auto_load_bundle = true with server-side rendering, there's a chicken-and-egg problem: stylesheets must load in the <head>, but react_component calls in <body> trigger auto-appends after the head has rendered, causing FOUC (Flash of Unstyled Content). This commit documents the content_for workaround pattern and references the comprehensive Shakapacker FOUC prevention guide (PR #737). Key improvements: - Explains the root cause of FOUC with SSR + auto_load_bundle - Documents the content_for :body_content pattern with execution flow - Added step-by-step comments showing Rails execution order - References Shakapacker's comprehensive FOUC prevention documentation - Links to working example in react-webpack-rails-tutorial PR #686 - Provides alternative solution (disable auto_load_bundle) - Clarifies that HMR FOUC is separate from this SSR issue - Addresses code review feedback from PR #1865 comment #3412140475 Aligns with Shakapacker PR #737 preventing_fouc.md documentation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent b3ce154 commit 32c22aa

File tree

1 file changed

+47
-12
lines changed

1 file changed

+47
-12
lines changed

docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -522,23 +522,58 @@ As of version 13.3.4, bundles inside directories that match `config.components_s
522522

523523
#### 2. CSS not loading (FOUC - Flash of Unstyled Content)
524524

525-
**Problem**: Components load but CSS styles are missing or delayed.
525+
**Problem**: Components load but CSS styles are missing or delayed, particularly with server-side rendering and `auto_load_bundle = true`.
526526

527-
**Important**: FOUC (Flash of Unstyled Content) **only occurs with HMR (Hot Module Replacement)**. Static and production modes work perfectly without FOUC.
527+
**Root Cause**: When using `auto_load_bundle = true`, `react_component` calls automatically invoke `append_stylesheet_pack_tag` during rendering. However, Shakapacker requires these appends to execute BEFORE the main `stylesheet_pack_tag` in your layout's `<head>`. Since Rails renders the layout's `<head>` before the `<body>` (where `react_component` calls typically occur), the appends happen too late, causing FOUC.
528528

529-
**Solutions**:
529+
**Solution**: Use the `content_for :body_content` pattern documented in Shakapacker's [Preventing FOUC guide](https://github.com/shakacode/shakapacker/blob/master/docs/preventing_fouc.md#the-content_for-body_content-pattern).
530+
531+
This pattern renders your body content first, ensuring all `react_component` auto-appends execute before the `<head>` renders:
532+
533+
```erb
534+
<%# Step 1: This block executes first, capturing content AND triggering auto-appends %>
535+
<% content_for :body_content do %>
536+
<%= react_component "NavigationBarApp", prerender: true %>
537+
538+
<div class="container">
539+
<%= yield %>
540+
</div>
541+
542+
<%= react_component "Footer", prerender: true %>
543+
<% end %>
544+
<!DOCTYPE html>
545+
<html>
546+
<head>
547+
<%= csrf_meta_tags %>
548+
<%= csp_meta_tag %>
549+
550+
<%# Step 2: Head renders with all accumulated stylesheet/JS appends %>
551+
<%= stylesheet_pack_tag(media: 'all') %>
552+
<%= javascript_pack_tag(defer: true) %>
553+
</head>
554+
<body>
555+
<%# Step 3: Finally, the captured body_content is rendered here %>
556+
<%= yield :body_content %>
557+
</body>
558+
</html>
559+
```
560+
561+
**Note**: While defining body content before `<!DOCTYPE html>` may seem counter-intuitive, Rails processes the `content_for` block first (capturing content and triggering appends), then renders the HTML in proper document order.
562+
563+
**Alternative**: If the `content_for` pattern doesn't fit your needs, disable auto-loading and manually specify packs:
564+
565+
```ruby
566+
# config/initializers/react_on_rails.rb
567+
config.auto_load_bundle = false
568+
```
530569

531-
- **Development with HMR** (`./bin/dev`): FOUC is expected behavior due to dynamic CSS injection - **not a bug**
532-
- **Development static** (`./bin/dev static`): No FOUC - CSS is extracted to separate files like production
533-
- **Production** (`./bin/dev prod`): No FOUC - CSS is extracted and optimized
534-
- **Layout**: Verify your layout includes empty `<%= stylesheet_pack_tag %>` placeholder for CSS injection
535-
- **Component imports**: Check that CSS files are properly imported: `import styles from './Component.module.css';`
570+
**Additional Resources**:
536571

537-
**Key insight**: Choose your development mode based on your current needs:
572+
- **Complete FOUC prevention guide**: [Shakapacker Preventing FOUC documentation](https://github.com/shakacode/shakapacker/blob/master/docs/preventing_fouc.md)
573+
- **Working example**: [react-webpack-rails-tutorial PR #686](https://github.com/shakacode/react-webpack-rails-tutorial/pull/686)
574+
- **Related issue**: [Shakapacker #720](https://github.com/shakacode/shakapacker/issues/720)
538575

539-
- Use HMR for fastest development (accept FOUC)
540-
- Use static mode when testing styling without FOUC
541-
- Use production mode for final testing
576+
**Note**: HMR-related FOUC in development mode (dynamic CSS injection) is separate from this SSR auto-loading issue. See Shakapacker docs for details.
542577

543578
#### 3. "document is not defined" errors during SSR
544579

0 commit comments

Comments
 (0)