Module: ReactOnRailsProHelper
- Includes:
- ScoutApm::Tracer
- Defined in:
- app/helpers/react_on_rails_pro_helper.rb
Overview
rubocop:disable Metrics/ModuleLength
Constant Summary collapse
- STATIC_RSC_RENDER_DIAGNOSTIC_EVENT =
"render_static_rsc_component.react_on_rails_pro"- HTML_SPACE_CHARACTERS =
[" ", "\t", "\n", "\f", "\r"].freeze
- HTML_QUOTE_CHARACTERS =
['"', "'"].freeze
- SCRIPT_OPEN_TAG =
"<script"- SCRIPT_OPEN_TAG_LENGTH =
7- SCRIPT_CLOSE_TAG =
"</script"- SCRIPT_CLOSE_TAG_LENGTH =
8- STATIC_RSC_PAYLOAD_SCRIPT_MARKER_ATTRIBUTE =
"data-react-on-rails-rsc-payload"- STATIC_RSC_ASSET_DIAGNOSTIC_CACHE_MUTEX =
Mutex.new
Class Attribute Summary collapse
-
.static_rsc_asset_diagnostic_cache ⇒ Object
readonly
Returns the value of attribute static_rsc_asset_diagnostic_cache.
Class Method Summary collapse
Instance Method Summary collapse
-
#async_react_component(component_name, options = {}) ⇒ ReactOnRailsPro::AsyncValue
Renders a React component asynchronously, returning an AsyncValue immediately.
-
#buffered_stream_react_component(component_name, options = {}) ⇒ Object
Renders a stream-capable component through the streaming/RSC renderer, but buffers every chunk before returning HTML to Rails.
-
#cached_async_react_component(component_name, raw_options = {}) { ... } ⇒ ReactOnRailsPro::AsyncValue, ReactOnRailsPro::ImmediateAsyncValue
Renders a React component asynchronously with caching support.
-
#cached_buffered_stream_react_component(component_name, raw_options = {}, &block) ⇒ Object
Cached version of buffered_stream_react_component.
-
#cached_react_component(component_name, raw_options = {}, &block) ⇒ Object
Provide caching support for react_component in a manner akin to Rails fragment caching.
-
#cached_react_component_hash(component_name, raw_options = {}, &block) ⇒ Object
Provide caching support for react_component_hash in a manner akin to Rails fragment caching.
-
#cached_static_rsc_component(component_name, raw_options = {}, &block) ⇒ Object
Cached static RSC rendering for public pages that use a sidecar pack instead of hydrating the generated page pack.
-
#cached_stream_react_component(component_name, raw_options = {}, &block) ⇒ Object
Provide caching support for stream_react_component in a manner akin to Rails fragment caching.
- #fetch_react_component(component_name, options) ⇒ Object
-
#rsc_payload_react_component(component_name, options = {}) ⇒ String
Renders the React Server Component (RSC) payload for a given component.
- #rsc_payload_react_component_with_async_props(component_name, options = {}, &props_block) ⇒ Object
-
#stream_react_component(component_name, options = {}) ⇒ Object
Streams a server-side rendered React component using React's
renderToPipeableStream. - #stream_react_component_with_async_props(component_name, options = {}, &props_block) ⇒ Object
Class Attribute Details
.static_rsc_asset_diagnostic_cache ⇒ Object (readonly)
Returns the value of attribute static_rsc_asset_diagnostic_cache.
40 41 42 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 40 def static_rsc_asset_diagnostic_cache @static_rsc_asset_diagnostic_cache end |
Class Method Details
.clear_static_rsc_asset_diagnostic_cache! ⇒ Object
42 43 44 45 46 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 42 def clear_static_rsc_asset_diagnostic_cache! STATIC_RSC_ASSET_DIAGNOSTIC_CACHE_MUTEX.synchronize do @static_rsc_asset_diagnostic_cache = {} end end |
Instance Method Details
#async_react_component(component_name, options = {}) ⇒ ReactOnRailsPro::AsyncValue
Renders a React component asynchronously, returning an AsyncValue immediately. Multiple async_react_component calls will execute their HTTP rendering requests concurrently instead of sequentially.
Requires the controller to include ReactOnRailsPro::AsyncRendering and call enable_async_react_rendering.
389 390 391 392 393 394 395 396 397 398 399 400 401 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 389 def async_react_component(component_name, = {}) unless defined?(@react_on_rails_async_barrier) && @react_on_rails_async_barrier raise ReactOnRailsPro::Error, "async_react_component requires AsyncRendering concern. " \ "Include ReactOnRailsPro::AsyncRendering in your controller and call enable_async_react_rendering." end task = @react_on_rails_async_barrier.async do react_component(component_name, ) end ReactOnRailsPro::AsyncValue.new(task:) end |
#buffered_stream_react_component(component_name, options = {}) ⇒ Object
Renders a stream-capable component through the streaming/RSC renderer, but buffers every chunk before returning HTML to Rails. Use this for static/cacheable responses that need RSC rendering without ActionController::Live committing headers on the first streamed byte.
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 177 def buffered_stream_react_component(component_name, = {}) = .dup [:prerender] = true if .key?(:immediate_hydration) ReactOnRails::Helper.warn_removed_immediate_hydration_option("buffered_stream_react_component") .delete(:immediate_hydration) end on_complete = .delete(:on_complete) collect_chunks = on_complete.respond_to?(:call) buffer = collect_chunks ? [] : +"" internal_stream_react_component(component_name, ).each_chunk do |chunk| buffer << chunk.to_s end if collect_chunks html = buffer.join.html_safe on_complete.call(buffer) html else buffer.html_safe end end |
#cached_async_react_component(component_name, raw_options = {}) { ... } ⇒ ReactOnRailsPro::AsyncValue, ReactOnRailsPro::ImmediateAsyncValue
Renders a React component asynchronously with caching support. Cache lookup is synchronous - cache hits return immediately without async. Cache misses trigger async render and cache the result on completion.
All the same options as cached_react_component apply:
- You must pass the props as a block (evaluated only on cache miss)
- Provide the cache_key option
- Optionally provide :cache_options for Rails.cache (expires_in, etc.)
- Provide :if or :unless for conditional caching
- Optionally provide :cache_tags for revalidation via ReactOnRailsPro.revalidate_tag
423 424 425 426 427 428 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 423 def cached_async_react_component(component_name, = {}, &block) ReactOnRailsPro::Utils.with_trace(component_name) do (, block) fetch_async_react_component(component_name, , &block) end end |
#cached_buffered_stream_react_component(component_name, raw_options = {}, &block) ⇒ Object
Cached version of buffered_stream_react_component. Unlike cached_stream_react_component, this returns the complete HTML string from the cache/miss path and does not require stream_view_containing_react_components. The on_complete callback is unsupported because cache hits do not replay chunks.
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 315 def cached_buffered_stream_react_component(component_name, = {}, &block) ReactOnRailsPro::Utils.with_trace(component_name) do (, block) if [:on_complete].respond_to?(:call) raise ReactOnRailsPro::Error, "cached_buffered_stream_react_component does not support on_complete; " \ "use buffered_stream_react_component for chunk callbacks" end = () = .merge( cache_key: lambda do raw_cache_key = [:cache_key] cache_key_value = raw_cache_key.respond_to?(:call) ? raw_cache_key.call : raw_cache_key ["buffered_stream_react_component", cache_key_value] end, prerender: true ) cached_result = fetch_react_component(component_name, ) do = .merge( props: yield, skip_prerender_cache: true ) buffered_stream_react_component(component_name, ) end cached_result.html_safe end end |
#cached_react_component(component_name, raw_options = {}, &block) ⇒ Object
Provide caching support for react_component in a manner akin to Rails fragment caching. All the same options as react_component apply with the following difference:
- You must pass the props as a block. This is so that the evaluation of the props is not done if the cache can be used.
- Provide the cache_key option cache_key: String or Array (or Proc returning a String or Array) containing your cache keys. If prerender is set to true, the server bundle digest will be included in the cache key. When RSC support is enabled and the RSC bundle exists, the RSC bundle digest is also included. The cache_key value is the same as used for conventional Rails fragment caching.
- Optionally provide the
:cache_optionskey with a value of a hash including as :compress, :expires_in, :race_condition_ttl as documented in the Rails Guides - Provide boolean values for
:ifor:unlessto conditionally use caching. - Optionally provide the
:cache_tagsoption: String or Array (or Proc, or any object responding tocache_key, such as an ActiveRecord model) of revalidation tags. Tagged cache entries can be deleted later withReactOnRailsPro.revalidate_tag(tag). Tag revalidation is best-effort, so also setcache_options: { expires_in: ... }to bound staleness.
79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 79 def cached_react_component(component_name, = {}, &block) ReactOnRailsPro::Utils.with_trace(component_name) do (, block) = () fetch_react_component(component_name, ) do = .dup [:props] = yield [:skip_prerender_cache] = true react_component(component_name, ) end end end |
#cached_react_component_hash(component_name, raw_options = {}, &block) ⇒ Object
Provide caching support for react_component_hash in a manner akin to Rails fragment caching. All the same options as react_component_hash apply with the following difference:
- You must pass the props as a block. This is so that the evaluation of the props is not done if the cache can be used.
- Provide the cache_key option cache_key: String or Array (or Proc returning a String or Array) containing your cache keys. Since prerender is automatically set to true, the server bundle digest will be included in the cache key. When RSC support is enabled and the RSC bundle exists, the RSC bundle digest is also included. The cache_key value is the same as used for conventional Rails fragment caching.
- Optionally provide the
:cache_optionskey with a value of a hash including as :compress, :expires_in, :race_condition_ttl as documented in the Rails Guides - Provide boolean values for
:ifor:unlessto conditionally use caching. - Optionally provide the
:cache_tagsoption: String or Array (or Proc, or any object responding tocache_key, such as an ActiveRecord model) of revalidation tags. Tagged cache entries can be deleted later withReactOnRailsPro.revalidate_tag(tag). Tag revalidation is best-effort, so also setcache_options: { expires_in: ... }to bound staleness.
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 110 def cached_react_component_hash(component_name, = {}, &block) [:prerender] = true ReactOnRailsPro::Utils.with_trace(component_name) do (, block) = () fetch_react_component(component_name, ) do = .dup [:props] = yield [:skip_prerender_cache] = true react_component_hash(component_name, ) end end end |
#cached_static_rsc_component(component_name, raw_options = {}, &block) ⇒ Object
Cached static RSC rendering for public pages that use a sidecar pack instead of hydrating the generated page pack. The cached value is the buffered HTML after removing embedded RSC payload bootstrap scripts.
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 349 def cached_static_rsc_component(component_name, = {}, &block) ReactOnRailsPro::Utils.with_trace(component_name) do = .dup diagnostics_context = static_rsc_diagnostics_context() (, block) () = () = (, ) cached_result = render_cached_static_rsc_component( component_name, , , diagnostics_context, &block ) emit_static_rsc_render_diagnostics(component_name, , diagnostics_context, cached_result) cached_result.html_safe end end |
#cached_stream_react_component(component_name, raw_options = {}, &block) ⇒ Object
Provide caching support for stream_react_component in a manner akin to Rails fragment caching. All the same options as stream_react_component apply with the following differences:
- You must pass the props as a block. This is so that the evaluation of the props is not done if the cache can be used.
- Provide the cache_key option cache_key: String or Array (or Proc returning a String or Array) containing your cache keys. Since prerender is automatically set to true, the server bundle digest will be included in the cache key. When RSC support is enabled and the RSC bundle exists, the RSC bundle digest is also included. The cache_key value is the same as used for conventional Rails fragment caching.
- Optionally provide the
:cache_optionskey with a value of a hash including as :compress, :expires_in, :race_condition_ttl as documented in the Rails Guides - Provide boolean values for
:ifor:unlessto conditionally use caching. - Optionally provide the
:cache_tagsoption: String or Array (or Proc, or any object responding tocache_key, such as an ActiveRecord model) of revalidation tags. Tagged cache entries can be deleted later withReactOnRailsPro.revalidate_tag(tag). Tag revalidation is best-effort, so also setcache_options: { expires_in: ... }to bound staleness.
304 305 306 307 308 309 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 304 def cached_stream_react_component(component_name, = {}, &block) ReactOnRailsPro::Utils.with_trace(component_name) do (, block) fetch_stream_react_component(component_name, , &block) end end |
#fetch_react_component(component_name, options) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 49 def fetch_react_component(component_name, , &) ReactOnRailsPro::Cache.fetch_react_component( component_name, , { on_cache_hit: lambda do |cached_component_name, | load_pack_for_cached_react_component(cached_component_name, ) end }, & ) end |
#rsc_payload_react_component(component_name, options = {}) ⇒ String
This helper requires React Server Components support to be enabled in your configuration: ReactOnRailsPro.configure do |config| config.enable_rsc_support = true end
You don't have to deal directly with this helper function - it's used internally by the
Renders the React Server Component (RSC) payload for a given component. This helper generates a special format designed by React for serializing server components and transmitting them to the client.
Example NDJSON stream:
{"html":"<RSC Payload>","consoleReplayScript":"","hasErrors":false,"isShellReady":true}
{"html":"<RSC Payload>","consoleReplayScript":"console.log('Loading...')","hasErrors":false,"isShellReady":true}
The RSC payload within the html field contains:
- The component's rendered output from the server
- References to client components that need hydration
- Data props passed to client components
rsc_payload_route helper function. The returned data from this function is used internally by
components registered using the registerServerComponent function. Don't use it unless you need
more control over the RSC payload generation. To know more about RSC payload, see the following link:
274 275 276 277 278 279 280 281 282 283 284 285 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 274 def rsc_payload_react_component(component_name, = {}) # rsc_payload_react_component doesn't have the prerender option # Because setting prerender to false will not do anything [:prerender] = true # Extract streaming-specific callback on_complete = .delete(:on_complete) consumer_stream_async(on_complete:) do internal_rsc_payload_react_component(component_name, ) end end |
#rsc_payload_react_component_with_async_props(component_name, options = {}, &props_block) ⇒ Object
214 215 216 217 218 219 220 221 222 223 224 |
# File 'app/helpers/react_on_rails_pro_helper.rb', line 214 def rsc_payload_react_component_with_async_props(component_name, = {}, &props_block) unless ReactOnRailsPro.configuration.enable_rsc_support raise ReactOnRailsPro::Error, "rsc_payload_react_component_with_async_props requires enable_rsc_support to be true. " \ "Async props depend on React Server Components. " \ "Set `config.enable_rsc_support = true` in your ReactOnRailsPro configuration." end [:async_props_block] = props_block rsc_payload_react_component(component_name, ) end |
#stream_react_component(component_name, options = {}) ⇒ Object
Streams a server-side rendered React component using React's renderToPipeableStream.
Supports React 18 features like Suspense, concurrent rendering, and selective hydration.
Enables progressive rendering and improved performance for large components.
Note: This function can only be used with React on Rails Pro.
The view that uses this function must be rendered using the
stream_view_containing_react_components method from the React on Rails Pro gem.
Example of an async React component that can benefit from streaming:
const AsyncComponent = async () => { const data = await fetchData(); return
function App() {
return (