Isomorphic Javascript - newgeekorder/TechWiki GitHub Wiki

React.js, Lazo.js and Rendr

So you want to work isomorphism into your web development? While there’s a wide variety of libraries and frameworks that allow developers to use isomorphism in JavaScript, some of the most popular choices are React.js, Lazo.js and Rendr. A quick comparison of these libraries follows.

Rendr

Rendr is a library developed at AirBnb to address slow first-page load. It was designed to utilize Backbone.js architecture on the server. Rendr also works with Express.js. If we explore a Rendr all closely, you’ll see that the routes are set up akin to those in Backbone.js:

module.exports = function(match) {
    match('',                   'home#index');
    match('repos',              'repos#index');
    match('repos/:owner/:name', 'repos#show');
    match('users',              'users#index');
    match('users/:login',       'users#show');
};
The Rendr app will have it’s own instance of Express.js which we mount to the main server with:
var server = rendr.createServer({
    dataAdapterConfig: dataAdapterConfig  // Some configurations
});
//...
app.use('/', server.expressApp); // Mount Rendr app to the main app

More Rendr examples are available at https://github.com/rendrjs/rendr-examples. There are quite a few similar projects that utilize the Backbone library to write code that can run on the server or design components to be shared between both the client and server. Some of these projects can be found here: backbone-serverside and previewcod.

Lazo.js

Lazo is similar to Rendr in that it utilizes Backbone.js. In addition, it leverages RequireJS and jQuery front-end JavaScript libraries. Lazo routes are stored in JSON file:

{
    "routes": {
        "":             { "component": "todos-single" },
        "multiple(/)":  { "component": "todos-multiple" },
        "single(/)":    { "component": "todos-single" },
        "layout(/)":    { "component": "main", "layout": "todos-layout" },
        "header(/)":    { "component": "header" },
        "main(/)":      { "component": "main" },
        "footer(/)":    { "component": "footer" },
        "hello(/)":     { "component": "hello", "layout": "todos-layout" }
    },
    "css": ["/app/client/base.css"]
}

The modules are defined in RequireJS style:

define(['lazoBundle'], function (LazoBundle) {...})

React.js

React.js isn’t a model-view controller (MVC) framework; it just has the view layer of a MVC. This means it can be used with most of other libraries front-end libraries such as Backbone.js. React.js is often used with the JSX language, which is a mix of JavaScript and XML/HTML. In this scenario, the JSX code is compiled into the native JavaScript before execution in the browser. The major advantage of using React.js over other libraries is that is uses virtual DOM for rendering, meaning only the delta of changes will be rendered on the page, leaving the unchanged elements intact. Here’s an example of React’s front-end code:

var Header = React.createClass({
    render: function(){
        return (<h1>Message Board</h1>)
    }
})
//...

The brilliance of React is that there are no templates — all HTML elements are rendered from JavaScript code. The XML-like syntax is just sugar coating and because the functionality is split between JS and HTML, this approach helps prevent constant jumping from JS to HTML to JS to HTML and so forth. When it compiles to isomorphism, React is effortlessly rendered on the server, enabling the faster first-page load we discussed earlier, while the later interactions are enabled by the browser React. Let’s take a look at the same component Header rendered on a server built with Express.js. The public/js/app.js is the browser file with React components, which we’ll re-use on the server:c

var React = require('react/addons'),
    components = require('./public/js/app.js'),
    Header = React.createFactory(components.Header)
    //...
    app.get('/', function(req, res, next) {
        req.messages.find({}, {sort: {_id: -1}}).toArray(function(err, docs){
            if (err) return next(err)
            res.render('index', {
                header: React.renderToString(Header()),  props: '<script type="text/javascript">var messages='+JSON.stringify(docs)+'</script>'
            })   
        })
    }

The data passed in the props will be exposed on the client/browser. The server-side template for the view (Handlebars template engine) look like this:

{{{props}}}
<div id="header">
    {{{header}}}
</div>

Once the client React code gets its data from a datastore (Reflux, jQuery, Backbone, etc.), it will check the checksums on the server-rendered elements. They will match, because the data is the same, and there would be no unnecessary re-rendering to slow page times. The first time this page loads will be super fast since the rendering happened on the server with later partial DOM updates happen on the browser. As SPAs became more widespread, the need for a single client/se code base to support SEO, non-JavaScript clients, better UX, and fast first page load grew larger. In a nutshell, isomorphic JavaScript is the answer to this web development problem.

The isomorphic approach solves these issues by using one set of code (usually JavaScript/Node.js) that renders both on the back end and the front-end, allowing for better maintainability, indexing by search engines, and user experience. While a contentious term, the utility of the concept is solid. Node.js/Io.js made isomorphic development easier and more accessible, allowing it to grow in popularity and expand into multiple frameworks. JavaScript is already the ONE LANGUAGE to rule them all — if by “them all” you mean every layer of the web tech stack from browser to server to database. What if isomorphic JavaScript represents the next evolution of web development, stripping away the complexity of keeping track of a thousand moving bits of code? What if all those abbreviations that crowd web developer resumes — HTML, CSS, HTTP, SQL, RoR, J2EE, PHP — could be replaced with a single beautiful isomorphic approach to JavaScript? Wouldn’t that be universally great?

⚠️ **GitHub.com Fallback** ⚠️