Class: Ruact::Flight::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/ruact/flight/renderer.rb

Overview

Renders a React element tree to a Flight wire format string.

Usage:

output = Renderer.render(root_element, bundler_config)
# => "1:I[...]\n0:[\"$\",\"div\",...]\n"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model, bundler_config, strict_serialization: false, on_as_json_warning: nil) ⇒ Renderer

Returns a new instance of Renderer.



24
25
26
27
28
# File 'lib/ruact/flight/renderer.rb', line 24

def initialize(model, bundler_config, strict_serialization: false, on_as_json_warning: nil)
  @request = Request.new(model, bundler_config,
                         strict_serialization: strict_serialization,
                         on_as_json_warning: on_as_json_warning)
end

Class Method Details

.each(model, bundler_config, strict_serialization: false, on_as_json_warning: nil, streaming: true) ⇒ Object



17
18
19
20
21
22
# File 'lib/ruact/flight/renderer.rb', line 17

def self.each(model, bundler_config, strict_serialization: false, on_as_json_warning: nil,
              streaming: true, &)
  new(model, bundler_config,
      strict_serialization: strict_serialization,
      on_as_json_warning: on_as_json_warning).each(streaming: streaming, &)
end

.render(model, bundler_config) ⇒ Object



13
14
15
# File 'lib/ruact/flight/renderer.rb', line 13

def self.render(model, bundler_config, **)
  each(model, bundler_config, streaming: false, **).to_a.join
end

Instance Method Details

#each(streaming: true) {|root_row| ... } ⇒ Object

Yields Flight rows one at a time. Flush order: imports → regular → root → deferred (with optional delay) → errors. When streaming: false (initial HTML shell), deferred delays are skipped.

Yields:

  • (root_row)


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ruact/flight/renderer.rb', line 33

def each(streaming: true, &block)
  return enum_for(:each, streaming: streaming) unless block_given?

  root_id = @request.allocate_id # => 0

  serializer = Serializer.new(@request)
  root_value = serializer.serialize_model(@request.root_model)
  root_json  = JSON.generate(root_value)
  root_row   = RowEmitter.model(root_id, root_json)

  @request.completed_import_chunks.each(&block)
  @request.completed_regular_chunks.each(&block)
  yield root_row

  # Deferred chunks: emitted after root, optionally delayed (Suspense streaming).
  # When the chunk delay exceeds suspense_timeout, an E-type error row is emitted instead.
  @request.deferred_chunks.each do |deferred|
    if streaming && deferred[:delay]&.positive?
      timeout = Ruact.config.suspense_timeout
      if timeout&.positive? && deferred[:delay] > timeout
        yield RowEmitter.error(deferred[:id], JSON.generate("Suspense timeout exceeded"))
        next
      end
      sleep(deferred[:delay])
    end

    # Serialize deferred content — may produce new import rows
    import_count_before = @request.completed_import_chunks.length
    deferred_value = serializer.serialize_model(deferred[:element])

    # Yield any import rows discovered during deferred serialization
    @request.completed_import_chunks[import_count_before..].each(&block)

    yield RowEmitter.model(deferred[:id], JSON.generate(deferred_value))
  end

  @request.completed_error_chunks.each(&block)
end