Goodbye Grunt, Hello Tend
June 9, 2014
Recently decided to give Grunt a try, which caused me to write my own node.js build system.
For the longest time I had refused to move away from Makefiles
for Grunt or some other node.js build system.
But I finally gave in and decided to take an afternoon to give Grunt a go.
Initially it seemed promising, Grunt had a plugin for everything and ultimately
it supporting watching files and directories (the one feature I really wanted
for my make
build setup).
I tried to move over a fairly simplistic Makefile
that I already had written
into a Gruntfile
. However, after about an hour (or more) of trying to get grunt
setup with grunt-cli and all the other
plugins installed and configured to do the right thing I realized that Grunt
wasn’t for me. I took a simple 10 (ish) line Makefile
and turned it into a 40+
line Gruntfile
and it still didn’t seem to do exactly what I wanted. What I
had to reflect on was why should I spend all this time trying to learn how to
configure some convoluted plugins when I already known the correct commands to
execute? Then I realized what I really wanted wasn’t a new build system but
simply watch
for a Makefile
I have attempted to get some form of watch working with a Makefile
in the past,
but it usually involves using inotify and I’ve never gotten it working exactly
like how I wanted. So, I decided to start writing my own system, because, why not
spend more time on perfecting my build system. My requirements were fairly simple,
I wanted a way to watch a directory/files for changes and when they do simply run
a single command (ultimately make <target>
), I wanted the ability to also run
long running processing like node server.js
and restart them if certain files
have changed, and lastly unlike other watch based systems I have seen I wanted
a way to run a command as soon as I start up the watch program (so you dont have
to start the watching, then go open/save a newline change to a file to get it to
build for the first time).
What I came up with was tend. Which solves mostly all of my needs, which was simply “watch for make”. So how do you use it?
Installation
npm install -g tend
Usage
Usage:
tend
tend <action>
tend [--restart] [--start] [--ignoreHidden] [--filter <filter>] [<dir> <command>]
tend (--help | --version)
Options:
-h --help Show this help text
-v --version Show tend version information
-r --restart If <command> is still running when there is a change, stop and re-run it
-i --ignoreHidden Ignore changes to files which start with "."
-f --filter <filter> Use <filter> regular expression to filter which files trigger the command
-s --start Run <command> as soon as tend executes
Example CLI Usage
The following will watch for changes to any js
files in the directory ./src/
when any of them change or are added it will run uglifyjs
to combine them into
a single file.
tend --ignoreHidden --filter "*.js" ./src "uglifyjs -o ./public/main.min.js ./src/*.js"
The following will run a long running process, starting it as soon as tend
starts
and restarting the program whenever files in ./routes/
has changed.
tend --restart --start --filter "*.js" ./routes "node server.js"
Config File
Instead of running tend
commands singly from the command line you can provide
tend
with a .tendrc
file of multiple directories/files to watch with commands
to run.
The following .tendrc
file are setup to run the same commands as shown above.
; global settings
ignoreHidden=true
[js]
filter=*.js
directory=./src
command=uglifyjs -o ./public/main.min.js ./src/*.js
[app]
filter=*.js
directory=./routes
command=node ./app/server.js
restart=true
start=true
You can then simply run tend
without any arguments to have tend
watch for
all changes configured in your .tendrc
file.
Running:
tend
Will basically execute:
tend --ignoreHidden --filter "*.js" ./src "uglifyjs -o ./public/main.min.js ./src/*.js" \
& tend --restart --start --filter "*.js" ./routes "node server.js"
Along with running multiple targets at once, you can run specific targets from
a .tendrc
file as well, tend <target>
.
tend js
Will run the js
target once.
tend --ignoreHidden --filter "*.js" ./src "uglifyjs -o ./public/main.min.js ./src/*.js"
With Make
If I haven’t beaten a dead horse enough, I am a Makefile
kind of person and
that is exactly what I wanted to use this new tool with. So below is an example
of a Makefile
and it’s corresponding .tendrc
file.
js:
uglifyjs -o ./public/main.min.js ./src/*.js
app:
node server.js
.PHONY: js app
ignoreHidden=true
[js]
filter=*.js
directory=./src
command=make js
[app]
filter=*.js
directory=./routes
command=make app
restart=true
start=true
Conclusion
So that is mostly it. Nothing overly exciting and nothing really new here, just another watch/build system written in node to add to the list. For the most part this tool does exactly what I want for now, but if anyone has any ideas on how to make this better or even any other better/easier tools which do similar things please let me know, I am more than willing to continue maintaining this tool.