DEV Community

Gergő Móricz
Gergő Móricz

Posted on

2 1

Making a CLI & Library fusion

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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay