Just use Make as your Task Runner

Make is ubiquitous on *nix systems, and it’s a great way to automate tasks. Every language ecosystem has it’s own set of tools to build, format, lint, test, and deploy code. But every project has the same set of tasks that need to be done. And I’m just not smart enough to remember the correct encantations to invoke to run them.

While make is not a general purpose task runner, it’s a great way to automate tasks, in an exosystem agnostic way.

The Makefile

This is the Makefile from a project I’m working on. It’s a simple Makefile that uses make to run a few tasks. While the NodeJS ecosystem has generally has task runner built into the build tools, there is something to be said for having a consistent way to run tasks across projects and languages.

default: help

include .env
export

help:		## Show this help.
	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
.PHONY: help

install:	## Install dependencies
	@brew install pnpm docker docker-compose
	@pnpm install
	@cp .env.example .env
.PHONY: install

build:		## Build application
	@pnpm run build
.PHONY: build

dev: docker		## Run  applications with live reload
	@pnpm run dev
.PHONY: dev

start: docker	## Start application
	@pnpm run start
.PHONY: start

format:		## Format code
	@pnpm run format
.PHONY: format

lint:		## Lint code
	@pnpm run lint
.PHONY: lint

typecheck:	## Typecheck code
	@pnpm run typecheck
.PHONY: typecheck

test: docker		## Run tests
	@pnpm run test
.PHONY: test

docker:	## Start docker containers
	@docker compose up -d --profile db
.PHONY: docker

down:	## Stop docker containers
	@docker compose down
.PHONY: down

This Makefile is also self documenting, make help will show you the help text for each task.

$ make help

Usage:
  make
  help             Show this help.
  install          Install dependencies
  build            Build application
  dev              Run  applications with live reload
  start            Start application
  format           Format code
  lint             Lint code
  test             Run tests
  docker           Start docker containers
  down             Stop docker containers

This comes in handy when you’re working on a project with a team, or are just genarraly forgetful, or have a lot of projects. I found the help hack in the comments of this gist, where there is also an suggestion to generate the help text from the Makefile with a docker image!

Conclusion

It is very useful to have a consistent way to run tasks across projects and languages. Being able to go into any project, regardless of the language, and know that I can run make test to run the unit tests, or make lint to run the linter. Without having to remember exactly which lint tool I’m using in this project is a huge time saver.