Class: Rhales::HydrationInjector
- Inherits:
-
Object
- Object
- Rhales::HydrationInjector
- Defined in:
- lib/rhales/hydration/hydration_injector.rb
Overview
Handles intelligent hydration script injection with multiple strategies for optimal performance and resource loading.
Supported Injection Strategies
Traditional Strategies
:late(default) - Inject before </body> tag (safest, backwards compatible):early- Inject before detected mount points (#app, #root, etc.):earliest- Inject in HTML head section for maximum performance
Link-Based Strategies (API endpoints)
:link- Basic link reference to API endpoint:prefetch- Browser prefetch for future page loads:preload- High priority preload for current page:modulepreload- ES module preloading:lazy- Intersection observer-based lazy loading
Strategy Selection Logic
- Template Disable Check: Respect
disable_early_for_templatesconfiguration - Strategy Routing: Execute strategy-specific injection logic
- Fallback Chain: :earliest → :early → :late (when enabled)
- Safety Validation: All injection points validated for HTML safety
Link-based strategies generate API calls instead of inline data, enabling better caching, parallel loading, and reduced HTML payload.
Constant Summary collapse
- LINK_BASED_STRATEGIES =
[:link, :prefetch, :preload, :modulepreload, :lazy].freeze
Instance Method Summary collapse
-
#generate_all_link_strategies(merged_data, nonce) ⇒ Object
private
-
#initialize(hydration_config, template_name = nil) ⇒ HydrationInjector
constructor
A new instance of HydrationInjector.
-
#inject(template_html, hydration_html, mount_point_data = nil) ⇒ Object
-
#inject_earliest(template_html, hydration_html) ⇒ Object
private
-
#inject_early(template_html, hydration_html, mount_point_data) ⇒ Object
private
-
#inject_late(template_html, hydration_html) ⇒ Object
private
-
#inject_link_based(template_html, hydration_html) ⇒ Object
private
-
#inject_link_based_strategy(template_html, merged_data, nonce = nil) ⇒ Object
Special method for link-based strategies that need merged data context.
-
#template_disabled_for_early? ⇒ Boolean
private
Constructor Details
#initialize(hydration_config, template_name = nil) ⇒ HydrationInjector
Returns a new instance of HydrationInjector.
39 40 41 42 43 44 45 46 47 48 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 39 def initialize(hydration_config, template_name = nil) @hydration_config = hydration_config @template_name = template_name @strategy = hydration_config.injection_strategy @fallback_to_late = hydration_config.fallback_to_late @fallback_when_unsafe = hydration_config.fallback_when_unsafe @disabled_templates = hydration_config.disable_early_for_templates @earliest_detector = EarliestInjectionDetector.new @link_detector = LinkBasedInjectionDetector.new(hydration_config) end |
Instance Method Details
#generate_all_link_strategies(merged_data, nonce) ⇒ Object (private)
154 155 156 157 158 159 160 161 162 163 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 154 def generate_all_link_strategies(merged_data, nonce) link_parts = [] merged_data.each do |window_attr, _data| link_html = @link_detector.generate_for_strategy(@strategy, @template_name, window_attr, nonce) link_parts << link_html end link_parts.join("\n") end |
#inject(template_html, hydration_html, mount_point_data = nil) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 50 def inject(template_html, hydration_html, mount_point_data = nil) return template_html if hydration_html.nil? || hydration_html.strip.empty? # Check if early/earliest injection is disabled for this template if [:early, :earliest].include?(@strategy) && template_disabled_for_early? return inject_late(template_html, hydration_html) end case @strategy when :early inject_early(template_html, hydration_html, mount_point_data) when :earliest inject_earliest(template_html, hydration_html) when :late inject_late(template_html, hydration_html) when *LINK_BASED_STRATEGIES inject_link_based(template_html, hydration_html) else inject_late(template_html, hydration_html) end end |
#inject_earliest(template_html, hydration_html) ⇒ Object (private)
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 122 def inject_earliest(template_html, hydration_html) begin injection_position = @earliest_detector.detect(template_html) rescue => e # Fall back to late injection on detector error return @fallback_to_late ? inject_late(template_html, hydration_html) : template_html end if injection_position before = template_html[0...injection_position] after = template_html[injection_position..] "#{before}#{hydration_html}\n#{after}" else # Fallback to late injection if earliest fails @fallback_to_late ? inject_late(template_html, hydration_html) : template_html end end |
#inject_early(template_html, hydration_html, mount_point_data) ⇒ Object (private)
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 97 def inject_early(template_html, hydration_html, mount_point_data) # Fallback to late injection if no mount point found if mount_point_data.nil? return @fallback_to_late ? inject_late(template_html, hydration_html) : template_html end # Check if the mount point data indicates an unsafe injection # (This would be nil if SafeInjectionValidator found no safe position) if mount_point_data[:position].nil? return @fallback_when_unsafe ? inject_late(template_html, hydration_html) : template_html end # Insert hydration script before the mount element position = mount_point_data[:position] before = template_html[0...position] after = template_html[position..] "#{before}#{hydration_html}\n#{after}" end |
#inject_late(template_html, hydration_html) ⇒ Object (private)
165 166 167 168 169 170 171 172 173 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 165 def inject_late(template_html, hydration_html) # Try to inject before closing </body> tag if template_html.include?('</body>') template_html.sub('</body>', "#{hydration_html}\n</body>") else # If no </body> tag, append to end "#{template_html}\n#{hydration_html}" end end |
#inject_link_based(template_html, hydration_html) ⇒ Object (private)
140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 140 def inject_link_based(template_html, hydration_html) # For link-based strategies, try earliest injection first, then fallback injection_position = @earliest_detector.detect(template_html) if injection_position before = template_html[0...injection_position] after = template_html[injection_position..] "#{before}#{hydration_html}\n#{after}" else # Fallback to late injection @fallback_to_late ? inject_late(template_html, hydration_html) : template_html end end |
#inject_link_based_strategy(template_html, merged_data, nonce = nil) ⇒ Object
Special method for link-based strategies that need merged data context
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 73 def inject_link_based_strategy(template_html, merged_data, nonce = nil) return template_html if merged_data.nil? || merged_data.empty? # Check if early injection is disabled for this template if template_disabled_for_early? # For link strategies, we still generate the links but fall back to late positioning link_html = generate_all_link_strategies(merged_data, nonce) return inject_late(template_html, link_html) end link_html = generate_all_link_strategies(merged_data, nonce) case @strategy when :earliest inject_earliest(template_html, link_html) when *LINK_BASED_STRATEGIES inject_link_based(template_html, link_html) else inject_late(template_html, link_html) end end |
#template_disabled_for_early? ⇒ Boolean (private)
118 119 120 |
# File 'lib/rhales/hydration/hydration_injector.rb', line 118 def template_disabled_for_early? @template_name && @disabled_templates.include?(@template_name) end |