2020-06-01 Node modules working as command-line scripts

Recently, I wanted to run one Node.JS CLI script from another. Of course, being in a hurry and KISS and whatnot, I decided to just use child_process.execFileSync with node as the first argument, but this is of course grossly inefficient. What if I could write a module usable both from the command line and other code?

Well, it turns out that not only is this doable, but actually easy and robust. (Anyone working with JavaScript for more than a week will appreciate the last part. ;-) )

First things first: to determine if the code is ran as a standalone script (using the Node binary) or required/imported, it is enough to test if require.main === module. (I first learned this from this Petr Stodulka’s post, and – since that post was pretty old – confirmed this with the current documentation. Notice that Stodulka uses ==, which works, but I’d rather use ===.)

Now the example was in CoffeeScript instead of plain JS, and used module.exports and require (which are perfectly fine, but a bit old-fashioned), so I decided to experiment a bit with the newer export / import syntax. Unfortunately, this seems harder than I thought – I don’t even know if it’s possible. I think perusing the docs might reveal an answer to this question, but I’m afraid it’s negative. Since I am perfectly ok with using module.exports and require for my needs here, I’ll go with it.

So, here’s my take on this. Unlike Stodulka, I am not going to use yargs (which I like nevertheless) here for the sake of simplicity. My module (let’s call it show_args.js) looks like this:

#!/usr/bin/node

function show_args(...args) {
	console.log(`Arguments were ${args}.`);
}

if (require.main === module) {
	show_args(process.argv);
} else {
	module.exports = show_args;
}

I define the show_args function which does nothing interesting besides printing its arguments. Also, I include the shebang so that the file can be executed directly (this is not needed of you intend to run it via node show_args.js). Finall, I run the show_args function with the command-line parameters if it was run as a standalone script, and export that function otherwise.

Now you can say ./show_args.js 1 2 3 (see what happens!), but you can also use this as a module in another Node.JS script or even a web app, like this:

const show_args = require('./show_args.js');
show_args(1, 2, 3);

Happy scripting!

CategoryEnglish, CategoryBlog, CategoryJavaScript