Javascript build tools
During my frontend time, I have seen some of tools to build frontend projects. Grunt, Gulp and so on. However, these tools often make me get in the way for its verbose configuration and long dependent plugins.
Why make
Actually, most of the tasks we need to build can be run using existing executables in the shell. Sass, Uglify, Unit test and so on have awesome executables already, what we need is just an easy way to run our commands to build projects without extra tooling and plugins. And Make comes to rescue.
What and how
GUN Make is a tool which controls the generation of executables and other non-sources files of a program from the program's source files.
Though make
is perceived as being only for C projects, it is a general-purpose build tool that can be used
on any kinds of projects. And in the case of a frontend build, make
can help us construct dependency graph
and execute some commands directly.
At begin, we need a file called Makefile
. A Makefile consists of rules that has ite own specific purpose.
Each of these rules has:
- a target, it can be a file or just a name
- prerequisites, an optional set of files the target depends on
- commands
And the syntax for a target is:
target: prerequisites
commands
A Web project Makefile
Next, we will build a simple web project that uses Compass
, jade
.
The contents of our source files are not important, what we concern is what we need to do with the
files to make them ready to run.
At first, we should create package.json
file to install the dependencies for this project, then
run npm install
. We could also achieve it in make.
{
"dependencies": {
"jade": "1.9.2",
"uglify-js": "~2.4.0"
}
}
NODE_MODULES = node_modules
install: package.json
@npm install
Next, we may need to compile all jade templates which under the templates directory to the single file. Here is the sample.
template_js := templates/*.js
template_source := templates/*.jade
$(template_js): $(template_source)
jade --client --no-debug $^
In first two lines, we use variables to define the source of our template, and in the recipe, we
use jade --client
command to render the source template file. $^
is a special make variable, which
is a list of all the dependencies, separated with spaces. Next time, we need to concatenate our js file
including runtime.js
and jquery
and minify it.
locals = js/locals.js
app_bundle := build/app.js
lib := vendor/jquery.js \
node_modules/jade/runtime.js
uglifyjs := ./node_modules/uglify-js/bin/uglifyjs
$(app_bundle): $(lib) $(template_js) $(locals)
$(uglifyjs) -cmo $@ $^
The locals.js
is something about locals object and the $@
refers to the target. Besides, we can also
compile our sass code.
scss_file := sass/*.scss
%.css: %.scss
compass compile $(scss_file)
At last, we may add a .PHONY
target, which is not really the name of a file, and tell the make
not to find this file. What's more, when you run make without a target, the first entry is the
one to run, usually named all
by convention.
all: install $(app_bundle)
.PHONY: all
The whole Makefile looks like this:
uglifyjs := ./node_modules/uglify-js/bin/uglifyjs
app_bundle := build/app.js
locals = js/locals.js
template_js := templates/*.js
template_source := templates/*.jade
lib := vendor/jquery.js \
node_modules/jade/runtime.js
scss_file := sass/*.scss
node_modules = node_modules
all: install $(app_bundle)
$(template_js): $(template_source)
jade --client --no-debug $^
$(app_bundle): $(lib) $(template_js) $(locals)
@$(uglifyjs) -cmo $@ $^
%.css: %.scss
compass compile $(scss_file)
install: package.json
@npm install
clean:
@rm -rf $(node_modules) $(template_js) $(app_bundle) $(scss_file)
.PHONY: all clean
Now we can create a web page to see the result.
<!DOCTYPE HTML>
<html>
<head></head>
<body>
<script src="./build/app.js"></script>
</body>
</html>