Part I. Using make
where I go over the basics of a makefile and the relevant parts you'll need to know.
In this post, I'll share some tips on working with
The project setup I've decided to go with as an example is very frontend focused but easily changed to work with a backend if needed.
If you need a refresher on
make, I'd suggest you check out part 1 on using make.
PATH := node_modules/.bin:$(PATH) build: webpack -p # it works!
First up, it's a good idea to amend the environment variable
PATH to include our project's
node_modules directory. This is so we can be sure
make is using the correct scripts for our tasks.
make is designed with an internal database system which keeps track of last modified times of files. Using this database, it knows only to build the relevant parts of the system where files have changed. This works as a great development tool for compiled projects but is mostly unneccessary if you're using
mocha or any other tool which has "watch" tasks.
We can force
make to always build regardless of last-modified checks, by:
- using cli flags
- using the special
.PHONYtask in our
.PHONY as it gives us greater control. Here's an example.
.PHONY: test test: mocha **/*.test.js
Example 2. What if we have multiple tasks?
# bad .PHONY: clean install test build deploy # good .PHONY: all .all: clean install test build deploy
make runs, it will print out the commands for task being run, which can get a little verbose if you're checking for errors.
Use the special
.SILENT task to prevent this default output. If you're
echo-ing things to stdout, these will still show.
Example 1. Checking at environment variable level
AWS_BUCKET := $(if $(filter production, $(NODE_ENV)),'my_production_bucket', 'my_staging_bucket') deploy: echo $(AWS_BUCKET)
Example 2. Checking at task level
deploy: if [ $(NODE_ENV) = production ]; \ then \ AWS_BUCKET='my_production_bucket'; \ else \ AWS_BUCKET='my_staging_bucket'; \ fi; \ echo $$AWS_BUCKET
Example 3. Checking with a function
deploy: AWS_BUCKET=$(call isProduction,"my_production_bucket","my_staging_bucket"); \ echo $$AWS_BUCKET define isProduction $(if $(filter production, $(NODE_ENV)),$1,$2) endef
Example 1. Using a function
archive: echo "Now zipping version $(call get_version)" tar -czf archive-$(call get_version).tar.gz -C ./build define get_version $(shell cat package.json | sed -n 's/"version": "\([^"]*\)\",/\1/p' | tr -d '[:space:]') endef
make will stop if it hits a non-zero exit. If for any reason, you need to handle or bypass errors, here's an example of how you can do that.
lint: eslint src; \ if [[ $$? -ne 0 ]]; then ...; exit 0; fi
PATH := node_modules/.bin:$(PATH) .PHONY: all .SILENT all: clean install lint test build deploy clean: rm -rf node_modules/* rm -rf build/* install: npm install lint: eslint src test: mocha **/*.test.js build: webpack -p deploy: aws s3 rm s3://mybucket --recursive aws s3 cp build s3://mybucket --recursive
I hope you've found both parts educational and at the very least convinced some of you
make can be a viable tool in your daily project workflows.
If you think
make is for you, then you should read up on the official man pages
and how others are using it. You'll be surprised that we've only really cover a small fraction
on what's possible with
make and I'll bet you'll stumble upon some tricks of your own.
This post is updated periodically as and when I receive feedback so shoot me a line and, time permitting, I'll do my best to get back to you as soon as I can.