JS1k: Making a very small game in JavaScript part 1 - tools
Well, that was fun. I’ve just submitted my JS1k Xmas edition demo. I only heard late on when the first JS1K happened, and I wasn’t up to coding anything decent at that stage anyway. So when I heard about this new one, I jumped on the task, working all weekend on it (except when I had to help move a piano). By the end of Sunday it was done, and I was mostly happy with it.
Before I started, I wanted to see if there were any good resources out there for this kind of thing, so I asked on Stack Overflow. I got a few good tips there, but the most useful one was probably:
You need to have the extreme small file size in mind when you write the code. So in part, you need to learn all the tricks yourself.
Show me the code!
Here’s the minified source of my submission. Trying to read minified JavaScript is a bit like reading assembly language when you’re used to C, or bytecode when you’re used to Java, so don’t try to understand it too much. Have a look at the un-minified code to see what it originally looked like.
It’s all up on github as well if you want to see the commit history.
Tools of the trade
I realised early on that I needed to have a quick way of minifying my code and checking its size. I started off playing with the Google Closure Compiler web interface but it was too slow to continually copy-paste my code in there. I downloaded it as a CLI app. Next off, I wrote this Makefile:
default:
java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js kave.js --js_output_file kave-min.js
stat -c%s kave-min.js
The first line uses Closure to compile with advanced optimisations, and the second outputs the size of the minified file. With this, all I had to do was type make
to see what the minified filesize would be. Being able to do this after every tiny optimisation was extremely useful, as I could quickly experiment with new techniques and see if they were worthwhile.
Learning the tools
It’s important to understand what the compiler is actually doing, and what it’s able to do. Reading through the Advance Topics in the Closure docs was essential. Closure will do some pretty advanced optimisations, but it needs help. For example, it doesn’t touch strings (thankfully). That means if you refer to a method in one place as obj.meth
and in another as obj['meth']
, it can’t rename obj.meth
.
Another big no-no is with
, which is good, because it just confuses things anyway. Using with
means Closure can’t distinguish between properties and local variables, so there are a lot of name shortenings it just can’t do.
In Part 2, I’ll look at some of the specific optimisations that I used.