Following my previous blog post 5 Cli Tools That Will Increase Your Dev Velocity And Code Quality I wrote a quick guide on how to write and publish a CLI.
What’s in it for you?
- Write a cool as f*** CLI tool.
- Learn how to set up a project using Typescript.
- Publish your new shiny CLI to npm.
setup
We will use Scaffolder to generate all the boilerplate we need for our shiny CLI.
|
|
Scaffolder makes creating and sharing boilerplate code a breeze, Check it out!
Once npm
has finished installing all of our dependencies, we should have a clean, greenfield project.
Let’s have a quick look at the package.json
file.
First of all, as you can see we got a postfix to our name
field, I added this to prevent naming conflicts with existing packages 😄
Second, we got a bin
field.
bin
field tells npm that this package has an executable that should be invoked using the coolGroup
command.
|
|
Finally, we have commander
as a dependency. We are going to use it to register commands for our cli to act on.
In a gist commander makes creating CLI’s a breeze
Now Let’s quickly go over the tsconfig.json
file.
|
|
We mentioned ./dist/cli.js
in the bin
field. We can do that because we tell typescript to compile our code into a dist
folder.
If you want to learn more about Typescript or tsconfig.json, I recommend this free book.
We are finally done going over our boilerplate. Let’s get down to business.
We are going to write a simple CLI that does the following:
- Go over all the files in a directory and get their extension.
- Create a folder for each type of file extension.
- Move all the files to their matching folders.
0.5. Some imports for later
|
|
1. Go over all the files in a directory and get their extension.
|
|
2. Create a folder for each type of file extension.
If the folder already exists, then skip its creation to avoid errors.
|
|
3. Move all the files to their matching folders.
|
|
Putting it all together
We are going to put all of this logic inside a file named groupFilesByExtensions.ts
|
|
We got all of our logic in working condition. Now, let’s wire this thing up.
What will be a reasonable workflow for this CLI? Let’s write it up as a user story.
1. As a user, I want to type coolGroup
in my cli and have all files in my current working directory grouped.
By importing our groupFilesByExtensions
function into cli.ts
file.
We add a shebang(
#!/usr/bin/env node
) to specify the script interpreter that’s used to execute our code.
|
|
Let’s introduce another requirement and see we can adjust to it.
2. As a user, I to be able to specify the folder coolGroup
will work on.
For example
coolGroup --entry-point ./group/this/folder
Change the cli.ts
file to accommodate this change
|
|
Now our users can specify a path to the folder they want to group.
As a bonus, we get a nice help section out of the box!
run
npm run build
and thennode ./dist/cli.js
to see it in action locally (or use npm link)
Share it with the world!
We got a cool working CLI but it only exists on our local machine.
Let’s share this brilliant creation with the world by publishing it to npm.
Before moving to the next section, if you don’t have an npm user follow this guide to create one and set up the credentials.
To publish our package all we need is to run npm publish
and you should be good to go!
For a more polished publish flow check np out.
If everything went well you should see something like this.
check it out by running npx <your-module-name-here>
inside whatever folder you like.
woohoo, we are all done.