I've never quite known the proper way to declare a global script within an npm module. The docs aren't exactly hazy, but I conducted a little survey, below, to grok the overall practice. A brief wrapup follows.
The meat of the app exists in ./bin/express
, which freely requires scripts with paths relative to itself.
"bin": {
"express": "./bin/express"
}
#!/usr/bin/env node
# [...]
Uses precisely the same pattern as express
"bin": {
"grunt": "bin/grunt"
}
#!/usr/bin/env node
# [...]
Mocha mixes things up a bit. "mocha" does little but execute "node ./_mocha", except when certain commands would modify node instead of mocha, i.e. "node debug _mocha". It wasn't always that way.
"bin": {
"mocha": "./bin/mocha",
"_mocha": "./bin/_mocha"
}
#!/usr/bin/env node
/**
* This tiny wrapper file checks for known node flags and appends them
* when found, before invoking the "real" _mocha(1) executable.
*/
// [...]
args = [ __dirname + '/_mocha' ]
/* [building some arguments] */
#!/usr/bin/env node
/** [familiar..]
* Module dependencies.
*/
Standard.
"bin" : {
"uglifyjs" : "./bin/uglifyjs"
}
#!/usr/bin/env node
[...]
Similar invocation, with an interesting twist: help files are stored in bin/usage.txt
and bin/advanced.txt
, offering a pretty neat way to manage usage if not using commanderjs.
"bin": {
"browserify": "bin/cmd.js"
}
#!/usr/bin/env node
var fs = require('fs');
[...]
jshint is the first on this list that has a one-liner bash script. Still, it invokes ../src/cli.js
.
"bin": {
"jshint": "./bin/jshint"
}
#!/usr/bin/env node
require("../src/cli.js").interpret(process.argv);
// [...]
var OPTIONS = {
"config": ["c", "Custom configuration file", "string", false ],
//[...]
The common method of creating a global command is to define it in package.json
like so:
package.json
"bin": {
"{commandName}": "bin/{fileName}"
}
The npm docs don't disagree.
That script then does the CLI-oriented stuff
bin/{fileName}
#!/usr/bin/env node
var program = require('commander');
program.parse(process.argv);
The script can require files from its package using paths relative to itself
bin/{fileName}
#!/usr/bin/env node
var tool = require('../lib/tool');
To easily surface usage/help messages, simply write then as .txt files à la browserify:
bin/{fileName}
#!/usr/bin/env node
return fs.createReadStream(__dirname + '/advanced.txt')
.pipe(process.stdout)
.on('close', function () { process.exit(1) })
;