Making a CLI & Library fusion
Gergő Móricz
Posted on January 20, 2018
So let's say you want to make a CLI. Great! You made it with yargs, or just straight process.argv
. Anything works.
But now you suddenly want to make it a package too. Create a seperate package? No need to.
For example, here's our CLI code[1]:
var fs = require('fs');
var fileName = process.argv[2]; // get 1st argument (0 is node, 1 is script filename)
var fileStats = fs.statSync(fileName); // get file stats
var fileSize = fileStats.size; // filesize in bytes
console.log(fileSize); // print fileSize
This simple code gets the filesize of the file provided in the arguments.
Now, if you'd want to make a CLI, you'd name this index.js
, put it as main file, and put it in "bin"
. But if you're making a fusion[2], you should name this cli.js
[3], and put it into "bin"
, but do not make it main. We'll create a new main file.
var fs = require('fs');
function getFileSize(fileName) {
var fileStats = fs.statSync(fileName); // get file stats
var fileSize = fileStats.size; // filesize in bytes
return fileSize;
}
module.exports = getFileSize;
This is somewhat-same as the CLI code. You still require fs
first, but then we create a function, with a fileName
argument. You don't need to get the fileName from argv
since it's supplied in the argument, so we just get the fileStats
and fileSize
, and then return it. Lastly, we export the function.
People can now use the main file in our own node scripts.
var cliApi = require('yourPackageName');
var fileSize = cliApi('example.txt'); //getFileSize(fileName)
Now, we could just leave the CLI code alone and just ship it, but when you update the package, inconsistency could happen between the API and the CLI code. So you'd want to rewrite the CLI code to use the CLI API code[1].
var cliApi = require('./index.js'); // require the CLI API file
var fileName = process.argv[2]; // get 1st argument (0 is node, 1 is script filename)
var fileSize = cliApi(fileName); //getFileSize(fileName)
console.log(fileSize);
First, we get the CLI API. Let's talk about this require statement for a bit. ./
is needed at the beginning. It means that node should require the file (that can be found at the path after ./
) not from node_modules, but the actual folder that the script (that's being executed) is.
Next, we need to get the filename from the arguments, then we get the filesize from the CLI API, and we print it to the console. That's it!
Notes
[1]: Shebang (needed for npm link
) not included.
[2]: Not a technical term.
[3]: Doesn't matter what you name it. Just reserve index.js
for the main file.
Also, make sure you make it clear in your README that this package is both a package and a CLI.
Example files
index.js
var fs = require('fs');
function getFileSize(fileName) {
var fileStats = fs.statSync(fileName); // get file stats
var fileSize = fileStats.size; // filesize in bytes
return fileSize;
}
module.exports = getFileSize;
cli.js
#!/usr/bin/env node
var cliApi = require('./index.js'); // require the CLI API file
var fileName = process.argv[2]; // get 1st argument (0 is node, 1 is script filename)
var fileSize = cliApi(fileName); //getFileSize(fileName)
console.log(fileSize);
package.json
{
"name": "getfilesize",
"version": "1.0.0",
"description": "A CLI and package for getting file sizes.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"fs"
],
"bin": {
"filesize": "cli.js"
},
"author": "skiilaa",
"license": "MIT"
}
Posted on January 20, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024