PIcking Your Javascript Mobile Framework: Part 4 - Coding
One of the differences between mobile development for sites and for browserified apps is that you don’t have to download the supporting files every time you start. That’s because they are typically packaged with the app and are right there with it on the device.
That’s a huge difference with respect to looking up mobile sites, because there every byte you can squeeze out is a byte you don’t have to download. While that’s not that important on WiFi or on 4G, it makes all the difference on 3G or heavens forbid 2G.
On the phone, tucked away in a neat little folder, you suddenly don’t care if the library is 50KB or 500KB. All you care about is how quickly the thing loads, and how long it takes to go from screen to screen.
That kills pretty much any comparison ever made online. They care about every single bit squeezed out the download, and will prefer a small library that does less if it means being able to download it less frequently.
On the other hand, the coder (you and me) has different priorities. We want something that is easy to write, concise, and does a lot of the grunt work for us. After all, if we write twice as much code, it’s not just that it takes twice the amount of time: it gives us twice the chances to make a dumb mistake.
So the first thing I wanted to look at is the total actual code size. That’s the code the developers of the Todo apps had to write, versus the total amount of code of the app. As we’ll see, that’s a much more important criterion than download size.
To figure that out, I had to go into each directory (of those remaining), remove all library code, all supporting files (like the READMEs) and remove from the remaining code all non-essential comments. Note here: some compilers use the comments as directives, in which case the comments cannot be removed.
Mind you: it’s absolutely not that I don’t think comments are essential. They are. But when you are comparing the amount of code you need to write, I cannot allow someone’s code to be penalized because it’s long on comments.
Below the table, as you are already used. Rank indicates total file size, regardless of number of files. If there is no rank, there are comments and the framework has been dropped.
Name | Rank | Comments |
---|---|---|
agilityjs | 13 | |
ampersand | 39 | |
angularjs | 32 | |
angularjs-perf | 6 | |
angularjs_require | 8 | |
backbone | 33 | |
backbone_marionette | 31 | (11823 bytes) |
backbone_marionette_require | 24 | |
backbone_require | 28 | |
batman | 2 | |
canjs | 3 | |
canjs_require | 4 | |
closure | 44 | (30725 bytes) |
durandal | 37 | |
emberjs | 15 | |
enyo_backbone | 40 | |
epitome | 38 | |
exoskeleton | 30 | |
firebase-angular | 10 | |
flight | 41 | (18304 bytes) |
gwt | probably on its way out, considering that Google is pushing Dart | |
jquery | 12 | |
kendo | the absolutely only for-pay framework in this test | |
knockback | 11 | (7517 bytes) |
knockoutjs | 7 | |
knockoutjs_require | 14 | |
lavaca_require | 42 | |
maria | 34 | |
mithril | 9 | |
mozart | the javascript app.js is a giant mess | |
plastronjs | came out with the largest directory; turns out it’s because there is a huge compiled file in there; not sure that’s exactly what i want | |
puremvc | it’s pretty reactive, but it’s also tons of code | |
ractive | 23 | |
rappidjs | 21 | (9398 bytes) |
react | 35 | |
react-backbone | 36 | |
sammyjs | 29 | |
sapui5 | has an external dependency on an enormous file that cannot be downloaded | |
serenadejs | 19 | |
somajs | 22 | |
somajs_require | 25 | |
spine | 5 | |
stapes | 16 | |
stapes_require | 18 | |
thorax | 26 | |
thorax_lumbar | 20 | |
troopjs_require | 27 | |
typescript-angular | another one that manages to be too big for its good | |
vanillajs | 43 | |
vue | 1 | (4917 bytes) |
yui | *yahoo-*ui has sadly stopped active development |
As you notice from the results, the code base varies from a minuscule 4,917 bytes to a relatively gargantuan 30,725. That’s more than six times the code to do exactly the same thing!
Here is a graph of how the different frameworks stack up:
As you see, there is a fairly gradual increase, until things start getting out of hand toward the tail end.
Now the important questions:
1. Is the small size of the smallest footprints real?
In short: yes. Vue, in particular, our absolute winner, has amazingly short and amazingly readable code. It’s a real miracle.
Some of the frameworks use precompilers to make things both more readable and shorter. One is the amazing CoffeeScript, which takes Python/Ruby ideas of scripting and puts them into Javascript. As you may know, Javascript is derived from Java, which in turn was competing with C++, which in turn is derived from C. C is in turn almost as old as me – time to go!
C derived languages need a lot of hand-holding. Statements have to be terminated with a semi-colon, lists are understood by their index, and all sorts of processor shenanigans (like the need for a break in switch statements) became part of the standard.
Modern languages (and I won’t count Javascript as one) don’t need any of that. CoffeeScript doesn’t, either – but it can be “compiled” to Javascript. That is, you write your code in CoffeeScript, then you tell the CoffeeScript compiler to do its magic, and you get Javascript that you can include in the browser.
(React, incidentally, uses Facebook’s own JSX. Not quite sure what good that does, considering that their code ended up towards the upper end of the chart.)
2. Does smaller size means It runs faster?
No, because all the todo apps in this list (except for Vanilla Javascript) have frameworks attached to them. These frameworks need to be loaded and introduce complexity that can slow down any application.
There is no such thing as a good framework or a bad framework. Each one is designed for some use case and will optimize its performance in that case, but miss the mark in other cases. Mithril, for instance comes out the smallest of all the examples when you include the dependencies, but is only number 9 in shortest code size. The discrepancy is explained by the fact the author tried to make sure the framework itself was small. As we saw, that matters a whole lot more when you have to download the file every time you look at a page that needs it.
The Mithril homepage lists a series of benchmarks to compare this framework to competitors (and unsurprisingly comes out on top by a mile). Frankly, I would agree with him that his code is ideal, if it weren’t for the templates. But more about that later.
One of the smallest examples, too, was the sapui5 one. The problem with that was that it relied on a gargantuan (500k) include file that could not be downloaded. Every time you look at a page with sapui5, it appears, you have to download that file.
3. Do these frameworks force me to do things a specific way?
Yes and no. Ultimately, it is up to you how much of their functionality you use – sort of. If you want to make your life easier, you’ll structure things the way the frameworks like them and use the conventions they choose.
In general that’s not a problem. There is one giant exception though: the views.
Views, as mentioned, are the things the user sees. Buttons, boxes, labels, inputs. So, since this is a browser-based app, it’s all HTML. The model and controllers live in the HTML, too – but as script tags that reference external scripts.
The issue with the views is that you somehow have to tell them to show or hide, have to tell them what they should do if a user presses, and what content they should display. Every framework handles that differently, but there are three main categories:
- Frameworks that use annotated HTML. Here is an example for Vue:
<div class=”view”>
<input class=”toggle” type=”checkbox” v-model=”completed”>
<label v-text=”title” v-on=”dblclick: editTodo(this)”></label>
<button class=”destroy” v-on=”click: removeTodo(this)”></button>
</div>
As you see, you can read it perfectly well if you have written HTML. There is a div element with three nested elements. A checkbox (input of type checkbox), a label (which is not really an HTML thing, but I guess most HTML developers would know what that’s for), and a button. - Frameworks that use templating engines, like Handlebars. Here the HTML is a little harder to read, because it has markers and directive that don’t look anything like it:
<div class=”view”>
<input class=”toggle” type=”checkbox” {{#if completed}}checked{{/if}}>
<label>{{title}}</label>
<button class=”destroy”></button>
</div>
This example is from the default jQuery implementation that (surprisingly) came in towards the top of the list. Notice how the HTML contains instructions like {{#if completed}}. What happens here is that the preprocessor (Handlebars, in this case) gets fed with the template and the model, and fills things in according to the instructions. Handlebars runs as a Javascript library in your browser, so there is nothing to install. - Frameworks that program the HTML. That’s for instance the case for Mithril. If you go to the index.html file looking for the div we looked at above, you’ll find absolutely nothing. In fact, the entire todo app is missing from the index file, except for a single section element. We’ll find our div, of course, buried in the code, along with all the other Javascript code.
Each approach has its advantages and drawbacks. Each approach can also be combined with the others when convenient.
Personally, I am most inclined to go the route of the first approach. The main reason is that I get to have my view in an HTML file and attach behaviors to a static object.
The templating approach has its advantages, in that you can do things easily that are hard to do in the DOM tree, because the templating engine is meant to deal with complex states and state changes. The downside is that you find yourself learning a new language, however limited it might be, and you expose yourself to its bugs.
The programming approach leaves the HTML developer out in the cold, so it’s not surprising that web developers are not all too fond of it. The advantage, though, is that it’s phenomenally quick. It turns out the bottleneck of much HTML display is the constant need to update the DOM tree, which is very expensive, because it requires lots of redraws of the page. You can see that in action when you load an image-heavy page on a slow server: whenever a new image is fully loaded, the whole page adjusts to it in a disjointed way.
When programming the DOM tree, the browser doesn’t know there is going to be a change to react to until the programmer says so. This gives you the option to update the entire application first, and then tell the browser to display only the finished result.
Next, we’ll look at performance.