Feedbacks on my Isomorphic app using React and ES6

logo-reactjs

UPDATE: This project has been upgraded to React v0.14read the blog post about the upgrade.

This post is about a three steps project I initiated a few weeks ago. I completed the previous step about two weeks ago, so feel free to read my blog post about the front-end part : “Playing with ES6 (and React)”.

Before going further, a quote from stackoverflow (this is the most concise I found) :

Isomorphic web sites can be run on both the server and in the browser. They grant code reuse, seo, and page load speed boosts while still having an interface written in JS. node.js is most often used for the server javascript-engine.

Initial Goal

My challenge was to make an isomorphic app, using React and ES6 :

  • ES6 : I’ve been hearing about it for a while on meetups, articles I read, videos I watched – just like I knew it already – had to throw some real lines of codes 😉
  • React : Same as above (moreover, I’ve been doing a lot of Angular the past two years and hearing more and more about React lately, so I had to try it for real)
  • Isomorphic app : If I were about to use React in a project, it seems to be the perfect opportunity to try to implement it

Project Steps

I split the project into three parts :

  • topheman-apis-proxy : The backend part (and a project on its own as well, since it’s extensible and configurable)
  • topheman/react-es6 : The frontend part where I developed the app in ES6, using React, with the last step in mind – I only used isomorphic libraries
  • topheman/react-es6-isomorphic : The expressJS server in the middle, that handles server-side rendering. I retrieved the frontend part from the previous step. At this point, any missing feature in the client was first developed on the frontend project repo then merged back to this one, to make sure that each project stays focused on its scope (one on frontend, the other on server-side rendering).

Try the app (there is an about page that will help you understand the difference between the two projects). If you’re into React and server-side rendering, take a look at my feedbacks

Give it a try !

Feedbacks

NodeJS / ES6

When you developed your React components in ES6, to run them server-side, you can’t just use require('node-jsx').install() (to make node understand .jsx files).

You’ll need to use require('babel/register'); then node will not only understand .jsx files but also any ES6 files you wrote and required through node’s require() (you won’t even need to run node with the --harmony flag that activates ES6 features implemented in V8 or use iojs).

NodeJS / Webpack

Webpack is a module bundler that comes with many great features. In some cases, they can become overwhelming.

Example : the resolve.alias option that allows you to replace any module by an other (a feature you’ll find on every module loaders).

There won’t be any problem with the client-side bundling of your source code. But when you’ll want to reuse the same code on the server, you’ll have to override node’s require(), passing it Webpack’s options – something that seems to be a lot messy (at least at the time I’m writting those lines).

The first version I made of the network layer service in charge of the API calls was using Webpack’s resolve.alias. I quickly refactored it to avoid the problem I describe above reversing the design, by using injection. You can see the refactor on this commit on topheman/react-es6#6f78bdc.

Note : Things may have evolved since I wrote the code. There might be simple solutions to override node’s require() so that it could take in account Webpack’s options. If you have insights, feel free to leave a comment.

React

Passing state to the client – Data serialization

If you simply return the server-side rendered html, React will re-render client-side your components (you would be loosing the interest of server-side rendering).

This is because when you do server-side rendering, you not only have to pass the markup but also the raw data (the state) on which was based the rendering, so that when the components mount, they already have a state – which is in sync with the existing markup. That way, you can tell React to use the state you passed and prevent it to make any API calls (more likely in componentWillMount).

If you take a look at the source code of a page of my app, you’ll see a var in a script tag, containing those informations. There are other ways to do that (twitter puts it inside a hidden input …).

Here is the commit where I implemented it : topheman/react-es6-isomorphic#7fa4e3d.

Notes :

  • Since I’m using the React router on server (behind express router) and client side, I benefit directly from this router handling me the state (at least the router part : route, query, params …) on both server and client side.
  • I’m passing the full result of the API call in the raw data (a large amount isn’t used on the view), this could be optimized – I’ll take care of that when I’ll implement flux …

React warnings

Warning: render(): Target node has markup rendered by React, but there are unrelated nodes as well. This is most commonly caused by white-space inserted around server-rendered markup.

When React gives you warnings, it’s not three words but a little story as you can see … For this one, I wanted to keep my .ejs layout template readable, so I just wrapped up the generated markup inside div tags.

Deployment

I deploy to heroku via git. On my previous websites, I had grunt tasks that made a full build version of the project into a /dist folder and then git pushed to deploy.

This time, I have a postinstall hook in my package.json which triggers my Webpack build task. So the client side bundles (js, css, assets …) are built on the production server, when I deliver a new release. This is another way to do it … If you take a look at the README, you’ll see there are still automated tasks to run the project in production mode locally.

Next

On this project, the next step would be to implement flux – not that such a small app would absolutely need flux in order to manage all the states, but at least, it would be an opportunity to apply those concepts I’ve been reading about for the last weeks …

Since I accomplished the goal I had set for myself on that project, I’ll be more likely to try something else before coming back on it. I’ve read lots of good things about aurelia, taken a look at the source code … I think I’ll try that next 🙂 .

Tophe

PS : I want to thank Nicolas Cuillery for his talk at React.js Paris “Live-coding sur React” (you can see a video of the same talk he gave at LyonJS – in french). When I attended the meetup, I didn’t start the isomorphic part yet, but it was pretty clear in my head except one thing : passing the raw data from the server to the client. I didn’t think a second about it and I’m sure it saved me some time …

If you haven’t yet,
give it a try !

One thought on “Feedbacks on my Isomorphic app using React and ES6

  1. You’re so cool! I do not suppose I’ve truly read through
    a single thing like this before. So nice to find another person with a few genuine thoughts on this
    issue. Seriously.. thanks for starting this up. This site is
    one thing that’s needed on the internet,
    someone with a bit of originality!

Leave a Reply

Your email address will not be published. Required fields are marked *