diff --git a/lib/react/server_rendering/exec_js_renderer.rb b/lib/react/server_rendering/exec_js_renderer.rb index d5eda592d..43aac73f5 100644 --- a/lib/react/server_rendering/exec_js_renderer.rb +++ b/lib/react/server_rendering/exec_js_renderer.rb @@ -11,16 +11,10 @@ def initialize(options={}) end def render(component_name, props, prerender_options) - render_function = prerender_options.fetch(:render_function, "renderToString") - js_code = <<-JS - (function () { - #{before_render(component_name, props, prerender_options)} - var result = ReactDOMServer.#{render_function}(React.createElement(#{component_name}, #{props})); - #{after_render(component_name, props, prerender_options)} - return result; - })() - JS - @context.eval(js_code).html_safe + js_executed_before = before_render(component_name, props, prerender_options) + js_executed_after = after_render(component_name, props, prerender_options) + js_main_section = main_render(component_name, props, prerender_options) + render_from_parts(js_executed_before, js_main_section, js_executed_after) rescue ExecJS::ProgramError => err raise React::ServerRendering::PrerenderError.new(component_name, props, err) end @@ -36,6 +30,28 @@ def after_render(component_name, props, prerender_options); ""; end var window = window || this; JS + private + + def render_from_parts(before, main, after) + js_code = compose_js(before, main, after) + @context.eval(js_code).html_safe + end + + def main_render(component_name, props, prerender_options) + render_function = prerender_options.fetch(:render_function, "renderToString") + "ReactDOMServer.#{render_function}(React.createElement(#{component_name}, #{props}))" + end + + def compose_js(before, main, after) + <<-JS + (function () { + #{before} + var result = #{main}; + #{after} + return result; + })() + JS + end end end end diff --git a/lib/react/server_rendering/sprockets_renderer.rb b/lib/react/server_rendering/sprockets_renderer.rb index 47e904138..21897bb6f 100644 --- a/lib/react/server_rendering/sprockets_renderer.rb +++ b/lib/react/server_rendering/sprockets_renderer.rb @@ -28,19 +28,14 @@ def initialize(options={}) super(options.merge(code: js_code)) end + # Prerender options are expected to be a Hash however might also be a symbol. + # pass prerender: :static to use renderToStaticMarkup + # pass prerender: true to enable default prerender + # pass prerender: {} to proxy some custom options def render(component_name, props, prerender_options) - # pass prerender: :static to use renderToStaticMarkup - react_render_method = if prerender_options == :static - "renderToStaticMarkup" - else - "renderToString" - end - - if !props.is_a?(String) - props = props.to_json - end - - super(component_name, props, {render_function: react_render_method}) + t_options = prepare_options(prerender_options) + t_props = prepare_props(props) + super(component_name, t_props, t_options) end def after_render(component_name, props, prerender_options) @@ -76,6 +71,32 @@ def asset_container def assets_precompiled? !::Rails.application.config.assets.compile end + + private + + def prepare_options(options) + r_func = render_function(options) + opts = case options + when Hash then options + when TrueClass then {} + else + {} + end + # This seems redundant to pass + opts.merge(render_function: r_func) + end + + def render_function(opts) + if opts == :static + 'renderToStaticMarkup'.freeze + else + 'renderToString'.freeze + end + end + + def prepare_props(props) + props.is_a?(String) ? props : props.to_json + end end end end diff --git a/test/react/server_rendering/sprockets_renderer_test.rb b/test/react/server_rendering/sprockets_renderer_test.rb index b602dd7dd..4399c1bc2 100644 --- a/test/react/server_rendering/sprockets_renderer_test.rb +++ b/test/react/server_rendering/sprockets_renderer_test.rb @@ -2,10 +2,29 @@ when_sprockets_available do class SprocketsRendererTest < ActiveSupport::TestCase + CALLBACKS = [:before_render, :after_render] + setup do @renderer = React::ServerRendering::SprocketsRenderer.new({}) end + CALLBACKS.each do |callback_name| + test "#render should pass prerender options to ##{callback_name}" do + mocked_method = MiniTest::Mock.new + mocked_method.expect :call, '', [ + "Todo", + "{\"todo\":\"write tests\"}", + { option: :value, render_function: "renderToString" } + ] + + @renderer.stub callback_name, mocked_method do + @renderer.render("Todo", { todo: "write tests" }, { option: :value }) + end + + mocked_method.verify + end + end + test '#render returns HTML' do result = @renderer.render("Todo", {todo: "write tests"}, nil) assert_match(/