Last week we were working on making our website indexable for search engines. This is the story of rewriting it and the summary of what we have learnt.
Two months ago when we created RisingStack we had to decide what kind of technologies we wanted to use on our website. We only had a few static pages with some event tracking. So it was very simple, but we wanted to keep it scalable and as fast as possible.
Our team is quite experienced in AngularJS so it seemed reasonable to choose Angular on the frontend side.
Please note, that this article is not about why React or AngularJS is better. It always depends on your use case.
The "Angular way"
AngularJS is a pretty cool framework by Google - it provides many great features like routing and two-way data binding to supercharge your development and create testable applications.
It can be a serious problem from a SEO point of view. Especially when you want to make your freshly founded Node.js company well known :)
At RisingStack, we do not like half measures, and we wanted to fix this - this is when prerender.io came into the picture. It is an external service (also an open source project) that renders your site on an external server with a headless browser and sends the result back in HTML.
It makes your site readable for most search engines but also breaks your AngularJS bindings so you cannot use it for real human users.
Because our site uses Koa, the generator based Node.js framework which is not supported by prerender.io, we had to implement it ourself.
So RisingStack released a koa-prerender middleware for Koa.
In a nutshell: it detects the crawlers from the request parameters (
_escaped_fragment_, user-agent etc.), then calls the external prerender service and responds with the static HTML content.
We were happy because our site was finally reachable for most search engines like Google and Yahoo but still not for all. Also the user-agents can change, and we do not want to maintain it. We kept looking for a better solution.
We wanted to have something that renders our content on the server-side at the first load, but provides the experience of the SPA applications after that.
We needed something that can render both on the client and server side and share the application state between the two sides. So the client should continue from the point where the server finished its job.
To implement this kind of architecture the code base has to be common on the server and client side (Browserify/Webpack) and the application also has to be able to render on both sides.
"Browserify lets you require('modules') in the browser by bundling up all of your dependencies." - browserify.org
React provides high performance client and server side rendering with a one-way flow for data binding. ReactJS is open source and built by the Facebook Engineering team.
Because React is not a framework you should extend it with other solutions like the Flux application architecture by Facebook.
"Flux eschews MVC in favor of a unidirectional data flow. When a user interacts with a React view, the view propagates an action through a central dispatcher, to the various stores that hold the application's data and business logic, which updates all of the views that are affected. This works especially well with React's declarative programming style, which allows the store to send updates without specifying how to transition views between states." - Flux docs
The flux architecture, source: http://facebook.github.io/
React + Flux + Koa = isomorphic goodness
After we have decided that we will create our isomorphic application with React and Flux, we started to look for ideas, samples from others.
Finally we started to build our site based on Yahoo's flux-examples.
Their flux-examples provides sample code for two Node.js isomorphic applications with routing and Express.
The main concept behind the isomorphic achitecture is the following:
The application state and code is shared between your browser and the server.
After the server has received the request it creates a new flux-react application instance and renders the view then passes the state of the storages (app) into the rendered HTML output:
<script>var STATE = ...</script>. The server responds with this rendered file.
The browser loads the same code (built with Browserify/Webpack) and bootstraps the application from the shared state. (shared by the server and injected into the global/window scope). This means that our application can continue from the point where the server has finished.
The user gets a fully rendered site at the first load like in the old times, but also able to continue the surfing with a super fast SPA application.
Still, the point of this post is not that React is superior to AngularJS - only that React is better in some cases and vica versa. It always depends on your use-case.
They can also live in symbiosis, a good example for this is the ngReactGrid project.
That's it for now, we are very excited about what will bring the isomorphic era for the web development and Node.js.
If you have something similar, it would be great to hear your story. Ping us on our Twitter channel: @RisingStack
Just published a full isomorphic example:
- Node.js (Koa + MongoDB) API: https://github.com/brewfactory/BrewCore
- React client: https://github.com/brewfactory/BrewUI
- Working demo: https://brewcore-demo.herokuapp.com
Need help in developing your application?