Isomorphism or how to handle complex webapps development with both front & server rendering?
A brief web app history
Under the dinosaurs area (I mean a long time ago, before 2010), Web used to belong to the server (I will not speak about flash). Front-end development was not a job, all app logic was handled by the server in a server specific language (php, C#, java…). JavaScript was just here to bring some sugar to the pages, with the help of jQuery (slideshows etc.).
No problems then, but not a very friendly environment for webapps, constant page reloading, poor UI interactivity and reactivity, heavy bandwidth usage etc.
And here came the JavaScript MVC frameworks (AngularJS, Backbone, Amber…), revolution!
Goodbye server side rendering and hello single page applications! No more page reloading, more reactive and complex interface… But all that goodness came with one painful cost: Initial page is just blank.
- Longer perceived loading time (with the Flash Of Unstyled Content, aka FOUC). Obviously all JavaScript has to be loaded before rendering start.
- Poor SEO. Despite of the enhancement of Google crawler JavaScript interpretation, single page application SEO is still very poor and uncertain.
So we fall into a hybrid approach almost every times: serve a fully or partially rendered page to the client and then take over with complex JavaScript.
Every developer who did that know how the Hell it is to build and to maintain. Many pieces of code (string formatting, templates…) have to be written on the server (in php, java, C#…) and on the client (JavaScript). You inevitably ends up with errors.
Here came NodeJS
With the revolution (once again) of NodeJs, a magic thing occurs: we can execute JavaScript code on the server. Yes, the same exact language which is executed by browsers.
Imagine you could, on the server, get your front JavaScript code, write something like “App.render()”, exactly the same way you do it on the client, and end up with a fully rendered page?
That what is Isomorphism, the JavaScript application of the old well known java paradigm “Write once run everywhere”. You write your logic one time in JavaScript, render it to string on the server, send it to the client and then execute the same application on the client.
Practice over theory
Look simple and obvious, but an issue quickly rise, the DOM.
Indeed, many popular JavaScript libraries heavily depend upon the DOM, which do not exist in server environment. Frameworks like AngularJS or jQuery are not environment agnostic, they depend upon the DOM and thus can be rendered only in a browser.
That’s why a new kind of view framework appear: ReactJS-like frameworks.
These frameworks abstract the DOM, so every piece of the app can be renderer to string.
Another gap is still there (at least for a NodeJS driven app). The language is the same, but there are still differences between the NodeJs dependencies management, driven by npm and require([modulename]) and front end, driven by bower and import statements.
Here come some nice tools to our rescue: Babel, Webpack and Browserify. These tools mimic the NodeJs dependencies management for the browser. They pack all your app into a single file, browser compliant application.
Grasp the ideal architecture
There is some all-in-one frameworks for building Isomorphic applications, like Meteor, but I will present a more tunable and handcrafted architecture.
For example I set up a little git project implementing these features :
- Server-side rendering
- Standard rendering server (for performances comparison)
- Standalone rest server (API)
- App working on browser without javascript (try is by disabling js in the dev console)
The view
The ideal is to have a standalone NodeJs server, the entry point of the app. It would be handling first user request, rendering template (Written with a framework like ReactJs) and serving rendered pages and packed app files (with the help of Webpack) to the client. No data here, just views!
It is a good practice to ensure that the app runs well without javascript, it’s tricky but it brings reliability to the app.
The data
We would develop an API only server, with whatever language you want. This server will handle all application logic and data. As the server is only handling json or XML and no html it can be more performant than classic full stack framework (no heavy rendering libraries like twig or Razor, lighter dataflow).
Upload / Content / Images etc …
Uploads (images, files) would be stored on a specific server, like amazon service or similar.
Conclusion
Yes, isomorphism is not an easy thing to setup, but it is worth it, it brings to the user a huge enhancement in reliability and performance, and to the developer an easy way to maintain app.
Moreover isomorphic architecture presents some very good side effects: a complete separation of concern. You have independent tiles doing only one task at a time. So very maintainable, easily expandable (imagine you want to add a mobile app tile, you already have a working Api and uploads management).
With the arrival of Angular V2 (which is not as coupled on the DOM as V1), the acceleration of NodeJs development and new ES2015 browser and server capacities, isomorphic JavaScript should evolve more quickly and should be more and more used in a near future !
Sources and resources: