Make For Asset Management post

tldr: the good stuff

Yes, that make.

$ man make

MAKE(1)

NAME
       make - GNU make utility to maintain groups of programs

Can this humble utility simplify a web developer's life managing a complex system of front end assets1?

In the past I used tools like Grunt, Gulp, Ant, and PHP's own Assetic to do this. Nothing felt right. Complex configurations, new scripts, new dependencies. There must be a better way.

Digression Warning

If anything is known about me, it is this: I'm lazy (proof). Don't make me do any extra work I don't have to do. Seriously. That previous sentence was only one word, that's how lazy I am. To me, laziness is an ideal. It's an ideal I can believe in, a rare gem awash in an ocean of ruthless pragmatism. But I digress.

Digression Averted, Make To The Rescue

Today, I want to talk about make. Make allows me to get work done faster so I can spend more time thinking about interesting problems, and less time building the plumbing for my web applications.

And, let's face it, plumbing carries shit. The less time I spend working on plumbing, the less time I have shit on my hands.

A Brief, Incomplete, Mostly Wrong History of Make

Make was originally introduced by Dr. Stuart Feldman of Bell Labs, in April 1976. Prior to widespread adoption of the utility, software was distributed with OS-specific "make" and "install" scripts. Make allowed multiple targets with commands to be written uniformly into one standardized build script. And this elegant solution is still one of the most widely distributed tools ever almost 40 years later.

Great. How Does This Relate To My Job?

The essence of make is to define repeatable transformations from a source to a target.

Ok. So what does that mean?

Transformations are shell commands, grouped into logical tasks by task name.

The source and target are filesystem objects. So what we have is a collection of shell commands, organized into logical groups of tasks, which define transformations in the filesystem.

Anatomy of a Makefile for the Web

By convention, a makefile's first target is a default catch-all, usually all:

all: clean build

More on this below.

Install

A web makefile is going to have different targets depending on things like libraries and the project structure. If dependencies are managed by Bower (and assuming bower is already configured and working), an install target like the one below works:

install:
    bower install

I usually have a few extra steps: convert a JS library from CommonJS to RequireJS, and create new distributable directories (note the buildDir macro2):

buildDir = /var/www/public

install:
    bower install \
    r.js -convert $(buildDir)/js/react-dropzone/ $(buildDir)/js/react-dropzone/ \
    mkdir -p $(buildDir)/js $(buildDir)/css \

Clean And Build

The build step compiles and releases a new set of CSS and javascript. For the example below, we're compiling LESS to CSS and JSX to vanilla JS. As the name implies, clean removes files generated during build.

assetsDir = /var/www/assets
buildDir = /var/www/public

build:
    cp -r $(assetsDir)/dist/* $(buildDir)/js \
    cp -r $(assetsDir)/dist/font-awesome/fonts $(buildDir)/fonts
    jsx --harmony --extension jsx --es6module $(assetsDir)/jsx $(buildDir)/js \
    lessc $(assetsDir)/less/master.less $(buildDir)/css/master.css

clean:
    rm $(buildDir)

Watching For Changes

Adding a --watch flag to the jsx command allows for automatic rebuild of JS resources when changed. Let's create a watch target for it.

watch:
    jsx --harmony --extension jsx --es6module --watch $(assetsDir)/jsx $(buildDir)/js

Putting It All Together

The makefile below contains two macros: assetsDir, buildDir, and four targets: install, build, watch, clean.

assetsDir = /var/www/assets
buildDir = /var/www/public

install:
    bower install \
    r.js -convert $(assetsDir)/dist/react-dropzone/ $(assetsDir)/dist/react-dropzone/ \
    mkdir $(buildDir)/js $(buildDir)/css

build:
    cp -r $(assetsDir)/dist/* $(buildDir)/js \
    cp -r $(assetsDir)/dist/font-awesome/fonts $(buildDir)/fonts \
    jsx --harmony --extension jsx --es6module $(assetsDir)/jsx $(buildDir)/js \
    lessc $(assetsDir)/less/master.less $(buildDir)/css/master.css

watch:
    jsx --harmony --extension jsx --es6module --watch $(assetsDir)/jsx $(buildDir)/js

clean:
    rm $(buildDir)

1. By assets, I'm referring to: javascript, preprocessed css, fonts, third party dependencies, and anything else that will eventually become accessible to the public. 2. Macros are variables local to the makefile.

Categories: features

Tags: make, frontend