It is an open secret, that I prefer make
over all those newfangled build
tools, that first need a ton of configuration to get off the ground. A simple
rule to add autoprefixer goodies to a CSS file is exactly two lines long:
out.css: in.css
./node_modules/.bin/postcss "$<" --use autoprefixer --output "$@"
This little rule uses GNU make
Automatic
Variables,
which allows us to copy-paste it or use it in a pattern rule to address a
bunch of CSS files at once.
Given, that the make
command is in your path, updating out.css
means typing
make
and you’re done. It will also check timestamps and only rebuild the file, if
in.css
changed.
So far, so good. However, sometimes we have a single command, that issues several files at once, which depend from several others. For example, if you use Webpack or Rollup to handle your CSS and JS files, this will ring true immediately for you.
How do we tell make
then, that it should call webpack
, if any of the
source files changed, and that it should call it exactly once for all of our
destination files?
There is a good answer on
StackOverflow, that details the process. In a nutshell, we will leverage a
virtual intermediate file for this. I.e., we tell make
to build a file, that
won’t ever exist, and then depend our output files from it. We go even a step
farther and tell make
, that this file won’t ever exist.
Such a Makefile
will look like this:
dist/output_1.js \
dist/output_2.js \
dist/output_3.js \
dist/output_4.js: intermediate-build-step
.INTERMEDIATE: intermediate-build-step
intermediate-build-step: src/input_1.js src/input_2.js
mkdir -p dist
webpack
In lines 1 to 4 we tell make
, that our four output files depend on the
file intermediate-build-step
. In line 6, we tell make
, that this file is
virtual, or “intermediate” in make
lingo. This means, make
knows, that the
file won’t exist. It won’t look for it, when it compares timestamps in order
to determine, if the output files should be made.
Line 7 handles our dependencies. List all input dependencies for all output files here. You can also do that in a separate rule:
dist/output_3.js: src/additional_requirement.js
In line 8, we create the output folder, just to be sure. If it already exists,
the -p
flag ensures, that make
will continue. Finally, in line 9 we call
Webpack.
The wonderful thing about this solution is, that you can call make
over and
over again, and it will only ever run Webpack, if any of the input files
changed.