Alex Ponomarev

Javascript web development notes and experiments

From Rails to Express.js

Rails and server-side rendering

Ruby on Rails is a web application framework developed by David Heinemeier Hansson, with the version 1.0 released back in 2005. It caught up hype quite fast and by now is kind of industry standard for rapid web development and prototyping, and there are also lots of production apps and companies using it right now. In a typical web app in 2005 server was receiving a request from a browser, like 'Show me page X' or 'Show me page X and sort table by Y', and responded with HTML of that page, that in turn was displayed to the user. Javascript was used primarily for decoration — to show lovely popups, add some interactivity to the forms, but nothing serious.

Rise of Javascript

Over time, Javascript got more power, especially after release of JQuery and AJAX in 2006. BTW, JQuery was inspired by Prototype, that was bundled with Rails 1.0 (see this nice annotated source of original JQuery if you're interested). Things started to change, web pages became more and more interactive and more and more logic was moved into the browser — in ten years most of the web servers were no longer serving full HTML pages, but instead they were serving data. In modern web app Javscript app in a browser is asking only for data — 'Give me a list of items for a PAGE X', it is responsible for displaying and manipulating this data, e.g. sorting, and only tells server about changes — 'Save item X, here is a new value'.

The Javascript ecosystem

This transition from server-side view rendering to client-side Javascript rendering allowed us to develop very rich, interactive and fast web apps. Moreover, in 2009 Node.js was released, that allowed to create server-side apps also in javascript. A whole new layer has been added to web stack, with its own set of tools, frameworks and workflows. For example we can't write our javascript app in one huge file — we need to create lots of small separate files called modules, that dependent on each other. Then we need a way to create one big Javscript file from them and make sure that all necessary modules are included — this is called bundling. This is why we need a bundler, such as Webpack of Browserify. Additional benefit of a bundler is that it allows developer reuse existing modules created by others via NPM. There are also things like transpilers, e.g. Babel that converts Javascript files from one dialect to another.

MVC - is a Model-View-Controller

Theese are three separate layers in modern web application. Model is responsible for data modeling, interaction with database and validation. View is responsible for data presentation in various formats, such as HTML. Controller is merely a mediator between view and Model — it interacts with data models based or request from the client and presents them using different views. In modern web apps View layer on server is limited to presentation of data in special text-based format — JSON, whereas all rendering is done on a client via client-side javascript app.

V in the MVC is becoming too big

Rails was created to serve the needs of classic, server-rendered apps, but in recent years V in the MVC pattern got life on its own — simple rendering of HAML template with some coffeescript bound to the page load is simply not sufficient. Moreover, there's a whole new set of libraries and tools to manage them, which are not too well integrated into Rails workflow. For me the tipping poing was when browserify-rails gem was used to package all my React components for the Rails asset pipleine just refused to do so with a sublte, unknow error. I also remember how much time was spent a year ago to make require.js work with a decent Marionette app in Rails project.

The tipping point

After spending about 10 hours trying to make browserify-rails to work I decided to extract client-side app completely and use webpack to bundle all my javascript, that can then be included into rails asset pipleine. Client-side app now lives in a separate folder, with separate tests, modules are managed with npm and all plays nice and well. Which leaves makes me think if I really need Rails this much — basically after bundling of CSS is also moved to Webpack (and I'll do so as soon as I'll have time) I will be using Rails only as a simple API server with VERY simple controllers, RABL templates and ActiveRecord for data modeling. Of course there are also migrations, RSpec, initializers and environments, but it is still less than 50% of the initial value Rails provides — I don't use views and all their neat helpers, I don't use form builders, flash, etc, all this is done manually in the client side.

Express.js — not bad

At a first glance Express.js 4.x combined with power of additional NPM modules can be as good as Rails theese days, so I'm going to try it out. In fact, I already did — this blog was created with Express + Mongoose, a typical stack for an Express project. Express.js is a minimalistic web framework based on Node.js, that allows to create simple API's as well as big complex apps. Mongoose is a Object-Document mapper for a MongoDB database with a very well written API. Of couser, I am already missing ActiveRecord and nice config files Rails have, but writing backend in Javascript, especially in ES6 (thanks babel) is also very nice. There are still things to figure out, such as how to make Webpack work with CSS and how to integrate it's deve server in Express development workflow, how to do simple things like image uploading and user auth, but theese are one-time tasks that you figure out once and use forever so invested time should definately pay off.

Future plans

So, as a conclusion — I'm trying to move from Rails to Express and I'm going to write about it, and transition was quite smooth so far. We'll see how things will go when more complex features will have to be implemented. I am also going to see how React and Flux plays with javascript backend — isomorphism AKA server-side rendering looks very interesting. And of course, there's a ton of things to explore in the client-side — Flexbox, PostCSS, various Flux implementations, Inline css in react, functional js, Immutable.js and many more