Makefile to automate things

with front-end development, testing and deployment

Lost in Space
@tomchentw/software

--

We’ve been struggling to find a desirable task management system for our projects. For ruby, we have rake, and it does things right. But there’s no luck for nodejs due to it’s async nature.

The nodejs community comes up with jake. Then we have a front-end specific friend show up : gruntjs. Until now it’s plugins are not only specific to front-end tools. But it got pitfalls that grunt tasks still run sequentially instead of concurrently, which wastes the best feature of nodejs. Furthermore, creating tasks using verbose configuration is counter-intuitive and confusing, though its declarative config was meant to reduce the entry level for non-programmers.

Suddenly, gulpjs shows up. It uses newly introduced streaming API from nodejs 0.8, providing maximum concurrency for your application. Consumers write codes instead of configs make it more natural to use existing node modules to hook your application up (instead of creating a new gulp plugin.)

But sometimes we might have scenarios that doesn’t really “fit” the nodejs world. For example, you might want to get the last commit from current git history, and use it to create a new commit message for releasing a new version. The workflow described above is simple, but implementing it in nodejs is so painful: there’s a callback hell and the code itself isn’t easy to maintain. It’s hard to extract the logic into a new library/plugin and still make it generic enough for different use cases.

However, these problems can be easily addressed with a few shell commands in the terminal. Although you need to sacrifice portability if someone in your team uses Windows. If we choose the commands wisely, they could provide consistent interfaces across platforms, and they’re just there, no extra dependencies. Using CLI to parse the last commit hash as we mentioned above is simple enough:

git rev-parse —short=10 HEAD

As the shell call is synchronous, it’s easier to write and maintain procedures (also more readable).

What if we need task running with another task dependencies? Say running a compile task before test cases run, or publishing a new version to npm registry after bumping your package.json. This could be achieved by our old friend, Makefile. But this time, we don’t write filenames for sources and targets. Just use a task name instead. For example,

install:
mkdir -p tmp/public
npm install
$(bin)/bower install

The install task will make sure our dependencies are installed.

test.karma: install
./node_modules/karma/bin/karma start test/karma.js
ifdef TRAVIS
find tmp/coverage -name lcov.info -follow -type f -print0 | xargs -0 cat | $(bin)/coveralls
endif

The test.karma task, apparently runs karma unit test using config file at test/karma.js, and output coverage report to coveralls when running on CI server (travis-ci).

See? It’s so simple and use common and well-documented interfaces so that everyone can easily understand what you want to achieve right now. And since Makefile has well-developed in the era of compiled languages, it’s easy to find examples and how-tos to get your jobs done (just with a little help of imagination and modification).

So give up writing ugly and unmaintainable codes in your gulpfile / Gruntfile and embrace Makefile. You can find more examples in my personal boilerplate for a Single Page Application right here.

Enjoy your journey with Makefile!

--

--

Lost in Space
@tomchentw/software

<Tom Chen> Aspie. Introvert. Remoter. Blogger. 「從程式碼的26個英文字母到文章的26個英文字母,開始發現寫作的魅力。」