Universal React Rendering: How We Rebuilt SitePoint

Universal React Rendering: How We Rebuilt SitePoint

SitePoint has a lot of great content and it’s not just articles, so when we recently redesigned the SitePoint home page one of the goals was to do a better job of showing off other content like books, courses and videos from SitePoint Premium, and discussions from our forums. That posed a challenge as it meant pulling data from multiple sources outside of our main WordPress app.

In our development team, we really enjoy using React. The component model, and the pattern of having “data stores” in JavaScript work really well for us and we find it results in a code base we enjoy working on.

We wanted to use these familiar tools but it was not going to be acceptable to send a mostly-empty homepage to users and then have them wait for all the different data sources to load and then render. So we knew what we wanted: our WordPress site to serve server rendered content written in React. It would also be great if users could enjoy our site without being required to have JavaScript enabled, or should something cause our JavaScript to break.

Universal React Rendering and PHP

WordPress is PHP, React is JavaScript so how do we do both server-side? Our solution was to create a Node.js proxy server. All requests come into this Node server and are passed straight on to our WordPress site. The proxy then inspects the returned page and does the React rendering before sending it on to the browser. The result is less a case of a full server side app and more a case of basic pages from WordPress with a series of components that can be rendered/upgraded via JavaScript on the client or server.

While that idea sounds simple enough and we found plenty of examples of rendering full pages via React we found relatively few on how to upgrade an existing response. The tools we chose for this were:

  • node-http-proxy, a full-featured HTTP proxy for Node.js
  • and Harmon, middleware for node-http-proxy to modify the remote website response with trumpet

The best way to describe this process is with an example. Here’s a simple demo app. If you visit the /_src URL you can see the full source code, or check out the GitHub repo.

  • server/target.js is a very simple HTTP server that always returns the same basic HTML
  • server/proxy.jsimplements node-http-proxy forwarding all requests to the target server
  • server/basicHarmon.js provides an express middleware using Harmon to rewrite any <header></header> tags with some new, fancier content
  • server/express.js creates the express server that uses the proxy and Harmon middleware

When you visit the app you should see the result you are served has the fancy header.

At this stage, we only have a trivial example of replacing text in a header tag, but in the following sections I will show how this same approach can be used to render our React components. This approach gives us great flexibility. The Node.js app needs no knowledge of how WordPress works. It could just as easily be applied in front of a Rails app or anything else.

Components on SitePoint.com

As I mentioned we really enjoy working with React and the way we already use it on SitePoint stood us in good stead for the move to the server side.

If you have used React before then the following code block should look familiar.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello React!</title>
    <script src="build/react.js"></script>
    <script src="build/react-dom.js"></script>
    <script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">
      ReactDOM.render(
        <h1>Hello, world!</h1>,
        document.getElementById('example')
      );
    </script>
  </body>
</html>

This comes straight from the React getting started page and shows how to render a single component into a page. What I see less often in examples is the use of multiple components in a page. Your site does not need to be a full single page app in order to use multiple components. You are free to add multiple React mounting points and we think it’s a great pattern that shouldn’t be discounted. Here’s a trivial example:

On SitePoint.com we use custom tags rather than element IDs and because it’s a pattern we use over and over again we have some helper functions to do that for us. First, we have the render() function that registers the custom tag with the browser and then locates all instances of that tag in the document.

function render (tag, Comp) {
  document.createElement(tag);

  const nodes = Array.from(document.getElementsByTagName(tag));
  nodes.map((node, i) => renderNode(tag, Comp, node, i));

  return Comp;
}

Second, we have renderNode() which performs the actual React render for each node after converting the nodes attributes to a props object.

Continue reading %Universal React Rendering: How We Rebuilt SitePoint%