Crafting a Basic Command Line Tool with Node.js
Empowering Your Projects with Custom Command-Line Tools ā A Hands-On Guide
Have you ever wondered how those cool command-line tools are builtš¤? In this practical guide, I'm going to take you through a way to build a basic CLI using Node.js and publish to npm. Letās dive in and transform your code into powerful commands that you can run from your terminal with ease!
Prerequisites
- Node.js installed.
- VS code or a text editor
The code I am going to use here is available here. Letās first set up a basic node.js project:
Setting Up the Basic Node.js Project
- Open the terminal
- Create a folder for project
mkdir cli
3. Navigate to the folder
cd cli
4. Initialize the Node.js project
npm init
5. Fill in the prompt
Creating a Basic CLI
- Create a folder named āsrcā in the root directory of your project.
- Inside the āsrcā folder, create a file named āindex.jsā. This file will serve as the entry point for your CLI.
- Open the āpackage.jsonā file in your project and modify the value of āmainā attribute from āindex.jsā to āsrc/index.jsā.
- Add a new entry to the āpackage.jsonā file. Create a key called ābinā and set its value to an object with the key animal(whatever you wish) and its value as ā./src/index.jsā.
- Add a key called ātypeā, and itās value to āmoduleā inside the package.json. It enables ECMAScript module syntax in Node.js, allowing you to use
import
andexport
statements instead ofrequire()
calls.
The package.json
file should now appear as follows:
{
"name": "cli",
"version": "1.0.0",
"description": "Basic cli ",
"main": "src/index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"animal": "./src/index.js"
},
"author": "",
"license": "ISC",
}
The key animal serves as the terminal keyword to invoke your CLI. Feel free to change as needed. Itās not a permanent label and can be modified at any time to suit your preferences or project requirements.
Letās make our CLI even more awesome! Open up the āindex.jsā file inside the ābinā folder, and sprinkle in the magic with the following code:
#!/usr/bin/env node
// Greet the world with your first program!
console.log("Hello, World! This is your pet speaking.");
The line#!/usr/bin/env node
is called a shebang or hashbang. Itās used in Unix-like operating systems (such as Linux and macOS) to indicate the interpreter that should be used to execute the script that follows.
#!
: This symbol is called the shebang or hashbang./usr/bin/env
: This is the path to theenv
command, which is a Unix/Linux utility that looks for executables in the userās environment.node
: This specifies the interpreter to be used, in this case, Node.js.
So, when you see `#!/usr/bin/env node` at the beginning of a script file, it means that the script should be executed using the Node.js interpreter, regardless of where Node.js is installed on the system. This allows for greater portability of scripts across different environments.
Ready to witness your CLI magic?
npm install -g
Since itās installed globally, you can invoke it from anywhere in your system! Take your CLI for a spinārun the command animal in your terminal to see the magic unfold!
How to Handle CLI Arguments?
With the foundation of our basic CLI in place, itās time to elevate its capabilities. A fundamental component of any CLI is the ability to handle command-line arguments.
Weāll use the wonderful commander npm package to help us with this process.
- Install commander:
npm i commander
2. Supercharge your `index.js` by including the commander module after installing it:
import {program} from ācommanderā;
3. creating a command that requires arguments:
program
.command("who")
.description("who am i")
.argument("<animal_name>", "name of the animal")
.action((animal_name) => {
console.log(`I am a ${animal_name}`);
});
program.parse(process.argv);
.command("who")
: This line defines a new command named "who"..description("who am i")
: This sets the description for the "who" command as "who am i"..argument("<animal_name>", "name of the animal")
: This declares an argument named "<animal_name>" for the "who" command with a description of the argument as "name of the animal"..action((animal_name) => { console.log(
I am a ${animal_name}); })
: This specifies the action to be taken when the "who" command is executed. It defines a function that takes the provided "animal_name" argument and logs "I am a [animal_name]" to the console.program.parse(process.argv)
: This line tells the program to parse the command-line arguments provided when the script is executed usingprocess.argv
.
You can execute through this command animal who āanimal nameā
Here is an example:
How to Create Commands with Flags?
Think of flags like switches you can toggle when youāre giving commands to your computer through the command line. Theyāre like little helpers that let you customize how a command works by adding extra bits of information.
You can recognize them because they usually start with a hyphen (-
) if they're short, like -h
for help, or a double hyphen (--
) if they're longer like, --help
Letās go through an example:
program
.command("food")
.description("what does animal like to eat")
.requiredOption("-a, --animal <animal_name>", "Name of the animal")
.requiredOption("-f, --food <food_name>", "The food the animal likes")
.action((options) => {
console.log(`${options.animal} likes to eat ${options.food}`);
});
.command("food")
: This line defines a new command named "food"..description("what does animal like to eat")
: This sets the description for the "food" command as "what does animal like to eat"..requiredOption("-a, --animal <animal_name>", "Name of the animal")
: This declares a required option-a
or--animal
for the "food" command, specifying the name of the animal. The<animal_name>
indicates that this option expects an argument..requiredOption("-f, --food <food_name>", "The food the animal likes")
: This declares another required option-f
or--food
for the "food" command, specifying the food the animal likes. Similarly,<food_name>
indicates that this option expects an argument..action((options) => { console.log(
${options.animal} likes to eat ${options.food}); })
: This specifies the action to be taken when the "food" command is executed. It defines a function that takes the provided options (includinganimal
andfood
specified by the user) and logs the message indicating what the animal likes to eat.
So, when you run this script from the command line with the āfoodā command followed by the required options or known as flags-a
or --animal
and -f
or --food
, it will execute the specified action and output the message indicating what the animal likes to eat.
Using flags makes your commands super flexible! You could type something like animal food -a cat -f milk
or animal food -f milk -a cat
you can mix it up however you want! With flags, the order of inputs doesnāt matter. But if youāre using arguments, then the order you type things in does matter.
Congratulations on creating your CLI tool! š Now, letās share it with the world by publishing it to npm. If youād like to provide guidance on how to install and use the commands, itās a great idea to include a readme.md file. You can take idea from this published package made by me.
How to Publish the CLI to NPM?
- Ensure that you have an npm account. If you donāt have one, you can create it by running
npm adduser
in your terminal and following the prompts. - Once you have an npm account, navigate to the root directory of your CLI project in your terminal.
- Run the command
npm login
and enter your npm username, password, and email when prompted. - After logging in successfully, run
npm publish
in your terminal. This will publish your CLI package to the npm registry.
Thatās it! Youāve officially published your CLI tool to npm. Now, go ahead and spread the word.
How to Update the Published Package?
Once youāve published your package, if you ever want to make changes to it, follow these simple steps:
- Make your changes: Update your code as needed. Fix bugs, add features, or make any other adjustments you see fit.
- Push changes to your repository: After making your changes, donāt forget to push them to your repository.
- Bump the version: Before publishing your changes, itās a good practice to bump the version of your package. This ensures that users who depend on your package can easily identify that there are new changes available. To bump the version, run:
npm version patch
This will automatically increment the patch version of your package in your āpackage.jsonā file. - Publish your changes: Once youāve bumped the version, youāre ready to publish your changes to npm. Run:
npm publish
This will update your package on the npm registry with the new changes.
And thatās itš¤! Your changes are now live and available for users to install.
I hope you found this information helpful! Keep coding and exploring new possibilities! Happy codingš»!