« Post-Mortem: Adopting React on Rails/Webpack

April 28, 2016 • ☕️ 4 min read

We recently pull React and Redux into our stack at work. Our app is a Ruby on Rails, and so up to this point, javascript is either isolated to ember or it is Coffeescript classes with piles of jQuery selectors. These things are totally normal for most Rails apps but after doing most heavy javascript lifting in Ember.js I was really starting to think we should not be doing these bad things. We didn’t want to write another Ember app where Rails generated html was fine.

So when we needed to add rich interactions that would make jQuery cry uncle, we pulled in React. In some ways it has been really great. React has a lot of flexibility, especially for smaller isolated components throughout an otherwise “boring” webpage(notice I said page not app 😉). All in all I think it was a win bringing React on board, but I want to talk about some of the issues we ran into and some things I am stoked about.

After looking at two gems `react-rails` and `react-on-rails` we ended up choosing `react-on-rails`. I am still not sure if this was the ‘right’ choice but it forced us into some things we liked and some we didnt.

One was that we were under some deadlines that were creeping up and react on rails is a lot to digest. It gives you the full SPA experience and is, “batteries included”. This means dependancies! All the dependancies! It pulls in foreman, webpack, react, redux, immutableJS, thunk(I still don’t know what that is), react-router, and of course left-pad, haha JK about the left-pad (kind of, babel depends on it). This made adding components quickly a lot harder than it had to be.

Redux

There are some conventions around redux that make things overly complex at first, but I think will help keep things organized as the app grows. for example, this is the common doctrine/process to update the store.

  1. create a click handler function in your container component.
  2. add the click handler to the markup.
  3. import actions from component actions file.
  4. dispatch an action from the click handler function
  5. from the actions file import the constants from the actionsTypes file (this is a list of constants of the all the reducer’s names)
  6. the actions returns an object with the type property being the reducer’s name and any other values needed to update the state of the redux store.
  7. from there the reducer is invoked. the reducer is usually formatted as a case statement where each type is a case. Each case should return a new, immutable object version of the state, and the default case returns the current state.

So in just 7 easy steps you have a click handler to update your, isOpen property and totally made bootstrap accordions/tabs totally irrelevant. 😂

This was a lot to consume and I am sure I am missing or misunderstanding stuff. It may be hard grasp at first and it also may be a harder than using just React and updating local component state, but I do think this is an example of ‘make the change easy, then make the easy change’, once this is all set up there is a clear data flow, easy debugging and easy changes to actions.

Webpack

Another big piece of all this was Webpack. What the fuck’s a Webpack? Sounds like something I would get bullied at school for wearing. At first pulling Webpack had me worried about adding too much complexity to our build process, but who the fuck am I kidding, we were already in a really shitty position, and Webpack actually forced us to deal with that. We were pulling in JS from gems, bower, and npm. Why Coffeescript? I am not even sure how sprockets works, anyway. So the big move was to let Javascript be in charge of Javascript and tell `rake precompile:assets` to not worry about anything but fingerprinting on deploys.

Moving to Webpack is a lot of work but totally worth it.

There are few phases. The react on rails Webpack build worked pretty well out of the gate and we just added the compiled JS to our `application.js` file on our existing Rails build and started importing all our react stuff.

The next phase to move all these `.coffee` files that are all in globals land that over to the Webpack build. This was a process but worked out pretty well. Depending on how large a codebase you have, you might want to add Coffeescript to your Webpack complier, but for us since we were already using ES6 with react-on-rails we thought it would be best to compile everything to ES5 while moving the files over.

The next phase, pulling all our dependancies into npm, and building all js through Webpack was a big win. Precompiling the assets was tacking on 10 min to deploys and webpack it is seconds. Our dependancies were scattered all over the place and now they are all in one place(npm).

To sum it up major wins for Webpack are: unified dependancies, way faster build time, ES2015, and moving with the javascript ecosystem instead of fighting it.

One downside I am still looking into is having the deploy fail if npm dependancies are not installed and up to date. I dont want to have to run npm install every time I deploy(god knows how long that takes), but I would like the build to fail if it needs to run (so let me know if you have an answer).

In summary I think React on Rails is a great option to be a large piece of your build pipeline and can be really helpful but it might not be the best for your build right now. But if you are feeling your Rails app’s front end it getting out of hand I think React on Rails is a good solution and has a lot of good conventions/boilerplate to help you along. I wouldn’t half ass move over, I think you will hate yourself if you did that. You should think of it as a pretty decent size project to take on, make a plan for, and consider all thing things I listed above when tackling such a project.