JSON into cookie string into JSON into content. Ran into header size limits with some authors. Problem only gets worse over time. Lets rebuild the architecture with an API and a React front end.
react-rails gem <%= react_component(User, name: 'John') %> <!-- becomes: --> <div data-react-class="User" data-react-props="{"name":"John"}"></div> On page load, the react_ujs driver will scan the page and mount components var nodes = window.ReactRailsUJS.findDOMNodes(searchSelector); for (var i = 0; i < nodes.length; ++i) { var node = nodes[i]; var constructor = window[className]; // Some variables omitted renderer.render(React.createElement(constructor, props), node); }
module.exports.raw = true; Load anything you want Enables us to do things like: require('styles/common/footer.scss'); var logo = require('assets/logo.png');
of the app • Common bundles { entry: { bookstore: "./bookstore.js", user_dashboard: "./user_dashboard.js", author_dashboard: "./author_dashboard.js" }, output: { path: path.join(__dirname, "dist"), filename: "[name].entry.js" } } Rails knows which route is being hit, so it can handle sending the correct entry file.
Page load speed ◦ Avoid hitting API for same content • Render everything that doesn’t depend on current user • Prepopulate reflux stores with data from Rails • Cache result on server
asset pipeline lets you write JS in Rails js_code = <<-JS (function () { var result = ReactDOMServer.#{render_function}(React.createElement(#{component_name}, #{props})); return result; })() JS Rails does not play nice with Webpack
ReactDOMServer from 'react-dom/server'; import Router from 'react-router'; import routes from './routes/index.jsx'; var rendered = ''; Router.run(routes, path, (Root) => { rendered = ReactDOMServer.renderToString(<Root />); }); console.log(rendered); • Lifecycle methods do not trigger • Needs a path • Needs prepopulated data
'assets', 'server-bundle.js') data = @fluxxor_data.to_s output = sh("node #{script} -p / -s '#{data}'") "<div id='react-root'>#{output}</div>".html_safe end Run the webpack bundle in node with our data as parameters
_ from 'lodash'; // Prepopulate all the stores for (let key of Object.keys(storeDataRaw)) { let store = null; switch(key) { case 'books': store = BooksStore; break; } if (store) { store.data = _.merge(store.data, storeDataRaw[key]); } } Add data from node arguments into stores before we render
about writing your components ◦ Always check if data is in the store before requesting it from the server ◦ Only request new data after componentDidMount ◦ Be able to render without references to window / document • Let Rails perform normal page caching • On page load, boot react app as normal
end • Reflux for client side data storage and manipulation • Webpack bundler • Node for server side rendering • Not dependant on rails • Not dependant on any Flux implementation • No asset pipeline • No namespacing issues