A Better Makefile for Bootstrap
– 04 December 2012– 772 words
tl;dr Bootstrap's Makefile is not so good. So I'm starting to make it better.
A little bit of backstory:
My current side-project is learning how to play Bridge. To help learn about the bidding process, I am making a simple static site web app out of a coffeescript playing card library, BankersBox for client-side storage, and of course Bootstrap for layout and styling. The project is called bridge-trainer.
Since each component has a compile step, I decided to take a
Jekyll-like approach by compiling the overall site into a _site
directory which I then sync to S3 as a hosted bucket.
You can see the github
repo, but the general
setup is an html, js, and css folder with BankersBox, and Bootstrap
living as git submodules
underneath their respective directories.
When I'm ready to test a change, I background emacs with ^Z and
type make
to compile the site into a _site
directory which I can
load locally in my browser. You can see the first version of the
Makefile
which compiled the site.
The Makefile would create the _site
directory, compile the
coffeescript files, run the Bootstrap make file, then copy all the
necessary files into the _site
hierarchy.
Trouble was, Bootstrap would compile from scratch each time I ran
make
. This seemed rather unnecessary as none of the source files for
Bootstrap were changing between site builds.
Here you can see near the top of Bootstrap's Makefile:
Bootstrap's Makefile is being used as a glorified shell script to run
a bunch of commands and not using make's real power: a compilation
asset dependency graph. Also, there is no all
target, so if you
just run a normal make
command, the first target is run by
default. In this case the first target is build
which builds the
docs for Bootstrap. This takes about 2.4 seconds each time.
$ time make build
##################################################
Building Bootstrap...
##################################################
Running JSHint on javascript... Done
Compiling LESS with Recess... Done
Compiling documentation... Done
Compiling and minifying javascript... Done
##################################################
Bootstrap successfully built at 06:17PM.
##################################################
Thanks for using Bootstrap,
<3 @mdo and @fat
real 0m2.480s
user 0m2.299s
sys 0m0.170s
Run the same command immedately afterward, and you get the same thing.
$ time make build
##################################################
Building Bootstrap...
##################################################
Running JSHint on javascript... Done
Compiling LESS with Recess... Done
Compiling documentation... Done
Compiling and minifying javascript... Done
##################################################
Bootstrap successfully built at 06:17PM.
##################################################
Thanks for using Bootstrap,
<3 @mdo and @fat
real 0m2.440s
user 0m2.271s
sys 0m0.172s
Another 2.4 seconds down the drain even though no input sources were changed.
At this point I decided I didn't want to wait 2.4 seconds each time I changed one line of html for my site and recompile to test it in my browser. At first I modified my project's Makefile to deal with Bootstrap's compilation dependencies as can be seen in this commit, but I thought it was a bit silly that I had to worry about that in my Makefile.
So, I did what any insane person would do. I forked Bootstrap.
Here is the updated Bootstrap Makefile using proper make target dependencies:
After running a make clean
to start from scratch, running make
bootstrap
again takes 2.x seconds to compile.
$ time make bootstrap
real 0m2.711s
user 0m2.552s
sys 0m0.168s
But now if you run it again, nothing needs to happen because nothing changed! Voilà!
$ time make bootstrap
make: Nothing to be done for `bootstrap'.
real 0m0.032s
user 0m0.029s
sys 0m0.002s
This allowed me to have a much cleaner Makefile in my project's repo now that Bootstrap was worrying about itself.
Now if I cd back to my repo's root, compiling the site from a fresh start takes ~6 seconds while Bootstrap is compiled and BankersBox is minified by Google's closure compiler.
$ time make site
real 0m6.111s
user 0m2.567s
sys 0m0.236s
However, after I make an edit to one of the repo's files (like my playing card coffeescript) and recompile, it is lightning quick because all of the Bootstrap and BankersBox dependencies are already fulfilled.
$ touch js/coffee/cards.coffee
$ time make site
real 0m0.248s
user 0m0.217s
sys 0m0.030s
Mission accomplished. If I do decide to customize the look of the site by editing Bootstrap's .less files, my project's Makefile will automatically trigger a Bootstrap rebuild (but only the css files!) because of the build dependencies.
make
can be a very powerful tool. It was designed to save
developers' time by not repeating unnecessary compilation steps
between builds of large programs. Use it wisely in your projects, and
you just might save valuable seconds of your fellow developers' lives.
Further discussion on Hacker News.
— Fin.