Create a gist now

Instantly share code, notes, and snippets.

An example of using Make instead of Grunt for fast, simple and maintainable front-end asset compilation.

Give it a go:

git clone make-asset-compilation
cd make-asset-compilation
npm install
node_modules/.bin/bower install
mkdir -p javascripts sass public
echo 'console.log("Hello world");' > javascripts/myapp.js
echo 'html { background: papayawhip; }' > sass/myapp.scss

And then look in public to see your compiled files.

To watch it auto-recompile on file change, run make watch and then edit javascripts/myapp.js or sass/myapp.scss

"name": "myapp",
"dependencies": {
"angular": "x"
# A simple Makefile alternative to using Grunt for your static asset compilation
## Usage
# $ npm install
# And then you can run various commands:
# $ make # compile files that need compiling
# $ make clean all # remove target files and recompile from scratch
# $ make watch # watch the filesystem for changes and recompile
## Why?
# 1. Less dependencies
# Instead of needing a grunt-* wrapper library for your favourite tool, and
# needing to update or wait for a new version just to pass a new option into
# the underlying library, you can simply use the library directly.
# Thankfully all the awesome node libraries you're using with Grunt include
# command-line tools which are easily executable by make.
# 2. Easy to extend
# For this example we're using some linux commands for concating, and various
# node-based libraries for Sass compilation, CSS prefixing, etc.
# Adding a new tool or step to your asset compilation is dead simple:
# 1. add the library to package.json
# 2. npm install
# 3. add a new line to the revelant target, calling the binary created by npm
# install
# 3. Performance
# Makefile understands file modification times, so it won't recompile any
# targets whose source dependencies haven't changed. Combined with using a
# file modification monitoring tool like wach, you get near-instant recompiles
# of your front-end assets.
# Variables
APP_JS_SOURCES=$(BOWER)/angular/angular.js $(JS)/$(APP).js
# Targets
# The format goes:
# target: list of dependencies
# commands to build target
# If something isn't re-compiling double-check the changed file is in the
# target's dependencies list.
# Phony targets - these are for when the target-side of a definition
# (such as "all" below) isn't a file but instead a just label. Declaring
# it as phony ensures that it always run, even if a file by the same name
# exists.
.PHONY : all clean watch
# Compile the final targets
all: $(DIST)/$(APP).css $(DIST)/$(APP).js
# Destroy the final targets
rm -f $(DIST)/$(APP).css $(DIST)/$(APP).js
# Watch the filesystem and recompile on file modification
$(BIN)/wach -o "$(JS)/**/*,$(SASS)/**/*" make all
# The final CSS file
$(DIST)/$(APP).css: $(SASS)/**
$(BIN)/node-sass $(SASS)/$(APP).scss $(DIST)/$(APP).css
$(BIN)/autoprefixer --browsers $(AUTOPREFIXER_BROWSERS) $(DIST)/$(APP).css
# The final JS file
cat $(APP_JS_SOURCES) > $(DIST)/$(APP).js
"name": "myapp",
"devDependencies": {
"bower": "x",
"autoprefixer": "x",
"node-sass": "x",
"wach": "x"

Awesome use of Make! It's somewhat more difficult to configure, but the advantages are clear.


I think you have a typo in your example makefile. On line 82 you have
$(BIN)/wach -o "$(JS)//*,$(SASS)//*" make all
where wach should be watch.


but I should also say thank you for the gist.

STRML commented Jul 7, 2014

@sshelagh It actually is wach.


great, I'm tired of re-learning js build tools


instead using of $(BIN)/node-sass or a other service you can declare top of your makefile:

export PATH := $(PATH):$(PWD)/node_modules/.bin

then you have you write just node-sass, autoprefixer, etc. :)

marlun commented Feb 28, 2015

Note that adding node_modules/.bin after your default PATH will run globally installed tools instead of the locally installed ones if they are installed in both places.

daiyi commented Feb 17, 2017 edited

Make automatically watches files for changes! You can run watch make all to use unix watch to run make every 2 seconds and it will recompile on modification and you won't have to install wach :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment