Making a CLI & Library fusion
Tags: javascript, node
Published: 2018-01-20 16:38:38

---
title: Making a CLI & Library fusion
published: true
description: Making a fancy CLI, and then stripping it down to it's skin and it's bones.
tags: javascript, node
---

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]:
```js
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.
```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;
```

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.
```js
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].
```js
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
```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
```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
```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"
}
```