How to Load Your React Application Twice as Fast With Isomorphic Application

How to improve the speed of a React application?

React is an incredible framework. You may have already learnt it from another post. However, it is a client-side framework and as such, it has a few drawbacks:

  • search bots do not see the page content *
  • a user with disabled javascript cannot see the page

OK, these are not the first things you are worried about when you create a website. The main drawback of such frameworks is the initial page load. According to an Akamai report, 25% of Internet connections are below 4Mbps.

For these 25% connections, a typical connection flow for a medium React
application (bundle of 1MB) is the following:

It takes 2 seconds for the user to see your application!

What is an Isomorphic application and why does it speed up my React application?

An isomorphic application is an application that shares the same codebase on the server side and on the client side. By sharing the same codebase, it is possible to render a page on the server side and send directly the result to the client. This result in the following flow:

Now the users will fetch the first page twice faster, your website will have a greatly enhanced Search Engine Optimisation (SEO), and people that sadly don’t have javascript will be able to admire your application.

If you are not convinced yet by isomorphic applications, you will be in a few lines. As there is only one common codebase, the code is easier to maintain and to test. Finally, you have a common state between the client and the server which makes it easier to debug your application.

How does it work?

Until now, isomorphic applications consisted in rendering the html code in a headless browser on the server such as PhantomJS. However, React is different from other Single-Page Application (SPA) frameworks thanks to its virtual DOM, an in-memory DOM decreasing the number of costly DOM modifications. With its virtual DOM, React does not need a headless browser to render a page and it is now possible to do it anywhere Javascript can be run. And this can be done on the server side thanks to the v8 engine and the various libraries to bind the engine to a specific language.

I want to do it, what should I do?

Creating an Isomorphic React application is actually simple. In order to integrate your React application into a PHP server, you will need to install v8js which embeds the v8 engine in PHP. Here are instructions to install it on Mac, Linux, and Windows.

The React team has created react-php-v8js which is dedicated to rendering React components in PHP. Let’s start a new project and use this package:

mkdir isomorphic-react && cd $_
composer require reactjs/react-php-v8js

To create our compiling pipeline, create a package.json file with the
following:

{
  "name": "php-and-react",
  "version": "0.1.0",
  "scripts": {
    "make": "npm run make-dev && npm run make-min && npm run make-table",
    "make-dev": "browserify -t [ envify --NODE_ENV development ] src/react-bundle.js > build/react-bundle.js",
    "make-min": "browserify -t [ envify --NODE_ENV production ] src/react-bundle.js | uglifyjs > build/react-bundle.min.js",
    "make-table": "babel --presets react src/app.js > build/app.js"
  },
    "dependencies": {
    "babel-cli": "^6.3.17",
    "babel-preset-react": "^6.3.13",
    "browserify": "^12.0.1",
    "envify": "^3.4.0",
    "react": "^0.14.5",
    "react-dom": "^0.14.5",
    "uglifyjs": "^2.4.10"
  }
}

Then to install the dependencies, run:

npm install

In the src folder, let’s create a react-bundle.js file which will load all the libraries.

// These dependencies will be compiled by browserify afterwards.
global.React = require('react');
global.ReactDOM = require('react-dom');
global.ReactDOMServer = require('react-dom/server');

We can then create a very simple React component in app.js:

var App = React.createClass({
  render() {
    return (
      <p>
        The server time is {this.props.time}.
      </p>
    );
  }
});

Finally, let’s build our PHP server.

<?php

// Load the dependencies
require_once('vendor/autoload.php');

// Create the ReactJS object
$rjs = new ReactJS(
  // location of React's code
  file_get_contents('build/react-bundle.js'),
  // application code
  file_get_contents('build/app.js')
);

// Data that will be handed over to the component
$props = [
  "time" => date("H:i:s")
];

// Set the current component to render
$rjs->setComponent('App', $props);

?>

<html>
  <head>
    <title>React from PHP</title>
  </head>
  <body>
    <!-- Insert the rendered content here -->
    <div id="app"><?php echo $rjs->getMarkup(); ?></div>

    <!-- load react and app code -->
    <script src="build/react-bundle.min.js"></script>
    <script src="build/app.js"></script>

    <!-- client-side render -->
    <script>
      <?php echo $rjs->getJS('#app', "GLOB"); ?>
    </script>
  </body>
</html>

The last lines of code, echo $rjs->getJS('#app', "GLOB"), loads the scripts and executes a client-side rendering. This way, the initial load uses the fast server-side rendering and the subsequent calls use the (already loaded) framework router.

Run php -S localhost:5678 and voilà! A PHP server is now running, rendering the view in the backend.

Caveats

Server side rendering is not as simple (for the server) as serving static files. If your server is too slow, the rendering can take more time than serving the files to the client, hence loosing one of the advantage of isomorphic applications. You may want to consider this point before switching your application to isomorphic.

* This is not so much true anymore as Google bots runs the Javascript code and
API calls to fully render the page. This is not a guaranteed result however, nor the case of every spider bot (Facebook, Twitter, Yahoo, Bing, etc).