React Server-Side Rendering for Rails
require 'connection_pool'
class ReactRenderer
mattr_accessor :pool
def self.setup!
size = ::Rails.configuration.react.max_renderers || 10
timeout = ::Rails.configuration.react.renderer_timeout || 20 #seconds
@@pool ||= ConnectionPool.new(:size => size, :timeout => timeout) { ReactRenderer.new }
end
def self.render(component, args={})
@@pool.with do |renderer|
renderer.render(component, args)
end
end
def context
@context ||= begin
react_code = File.read(::React::Source.bundled_path_for("react-with-addons.min.js"))
components_code = ::Rails.application.assets['components.js'].to_s
all_code = <<-CODE
var global = global || this;
#{react_code};
React = global.React;
#{components_code};
CODE
ExecJS.compile(all_code)
end
end
def render(component, args={})
# This works because even though renderComponentToString uses a callback API it is really synchronous
jscode = <<-JS
function() {
var html = "";
React.renderComponentToString(#{component}(#{args.to_json}), function(s){html = s});
return html;
}()
JS
context.eval(jscode).html_safe
end
end