Skip to content

Server side rendering when written as CommonJS #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
simonsmith opened this issue Nov 20, 2014 · 7 comments
Closed

Server side rendering when written as CommonJS #120

simonsmith opened this issue Nov 20, 2014 · 7 comments

Comments

@simonsmith
Copy link

The documentation states:

a concatenated file containing all of your React components, and each one has to be available in the global scope (either window or global can be used)

So far all the examples I've seen just expose their React components to the window e.g var Component = React.createClass({})

How can I use components that are written as CommonJS for the client side? Ideally I'd like to avoid dozens of global variables in the browser.

Thanks

@bowd
Copy link
Contributor

bowd commented Dec 9, 2014

@simonsmith I've just started playing around with this and my workflow is based on component.js (which uses CommonJS components).

My configs look something like this:

  config.react.react_js = lambda { "" }
  config.react.component_filenames = [ 'components-server-side-build.js' ]

First of all I'm telling the gem to forget about loading it's react because if you're writing your components as CommonJS chances are you're requiring a version of react with them and have it bundled in your build file, so if this gem would use it's React to render components defined with another React we would have a bad time.

If you take a look at the gems source here:

#{@@react_js.call};
React = global.React;
#{@@components_js.call};

This is how these two things are used. So because i have set the @@react_js lambda to an empty string, React would be undefined.

But for the @@components_js lambda, my components-server-side-build.js file looks something like this:

//= require build/components
React = require('component-react');
global.React = React;

This way I give the server side context access to the React I bundle using component.js.

After that because of the way the gem is written I can do:

= react_component("require('./views/test')", {}, {prerender: true})

This works because it takes the component name (in this case: "require('./views/test')") and either looks for a global var or tries to execute the string as javascript. The latter works and I get my component!

P.S. Currently I don't see any drawbacks to this, but it might not work anymore if there are changes to the implementation at some point (hello forking) and I also just started setting this up so there might be issues I haven't yet come across. Hope this helps!

@simonsmith
Copy link
Author

@bogdan-dumitru Ah very clever workaround, thanks for sharing!

So do you also serve the components-server-side-build.js to the client and wire up the components yourself? Basically what the react_ujs file does

@bowd
Copy link
Contributor

bowd commented Dec 9, 2014

@simonsmith I have a similar manifest for the client that looks something like this:

//= require console-polyfill
//= require build/components
//= require_self
//= require react_ujs

// For the dev tools and ujs
window.React = require('component-react');

So I basically still rely on UJS but I have to make sure that React is again in the scope when it's loaded and I also add some other sparkles here and there like the console polyfill.

@bowd
Copy link
Contributor

bowd commented Dec 9, 2014

@simonsmith and yeah lucky the react_ujs also works out of the box with having "require('...')" as the component name because it also falls back to an eval right now.

@krashidov
Copy link

@bogdan-dumitru do you have an example repo of this anywhere? I don't seem to understand what exactly is in your build/components.js file.

Thanks.

@bowd
Copy link
Contributor

bowd commented Jan 20, 2015

I don't. But let me try to explain a bit. So the build/components.js is the build file for your CommonJS modules.

This could be what browserify spits out, if that's your poison, or in my case it's what my custom component.js build spits out.

In general it's gonna be a javascript file that defines a require function in the global namespace, and then wraps your dependencies in something like define blocks that result in them being expose when doing require(<module name>).

Hope the helps. In a sense that part of the equation, how you get your dependencies components built together can depend on your setup, in my example I was outlying how to link this CommonJS build (wherever it might come from) to react-rails.

@bizmurr
Copy link

bizmurr commented Feb 15, 2015

@bogdan-dumitru Are you using this with react-router at all? I would love to be able to maintain rails routes, server side render and then pass off to the client to continue to handle the routing and etc. Any thoughts on how this would work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants