Recently I’ve been digging into the world of React and ES6. I was keen to get these working in a Rails context. The key things I wanted to achieve were server-side rendering, ES6 syntax JavaScript, react-router and to import node modules. On a heavily delayed train journey from London to Edinburgh I decided to try crack it.

There are a bunch of gems that can get us most of the way with very little configuration. However all of these don’t get you quite to my desired feature combination, but with a bit of tweaking it is possible.

There is React-Rails

We can use use the react-rails gem to get moving pretty fast. It adds both JSX and Babel transpilers to the asset pipeline so you can generate your React files just like any other Rails asset with the .jsx suffix. The gem is also maintained (or at least approved) by the React organisation, so it feels like an officially supported way to use React.

Most beneficial of all is it provides a simple view helper that can be used in your views to render your React component to the HTML server side. It also provides a script that will start your react client-side app automatically based on data attributes from the component you rendered server side.

    <%= react_component(component, arguments, options) %>

The downside of this automagic is both of these renderings happen before the point you’d hook up the react-router to your app. Luckily someone has already solved that.

React-Router-Rails to the rescue

Another gem very similar to react-rails has been created by mariopeixoto called react-router-rails. It provides very similar functionality to react-rails, however where react-rails renders a component react-router-rails renders a router.

    <%= react_router(component, arguments, options) %>

Using this you’re soon creating a react app with routing. It’s very cool.

However what nagged at me was how the asset pipeline affected matters. By using this everything had to be shared via global variables. This didn’t feel very natural in the context of React:

    // Not very react
    (function(Components) {
      Components.App = React.createClass({
        render: function () {
          return <ReactRouter.RouteHandler />;
        }
      });
    })(Project.Components);

External libraries also needed to be introduced via global variables rather than the frequently seen CommonJS module system.

This left me at the staring point of a simple React-Router powered Isomorphic JS app, but it didn’t feel quite right. It felt like I had one foot in the present, one in the past (albeit the recent past given the pace of client-side developments :-).

Enter browserify-rails

There are two popular projects bringing the world of node modules to the browser, Browserify and Webpack. Webpack is the one that aims to do a bit more, with the aim of bundling all your JS deps with some cool hot-reload functionality, whereas Browserify is a bit simpler only focussing on node modules.

In the realms of Rails, browserify seemed the more attractive bet. People have done cool integrations with Webpack but that struck me as problematic for server-side rendering.

Like most things Rails, someone has already built it and released the gem. There is browserify-rails out there which will run browserify against your JS as part of the asset pipeline. Instead of using sprockets to require files, it can all be done via CommonJS imports.

Browserify can also run babel (via babelify) over the JS files to transpile both the ES6 and JSX syntaxes.

Using the ES6 syntax does cause an initial problem that browserify-rails doesn’t actually realise it is supposed to transpile the file as it looks for presence of CommonJS ES5 syntax. This can be resolved by including a comment of // require, by configuring the path or by setting everything to transpile.

Bringing them all together

Each of these work pretty good together but bringing them all together produced a few hurdles to overcome.

Firstly it felt a bit weird having some client side dependencies served by gems (react & react-router) and others via NPM. So I felt it was easier to switch those out to NPM and not use the bundled gem ones.

This switch revealed that I had both broken the existing code (by not importing React) and had an environment that wasn’t easy to debug (it doesn’t report which JS file has an error server side). In the heat of this I believed (incorrectly) that problems lay in react-router-rails and how it deviated from keeping up with react-rails.

I decided a safer route was to stick to just using the react-rails and include the changes needed for routing myself via changing the renderer via the react-rails config and introducing a new view helper method (mostly copied from react-router-rails). I’m not sure if I’ve made a great decision here or not, on one hand I’ve killed a dependency, the other I’ve added a concern. Ideally it’d just be easier in react-rails to specify the JS that is used to initialise the app server-side.

Is it any good?

It all works and is cool but does have a couple of issues. The browserify stuff feels a bit fragile, particularly on the server-side. I’ve had a few issues where I’ve felt like restarting the server or clearing cache were required to get the most up to date code executed. I’m too early into this project to know if that’ll be a consistent issue.

Whether Rails is the right tool in a stack like this feels contentious. For the project I’m working on, the freebies you get from the eco-system make it feel like the right choice. But for many projects it’d be smarter to use a node/express setup with webpack. Some of the pains should be eased when Sprockets ES6 comes with Rails 5, but at the pace of change within client-side development it might feel like it’s behind in a different way.

Anyway, now to pick a Flux implementation. That can’t be too hard right?

I’ve found applying mixins to the MV* classes of Backbone can feel a bit verbose and difficult to read. In this post I’m going to explain the approach I have come up with for handling them.

So here’s the out-the-box approach to mixins

    Backbone.Model.extend(MyMixin).extend(MySecondMixin).extend({}, MyStaticMixin).extend({
	// actual extend
    });

By nature of the syntax you’re invited to take a more traditional hierarchical view to class composition through Backbone. What I wanted to achieve is a nicer, easy to read approach to mixins where the mixin intention was clearer.

    Backbone.mixins(
        MyMixin, 
        MySecondMixin
    ).extend({
        // actual object
    });

I wanted to be able to handle static properties too so I thought of two strategies for that. The first is a staticMixins method, the second would be the original mixins method accepting arrays of length 2 to specify prototype and static properties.

    Backbone.mixins(
        MyMixin, 
        MySecondMixin
        [ {}, MyStaticMixin ]
    ).staticMixins(
        AnotherStaticMixin
    ).extend({
        // actual object
    });

To implemented this with the following simple object that could be extended into classes.

Applying this to your classes is done via extending the static properties. I do this on a common super class model.

    var MyCommonModel = Backbone.Model.extend({}, Backbone.Etch.Mixins);

You could even go dirty and patch it onto the Backbone classes

    Backbone.Model.mixins = Backbone.Collection.mixins = Backbone.View.mixins = Backbone.Etch.Mixins.mixins;
    Backbone.Model.staticMixins = Backbone.Collection.staticMixins = Backbone.View.staticMixins = Backbone.Etch.Mixins.staticMixins;

For more complex mixins (e.g. those that define prototype and static properties) I like to define my mixins as functions that return the objects to be mixed in.

    var MyMixin = function() {
        var prototypeProperties = {
            // properties
        };
        var staticProperties = {
            // properties
        };
        return [ prototypeProperties, staticProperties ];
    };

A problem that a mixin approach does cause in JavaScript is overriding messages and calling the super. The advised approach to this in Backbone is to call the prototype of the parent object. This approach only works in a hierarchical system (and even then is a bit flaky) and if we apply that to mixins then they are tied to being a particular order - defeating the opportunity to mix them into classes at will. Also if we’re defining mixins dynamically as functions we do not have a specific object available to access.

To counter this I pass all mixins that are defined as functions an argument of the current object which acts as a super class.. The mixin can then use this super class variable to call the parents methods. Backbone itself defines a __super__ attribute, which references the super class’ prototype. Because this references the prototype it cannot be used for static methods, for these the extend method will need to be overridden.

    var MyCommonModel = Backbone.Model.extend({}, Backbone.Etch.Mixins);

    var MyOddMixin = function(superClass) {
        return {
            set: function(key, value, options) {
                console.log('my odd mixin');
                superClass.prototype.set.call(this, key, value, options);
            }
        }
    };

    var MyModel = MyCommonModel.mixins(
        MyOddMixin,
        function(superClass) {
            return {
                set: function(key, value, options) {
                    console.log('my inline mixin');
                    superClass.prototype.set.call(this, key, value, options);
                }
            };
        }
    ).extend({
        defaults: {
            my_var: false
        },
        set: function(key, value, options) {
            console.log('my model');
            MyModel.__super__.set.call(this, key, value, options);
        }
    });

    var myModel = new MyModel();
    myModel.set('my_var', true);

Running this will change the my_var attribute to true and log ‘my model’, 'my inline mixin’, 'my odd mixin’. Nicely solving the super issue.

If you want you can take the mixins further so that they are generated by a function to specify particular methods/properties.

    var MySpecificMixin = function(propeties) {
        return function(superClass) {
            var mixin = {
                prop1: 'property',
                func1: function() {
                    superClass.func1.call(this);
                },
                prop2: 'property',
                func2: function() {}
            }

            return _.pick(mixin, propeties);
        }
    };

    var MyModel = MyCommonModel.mixins(
        MySpecificMixin([ 'prop1', 'func1' ])
    ).extend({
        // actual object
    });

So I hope this helps inspire you in ways to neaten up your mixins with Backbone. If you have a nicer strategy let me know on twitter @el_kev.