Minify javascript with GNU Make

June 9, 2017

In my former blog post I wrote an introduction how to set up Makefile to generate CSS and minify CSS from Sass files. In this blog post I will extend the Makefile with a rule for generating minified javascript files.

My folder structure and Makefile looks like this:

FOO-project/
   static/
      css/
         /* here comes the generated css files */
      js/
         base.src.js
         /* the minified js files will also be placed in this directory */
   scss/
      base.scss
      login.scss
      shop.scss
      _variables.scss
      _mixins.scss

CSS_OBJ = static/css
SASS_SRCS = scss

CSS_DEPS = $(wildcard $(SASS_SRCS)/_*.scss)
CSS_SRCS = $(filter-out _%, $(notdir $(wildcard $(SASS_SRCS)/*.scss)))
CSS_OBJS = $(patsubst %.scss, $(CSS_OBJ)/%.src.css, $(CSS_SRCS))
CSS_MIN_OBJS = $(patsubst %.scss, $(CSS_OBJ)/%.min.css, $(CSS_SRCS))

all: $(CSS_OBJS) $(CSS_MIN_OBJS)

$(CSS_OBJ)/%.src.css: $(SASS_SRCS)/%.scss $(CSS_DEPS)
    scss $< $@

$(CSS_OBJ)/%.min.css: $(SASS_SRCS)/%.scss $(CSS_DEPS)
    scss --sourcemap=none --style compressed $< $@

clean:
    rm -f $(CSS_OBJS) $(CSS_MIN_OBJS)

.PHONY: clean all

.SUFFIXES:            # Delete the default suffixes
.SUFFIXES: .min.css .src.css

UglifyJS

You need a package which minifies the javascript files. I use UglifyJS for this task, it is a javascript parser, compressor and beautifier. You can install it via npm:

 $ npm install -g uglify-js 

I create a variable called JS_MIN_OBJS, which replaces the .src.js file name with .min.js file name from the source files 'static/js/*.src.js'. I put this line below the variable CSS_MIN_OBJS in the Makefile:

CSS_MIN_OBJS = $(patsubst %.scss, $(CSS_OBJ)/%.min.css, $(CSS_SRCS))

JS_MIN_OBJS= $(patsubst %.src.js, %.min.js, $(wildcard $(JS_SRCS)/*.src.js))

Now I add the UglifyJS rule in the Makefile with the UglifyJS options for generating the wanted minified output. I put this line of code below the rule for minifying css:

$(CSS_OBJ)/%.min.css: $(SASS_SRCS)/%.scss $(CSS_DEPS)
    scss --sourcemap=none --style compressed $< $@

%.min.js: %.src.js
    uglifyjs --comments -c hoist_vars=true,join_vars=true -m -r '$$' -o $@ $<

The UglifyJS options are documented on their github page, another resource is a blog post from David Walsh. You can also find the list of options in your terminal with the command: *uglifyjs -h*.

In my example I ask uglify to preserve the copyright comments in the output *(- -comments)* and compress *(-c)* the file with the following options:

To let Make also run the uglify task, I need to add $(JS_MIN_OBJS) to the all target. I also want that the minified files are deleted when running make:

CSS_OBJ = static/css
SASS_SRCS = scss
JS_SRCS = static/js

CSS_DEPS = $(wildcard $(SASS_SRCS)/_*.scss)
CSS_SRCS = $(filter-out _%, $(notdir $(wildcard $(SASS_SRCS)/*.scss)))
CSS_OBJS = $(patsubst %.scss, $(CSS_OBJ)/%.src.css, $(CSS_SRCS))
CSS_MIN_OBJS = $(patsubst %.scss, $(CSS_OBJ)/%.min.css, $(CSS_SRCS))
CSS_MAPS =  $(patsubst %.src.css, %.src.css.map, $(CSS_OBJS))

JS_MIN_OBJS= $(patsubst %.src.js, %.min.js, $(wildcard $(JS_SRCS)/*.src.js))

all: $(CSS_OBJS) $(CSS_MIN_OBJS) $(JS_MIN_OBJS)

$(CSS_OBJ)/%.src.css: $(SASS_SRCS)/%.scss $(CSS_DEPS)
    scss $< $@

$(CSS_OBJ)/%.min.css: $(SASS_SRCS)/%.scss $(CSS_DEPS)
    scss --sourcemap=none --style compressed $< $@

%.min.js: %.src.js
    uglifyjs --comments -c hoist_vars=true,join_vars=true -m -r '$$' -o $@ $<

clean:
    rm -f $(CSS_OBJS) $(CSS_MIN_OBJS) $(CSS_MAPS) $(JS_MIN_OBJS)

.PHONY: clean all

.SUFFIXES:            # Delete the default suffixes
.SUFFIXES: .min.css .src.css .min.js

Run make in the terminal and the minified files are generated. In the terminal you'll get the following output:

 $ make
uglifyjs --comments -c hoist_vars=true,join_vars=true -m -r '$' -o static/js/base.min.js static/js/base.src.js
 

That's it. You only need 4 lines of code to minify your javascript files. Together with compiling CSS and minifying CSS it is only 30 lines of code. That's pretty clean.