You can view all files in this Gist.
For non-minified file file, it’s named as file.dev.js and its minified version is named as file.min.js. There are the sources to be symbolic linked from file.js, for which is linked that depends on whether you are developing or deploying.
So, the HTML should always use file.js, not *.dev.js or *.min.js. This way, it’s much easier to switch without needing to touch HTML files.
Normally, I would lay files like:
/Makefile /css/Makefile /css/foo.dev.css /css/bar.dev.css /js/Makefile /js/foo.dev.js /js/bar.dev.js
But in this post, I would have to flatten them out because I am using Gist to store these example files and I don’t think Gist can support files in directories:
/Makefile /Makefile.CSS /foo.dev.css /bar.dev.css /Makefile.JS /foo.dev.js /bar.dev.js
Using foo.dev.css as example, the minified file and symbolic link file would look like:
/foo.min.css /foo.css -> foo.min.css
or, if in development:
/foo.css -> foo.dev.css
The root Makefile is only used for carry target onto the Makefiles for JS and CSS, Makefile.CSS and Makefile.JS:
dev min clean: make -f Makefile.CSS $@ make -f Makefile.JS $@
There are three targets: dev, min, and clean. I don’t think I need to explain what they mean. The recipe is simply invoking the two Makefiles for doing actual work with the target name $@.
I will only show and explain Makefile.JS in this post, they are almost identical. This is the Makefile.JS:
TARGETS = foo bar TARGETS_ALL = $(TARGETS) foobar CLOSURE_URI = http://closure-compiler.appspot.com/compile all: min foobar.%.js: $(addsuffix .%.js,$(TARGETS)) cat $^ > $@ %.min.js: %.dev.js curl --data output_info=compiled_code --data-urlencode js_code@$< $(CLOSURE_URI) > $@ dev: $(addsuffix .dev.js,$(TARGETS_ALL)) dev_symlink min: $(addsuffix .min.js,$(TARGETS_ALL)) min_symlink dev_symlink: $(addsuffix .dev,$(TARGETS_ALL)) min_symlink: $(addsuffix .min,$(TARGETS_ALL)) %.dev %.min: @if [ "`readlink $*.js`" != "$@.js" ]; then\ rm -f $*.js ;\ ln -v -s $@.js $*.js ;\ fi clean: rm -f $(addsuffix .js,$(TARGETS_ALL)) rm -f $(addsuffix .min.js,$(TARGETS_ALL)) rm -f foobar.dev.js .PHONY: all clean dev_symlink min_symlink
The TARGETS stores the names of scripts without .dev.js, they are the scripts which need to be minified. In this case, they are foo bar.
The next TARGETS_ALL are foo bar foobar, where foobar is the concatenated file of foo and bar. I want to add the concatenation for this example because reducing files is a good way to speed up page loading a little bit.
Firstly, take a look at dev target:
dev: $(addsuffix .dev.js,$(TARGETS_ALL)) dev_symlink
The prerequisites are expanded to foo.dev.js bar.dev.js foobar.dev.js dev_symlink. The first two are the development or non-minified files, third one matchs foobar.%.js target, and last one is a phony dev_symlink target.
The third prerequisite foobar.dev.js of dev target matches foobar.%.js recipe:
foobar.%.js: $(addsuffix .%.js,$(TARGETS)) cat $^ > $@
Its prerequisites are foo.dev.js bar.dev.js, which is also $^ in the recipe, and will be concatenated by cat command. $@ is the target, that is foobar.dev.js. Therefore the recipe would look like performing:
cat foo.dev.js bar.dev.js > foobar.dev.js
This recipe is also used for min target.
The min is almost the same as dev target. The only difference is the target for minifying files:
%.min.js: %.dev.js curl --data output_info=compiled_code --data-urlencode js_code@$< $(CLOSURE_URI) > $@
This is the recipe to minify files. You can see the command is running a HTTP request instead of a local command, because I don’t want to have Java on my computer, so I’ve found a way to minify files with remote services.
The clean is for removing generated or symbolic link files:
clean: rm -f $(addsuffix .js,$(TARGETS_ALL)) rm -f $(addsuffix .min.js,$(TARGETS_ALL)) rm -f foobar.dev.js
I know I am not very good at writing Makefile, they may contain some pitfalls that I haven’t fallen into. If you have any suggestions or corrections, feel free to do so in the comments.