Makefile for CSS and JS Minify/Compress
I love Makefiles. Automation in all its forms is desirable, but Makefiles have a combination of surface simplicity and unknowable complexity that I find very endearing. I've had an ever-growing need to automate the minification and compression of CSS and JavaScript files on my web server, and while I'd written some rudimentary Makefiles in the past, I finally found time to write a kick-ass general purpose Makefile that can be applied to any project with very little modification.
You'll want to have the YUI Compressor and Google Closure
Compiler installed for minification of CSS and JavaScript,
respectively. I installed them to my ~/bin
directory, and referenced
that directory in my Makefile.
Note that I'm using these two pieces of software mostly out of habit; I haven't evaluated them or their competitors recently.
The Meat
Customizing for Your Project
To make this file useful for your own project, you'll need to point it at your CSS and JS files.
JS_TARGETS =
CSS_TARGETS =
CLEANUP =
The first two variables define what scripts will be minified and
compressed when you type "make js" or "make css," respectively. Both of
these commands will run when you type "make all" or simply "make."
CLEANUP
allows you to specify additional files that will be removed
when you type "make clean."
Some sample customizations are mentioned in the file.
CSS_TARGETS = $(shell cat manifest.txt)
If you would rather organize your list of CSS or JavaScript targets into their own files, you can automatically expand that manifest file using the cat command.
CLEANUP = $(CSS_TARGETS) $(JS_TARGETS)
Some more advanced setups may combine several CSS files before minification, or use a custom target to concatenate JavaScript using the closure compiler. If you find that all your targets can be cleaned, you can simply reference them automatically as above.
concatenated.min.js: file1.js file2.js
java -jar ~/bin/compiler.jar $(addprefix --js=,$^) >$@
The closure compiler requires a prefix for all input JavaScript files.
Use the make function "addprefix
" to format the argument list.
custom-concat.css: file1.css file2.css file3.css
cat $^ >$@
Automatic variables greatly simplify most of the functionality within
this makefile. To create a concatenated CSS file, simplify specify the
target to the left of the colon, and its dependencies (the files to
concatenate) to the right; the cat
command never needs modification.
Of course, you can always define custom rules, ie. this one to fetch the newest development version of jQuery:
jquery:
curl -o jquery.js http://code.jquery.com/jquery-git.js
Other Magic
Some other goodness happens below the "you shouldn't need to edit past here" line. After we configure a few settings, we define how to create files based on suffixes: .min.css gets passed through YUI Compressor, .min.js through Closure, and .gz through gzip. We configure what files we care about, and make handles the rest.
.DEFAULT_GOAL := all
Set a default rule, rather than using the first rule in the file as the default.
.PHONY: css js
Prevent files named "css" or "js" from interfering with the css and js rules.
%.gz: %
gzip -9 <$< >$@
One of three pattern rules. This enables you to compress any file (not just CSS or JS) by running "make filename.gz." I precompress my files because I'm using [gzip_static in nginx][].
CSS_GZIP = $(CSS_TARGETS:.css=.css.gz)
One of several variables that modifies filenames found in
$(CSS_TARGETS)
, changing the suffix from .css
to .css.gz
. Note
that the colon/equals syntax is shorthand for patsubst. Given
CSS_TARGETS = text.css tables.css
, we would get
CSS_GZIP = text.css.gz tables.css.gz
, which would be sent as targets
to the more general css
rule, and in turn would be handled by the
general-purpose %.gz
rule above.
See Also
- Advanced Makefile Tricks -- macros (
$@
et al) and wildcard rules - GNU make manual -- functions, automatic variables, pattern rules
- Grunt -- A Node-based build system for more complex automation