How to get smaller

2016-02-22

This month I'd like to explain some examples of how the code I write ends up being small in production. There are various code quality metrics related to the lines of code per file, or even per function. And while everyone agrees that a 50k loc file containing your core logic is generally a bad smell, minifiers will love it and it's a great middle step while creating your production build. So how do you get there? That... depends.

Note: A client of mine asked me to write blog posts for them. This is the first one. You can find the original post on their website, linden-it.com. You can find a copy below for posterity (was added here at least a month later).

No really, it depends. It depends on your project. It depends on your team members. It depends on deliverable requirements.

For example, I’ve written a JavaScript parser that consists of two classes, each its own file. One class uses the other class and only a single function is exposed for the whole project as a module. The project uses a strict style guide where using any method on that inner class happens with a specific variable name. This way the tooling can recognize that if `foo.bar()` is being called, this `foo` was in fact my other class and not some random core JavaScript API. Next it processes the file with a parser. It renames the object structure (`Foo.prototype = { ... }`) and eliminates that object wrapper. It renames all the keys of this object to some prefix and replaces the colon with an assignment. Finally it puts a semi-colon at the end of each declaration. To illustrate: `Foo.prototype = { a: function(){..}, b: 15 };` becomes `foo_a = function(){ ... }; foo_b = 15;`.

Since I'm using a strict style guide I can replace all the usages of that class in the other file by simply looking for `foo.*`. With a parser I can make sure I'm looking at variables and not a piece of comment or unrelated code. When I find it, I'll rename `foo.bar()` to `foo_bar()`. Likewise for all the `this.bar()` inside the class self I'll rename it to `foo_bar()`. This way all the occurrences of the methods and properties of the class get renamed to local function/variables. We do this for the other class too, which only has to concern itself with `this.xxx()` since it's not used anywhere else.

This process leaves me with two ugly files with only local functions and variables, everything namespaced. I concatenate them, put it all in the same scope, and hand it off to a minifier. There are some special cases that make sure stuff is properly exported and state is dealt with and that's that; performance increase as well as a much smaller size than I'd get when minifying prototype based structures.

Another example is a project that heavily uses modules and was relying on a project called “browserify” to create a neat package. Don't get me wrong, browserify sure has its place, but to me the results are excruciating to look at. The ideal situation for a minifier would be everything in the same scope as local functions and variables. So to do this move all the imports to the top of the file, where they ought to be. Any exports are grouped together at the bottom of a file. Add some markers in comments to recognize the core of each file. A simple regex script to cut them out and put them all together in a big giant scope and then hand it off to a minifier.

The key here is again a strict style guide and in particular a naming convention where you name (module) local vars and functions quite explicitly and export them in the same way. So you'd end up with something like `helper.js` containing `function helper_makeNice(){}` and later exporting `module.exports = {helper_makeNice: helper_makeNice};`. You import it the same way; `helper_makeNice = require('./helper').helper_makeNice;`. Everything in the code will just use `helper_makeNice` so the code will still work when you cut away the imports and exports and put everything in the same scope.

Again, this won't work for every project. Some are better suited than others. Some team members can handle java-esque naming conventions better than others. But if the requirements are small, you can go small.

I'm Peter and I do JS1k. It's a JavaScript golfing competition where you have to create a complete JavaScript application in 1024 bytes. This years competition started in February and runs till mid may. Next time I'll try to get deeper into how to build a JS1k demo. But in the mean time you should give it a shot yourself. You may not win but you’ll have fun building a demo. And that is fine too.