-
-
Notifications
You must be signed in to change notification settings - Fork 101
Description
Summary
Add support for HTTP 103 Early Hints to enable browsers to start preloading critical assets (JavaScript, CSS, fonts) while Rails is still rendering the response. This can significantly improve page load performance, especially for slower backends.
Background
What are HTTP 103 Early Hints?
HTTP 103 Early Hints is a status code that allows the server to send preliminary responses with Link:
headers before the final HTTP 200 response. This enables browsers to start downloading critical assets during the server's "think time" while Rails is still rendering views and processing the request.
Timeline:
1. Browser requests page
2. Server sends HTTP 103 with Link: headers → Link: </app.js>; rel=preload; as=script
3. Browser starts downloading assets in parallel ⚡
4. Server finishes rendering and sends HTTP 200 with full HTML
5. Page loads faster because browser started downloading earlier
Current State:
Rails 5.2+ supports request.send_early_hints
, which sends HTTP 103 responses with Link headers to tell browsers to start downloading resources before the full HTML response is ready. However, Shakapacker currently has no built-in integration for this feature.
Solution (Implemented in PR #722)
Zero-Configuration Upgrade
The implementation automatically discovers which packs to preload by reading from Shakapacker's existing pack queues (populated by append_javascript_pack_tag
and append_stylesheet_pack_tag
).
Step 1: Enable in configuration
# config/shakapacker.yml
production:
early_hints:
enabled: true
Step 2: Add one line to layout
<% send_pack_early_hints %> <%# No arguments needed! %>
<!DOCTYPE html>
<html>
<body>
<%= yield %>
<%= javascript_pack_tag 'application' %>
</body>
</html>
Done! Works with existing code - no changes to views needed.
How Automatic Pack Discovery Works
Rails rendering order is the key:
1. Views render first → append_javascript_pack_tag('admin') [queues populate]
2. Layout renders after → send_pack_early_hints() [reads queues!]
3. HTTP 103 sent → Browser starts downloading
4. HTML continues → javascript_pack_tag renders tags
When the layout renders, views have already rendered, so pack queues are populated!
Example: Multi-Pack App
Existing code:
<%# app/views/admin/dashboard.html.erb %>
<% append_javascript_pack_tag 'admin' %>
<% append_stylesheet_pack_tag 'admin' %>
<div class="admin-dashboard">...</div>
Layout:
<% send_pack_early_hints %> <%# Automatically includes 'application' AND 'admin'! %>
<!DOCTYPE html>...
No duplication, no configuration - it just works!
Alternative Usage Patterns
Explicit Pack Names
<% send_pack_early_hints 'application', 'admin' %>
Controller before_action (Before Expensive Queries)
class ApplicationController < ActionController::Base
before_action :send_early_hints
private
def send_early_hints
view_context.send_pack_early_hints('application')
end
end
Integrated with javascript_pack_tag
<%= javascript_pack_tag 'application', early_hints: true %>
Benefits
- Faster perceived load times: Browser starts downloading assets during backend processing
- Better resource utilization: Uses server "think time" productively
- Zero-config upgrade: Works with existing
append_*
pattern - No duplication: Pack names only in views (where they already are)
- Backward compatible: Disabled by default, gracefully degrades
- Flexible: Multiple usage patterns supported
Performance Impact
Early hints are most effective for:
- Critical CSS: Eliminates render-blocking stylesheet downloads
- Critical JS: Starts downloading vendor/app chunks earlier
- Web fonts: Reduces flash of unstyled text (FOUT)
- Slow backends: Maximum benefit with expensive queries/rendering
Example improvement:
Before: Request → Rails renders (3s) → Browser downloads (2s) → Total: 5s
After: Request → HTTP 103 → Downloads in parallel (2s)
→ Rails renders (3s) → Ready! → Total: 3s
40% faster!
Requirements
- Rails 5.2+ (for
request.send_early_hints
support) - Web server with HTTP/2 and early hints support:
- Puma 5+ ✅
- nginx 1.13+ with ngx_http_v2_module ✅
- Other HTTP/2 servers with early hints support
If requirements not met, feature gracefully degrades with no errors.
Implementation Details
The helper:
- Checks if
request.send_early_hints
is available (Rails 5.2+) - Checks if early hints enabled in config
- Collects pack names from queues (if no arguments provided)
- Looks up all chunks for specified packs using existing manifest methods
- Builds Link headers with appropriate
rel=preload
andas=
attributes - Calls
request.send_early_hints(links)
with the collected headers - Returns
nil
to avoid rendering output