module Isomorfeus
module ReactViewHelper
def mount_component(component_name, props = {}, asset = 'application_ssr.js')
@ssr_response_status = nil
@ssr_styles = nil
thread_id_asset = "#{Thread.current.object_id}#{asset}"
render_result = "
10
sleep 0.01
first_pass_finished = Isomorfeus.ssr_contexts[thread_id_asset].exec('return global.FirstPassFinished')
end
end
# wait for transport requests to finish
if first_pass_finished == 'transport'
transport_busy = Isomorfeus.ssr_contexts[thread_id_asset].exec('return global.Opal.Isomorfeus.Transport["$busy?"]()')
if transport_busy
start_time = Time.now
while transport_busy
break if (Time.now - start_time) > 10
sleep 0.01
transport_busy = Isomorfeus.ssr_contexts[thread_id_asset].exec('return global.Opal.Isomorfeus.Transport["$busy?"]()')
end
end
end
end
# build javascript for second render pass
# guard against leaks from first pass, maybe because of a exception
javascript = <<~JAVASCRIPT
global.Opal.React.render_buffer = [];
global.Opal.React.active_components = [];
global.Opal.React.active_redux_components = [];
let rendered_tree;
let ssr_styles;
let component;
if (typeof global.Opal.global.MuiStyles !== 'undefined' && typeof global.Opal.global.MuiStyles.ServerStyleSheets !== 'undefined') {
component = '#{component_name}'.split(".").reduce(function(o, x) {
return (o !== null && typeof o[x] !== "undefined" && o[x] !== null) ? o[x] : null;
}, global.Opal.global)
if (!component) { component = global.Opal.Isomorfeus.$cached_component_class('#{component_name}'); }
try {
let sheets = new global.Opal.global.MuiStyles.ServerStyleSheets();
let app = global.Opal.React.$create_element(component, global.Opal.Hash.$new(#{Oj.dump(props, mode: :strict)}));
rendered_tree = global.Opal.global.ReactDOMServer.renderToString(sheets.collect(app));
ssr_styles = sheets.toString();
} catch (e) {
rendered_tree = e.message + "\\n" + e.stack;
}
} else if (typeof global.Opal.global.ReactJSS !== 'undefined' && typeof global.Opal.global.ReactJSS.SheetsRegistry !== 'undefined') {
component = '#{component_name}'.split(".").reduce(function(o, x) {
return (o !== null && typeof o[x] !== "undefined" && o[x] !== null) ? o[x] : null;
}, global.Opal.global)
if (!component) { component = global.Opal.Isomorfeus.$cached_component_class('#{component_name}'); }
try {
let sheets = new global.Opal.global.ReactJSS.SheetsRegistry();
let generate_id = global.Opal.global.ReactJSS.createGenerateId();
let app = global.Opal.React.$create_element(component, global.Opal.Hash.$new(#{Oj.dump(props, mode: :strict)}));
let element = global.Opal.global.React.createElement(global.Opal.global.ReactJSS.JssProvider, { registry: sheets, generateId: generate_id }, app);
rendered_tree = global.Opal.global.ReactDOMServer.renderToString(element);
ssr_styles = sheets.toString();
} catch (e) {
rendered_tree = e.message + "\\n" + e.stack;
}
} else {
try {
rendered_tree = global.Opal.Isomorfeus.TopLevel.$render_component_to_string('#{component_name}', #{Oj.dump(props, mode: :strict)});
} catch (e) {
rendered_tree = e.message + "\\n" + e.stack;
}
}
let application_state = global.Opal.Isomorfeus.store.native.getState();
if (typeof global.Opal.Isomorfeus.Transport !== 'undefined') { global.Opal.Isomorfeus.Transport.$disconnect(); }
return [rendered_tree, application_state, ssr_styles, global.Opal.Isomorfeus['$ssr_response_status']()];
JAVASCRIPT
# execute second render pass
rendered_tree, application_state, @ssr_styles, @ssr_response_status = Isomorfeus.ssr_contexts[thread_id_asset].exec(javascript)
# build result
render_result << " data-iso-hydrated='true'" if rendered_tree
render_result << " data-iso-nloc='#{props[:locale]}' data-iso-state='#{Oj.dump(application_state, mode: :strict)}'>"
render_result << (rendered_tree ? rendered_tree : "SSR didn't work")
else
render_result << " data-iso-nloc='#{props[:locale]}'>"
end
render_result << '
'
render_result
end
def ssr_response_status
@ssr_response_status || 200
end
def ssr_styles
@ssr_styles || ''
end
end
end