Class: ReactOnRailsPro::ServerRenderingPool::NodeRenderingPool

Inherits:
Object
  • Object
show all
Defined in:
lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb

Overview

This implementation of the rendering pool uses NodeJS to execute javasript code

Constant Summary collapse

RENDERED_HTML_KEY =
"renderedHtml"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.bundle_hashObject (readonly)

Returns the value of attribute bundle_hash.



23
24
25
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 23

def bundle_hash
  @bundle_hash
end

Class Method Details

.eval_js(js_code, render_options, send_bundle: false) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 107

def eval_js(js_code, render_options, send_bundle: false)
  path = prepare_render_path(js_code, render_options)

  request_options = { bundle_role: bundle_role_for(render_options) }
  artifacts = renderer_artifact_snapshot(render_options)
  request_options[:artifacts] = artifacts if artifacts
  response = ReactOnRailsPro::Request.render_code(path, js_code, send_bundle, **request_options)

  case response.status
  when 200
    response.body
  when ReactOnRailsPro::STATUS_SEND_BUNDLE
    # To prevent infinite loop
    ReactOnRailsPro::Error.raise_duplicate_bundle_upload_error if send_bundle

    eval_js(js_code, render_options, send_bundle: true)
  when ReactOnRailsPro::STATUS_BAD_REQUEST
    raise ReactOnRailsPro::Error,
          "Renderer rejected malformed request or hit an unhandled VM error: " \
          "#{response.status}:\n#{response.body}"
  else
    raise ReactOnRailsPro::Error,
          "Unexpected response code from renderer: #{response.status}:\n#{response.body}"
  end
rescue StandardError => e
  raise e unless ReactOnRailsPro.configuration.renderer_use_fallback_exec_js

  fallback_exec_js(js_code, render_options, e)
end

.eval_streaming_js(js_code, render_options) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 68

def eval_streaming_js(js_code, render_options)
  is_rsc_payload = ReactOnRailsPro.configuration.enable_rsc_support && render_options.rsc_payload_streaming?
  async_props_block = render_options.internal_option(:async_props_block)
  rsc_stream_observability = render_options.internal_option(:rsc_stream_observability) == true
  artifacts = renderer_artifact_snapshot(render_options)

  if async_props_block
    # Use incremental rendering when async props block is provided
    path = prepare_incremental_render_path(js_code, render_options)
    push_props = render_options.internal_option(:push_props)
    # Pull mode is enabled whenever push_props is set, including [] for pure pull.
    # nil means push-only mode with no bidirectional prop-request channel.
    pull_enabled = !push_props.nil?
    request_options = {
      async_props_block:,
      pull_enabled:,
      push_props:,
      is_rsc_payload:,
      rsc_stream_observability:
    }
    request_options[:artifacts] = artifacts if artifacts
    ReactOnRailsPro::Request.render_code_with_incremental_updates(
      path,
      js_code,
      **request_options
    )
  else
    # Use standard streaming when no async props block
    path = prepare_render_path(js_code, render_options)
    request_options = { is_rsc_payload:, rsc_stream_observability: }
    request_options[:artifacts] = artifacts if artifacts
    ReactOnRailsPro::Request.render_code_as_stream(
      path,
      js_code,
      **request_options
    )
  end
end

.exec_server_render_js(js_code, render_options) ⇒ Object

js_code: JavaScript expression that returns a string. Returns a Hash:

html: string of HTML for direct insertion on the page by evaluating js_code
consoleReplayScript: script for replaying console
hasErrors: true if server rendering errors

Note, js_code does not have to be based on React. js_code MUST RETURN json stringify Object Calling code will probably call 'html_safe' on return value before rendering to the view.



61
62
63
64
65
66
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 61

def exec_server_render_js(js_code, render_options)
  # The secret sauce is passing self as the 3rd param, the js_evaluator
  render_options.set_option(:throw_js_errors, ReactOnRailsPro.configuration.throw_js_errors)
  ReactOnRails::ServerRenderingPool::RubyEmbeddedJavaScript
    .exec_server_render_js(js_code, render_options, self)
end

.prepare_incremental_render_path(js_code, render_options) ⇒ Object



161
162
163
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 161

def prepare_incremental_render_path(js_code, render_options)
  build_render_path(js_code, render_options, "incremental-render")
end

.prepare_render_path(js_code, render_options) ⇒ Object



154
155
156
157
158
159
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 154

def prepare_render_path(js_code, render_options)
  # TODO: Remove the request_digest. See https://github.com/shakacode/react_on_rails_pro/issues/119
  # From the request path
  # path = "/bundles/#{@bundle_hash}/render"
  build_render_path(js_code, render_options, "render")
end

.renderer_bundle_file_nameObject



45
46
47
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 45

def renderer_bundle_file_name
  "#{ReactOnRailsPro::Utils.bundle_hash}.js"
end

.reset_poolObject



25
26
27
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 25

def reset_pool
  ReactOnRailsPro::Request.reset_connection
end

.reset_pool_if_server_bundle_was_modifiedObject



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 29

def reset_pool_if_server_bundle_was_modified
  # Resetting the pool for server bundle modifications is accomplished by changing the mtime
  # of the server bundle in the request to the remote rendering server.
  # In non-development mode, we don't need to re-read this value.
  if @server_bundle_hash.blank? || ReactOnRails.configuration.development_mode
    @server_bundle_hash = ReactOnRailsPro::Utils.bundle_hash
  end

  unless ReactOnRailsPro.configuration.enable_rsc_support &&
         (@rsc_bundle_hash.blank? || ReactOnRails.configuration.development_mode)
    return
  end

  @rsc_bundle_hash = ReactOnRailsPro::Utils.rsc_bundle_hash
end

.rsc_bundle_hashObject



143
144
145
146
147
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 143

def rsc_bundle_hash
  return ReactOnRailsPro::Utils.rsc_bundle_hash if volatile_artifact_ids?

  @rsc_bundle_hash ||= ReactOnRailsPro::Utils.rsc_bundle_hash
end

.rsc_renderer_bundle_file_nameObject



49
50
51
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 49

def rsc_renderer_bundle_file_name
  "#{ReactOnRailsPro::Utils.rsc_bundle_hash}.js"
end

.server_bundle_hashObject



137
138
139
140
141
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 137

def server_bundle_hash
  return ReactOnRailsPro::Utils.bundle_hash if volatile_artifact_ids?

  @server_bundle_hash ||= ReactOnRailsPro::Utils.bundle_hash
end

.volatile_artifact_ids?Boolean

Returns:

  • (Boolean)


149
150
151
# File 'lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb', line 149

def volatile_artifact_ids?
  ReactOnRails.configuration.development_mode
end