You can also use npm-scripts for basic shell commands. You can rely on NPM-authored tasks and have them listed as a devDependency, so that users don't need to install anything manually.
//create a UMD build for the browser
"scripts": {
"bundle": "browserify index.js -s foo > build/foo.js",
"minify": "uglifyjs build/foo.js > build/foo.min.js",
"build": "npm run bundle && npm run minify"
}
Now a user just needs to run this to build your app: npm run buildMake plays nicely with npm once you set the PATH to include ./node_modules/.bin . Watching is the only thing Make can't do, so I usually set up a very simple Gruntfile that watches the source files, launches a livereload server, and just calls `make` when anything changes.
Make is another story.
The main issue I have faced when trying to use bash scripts for this is that most frontend developers are not familiar with it, and a (thankfully) minority still uses Windows. You can still install dependencies from package.json and use ./node_modules/bin/xxx to execute them, so that's not a stopper.
I wrote a simple task-runner around the same time Grunt was born: http://ricardo.cc/cake-flour/, I still use it daily thought it's a bit out of date. Or you can use Gulp, still simpler and faster despite the quirky api.