Run your NPX script directly from Github. Create your own CLI commands and other stories
Tags: tutorial, github, npm, todayilearned
Published: 2020-09-10 12:04:21

This will be a short read, probably, I can't promise you that though, but at least I'll make it as entertaining as it can get.

First, what is NPX, and what are CLI commands?
NPX is a command-line tool meant to run NPM packages containing CLI scripts.
A CLI command is a program that can be run from the command line by name, for example, `gcc` or `cd` or `ls`, etc.

In NodeJs you have the option to create CLI commands that can be run only from NPM scripts, remember `npm run <script name>`? 
A good example of this is `tsc` or `babel` or `webpack` that unless installed globally (and added to the path) they can be only 
summoned from inside a script from the `scripts` section in the `package.json`.

We will need [NodeJs](https://nodejs.org/en/) and NPX installed as a global package for the rest of the article. Any NodeJs > v5.0 should have NPX already installed but if it doesn't work you can always run `npm install -g npx`.

From [NPX's Github page](https://github.com/npm/npx), we can get the following command to run in a terminal: `npx github:piuccio/cowsay JavaScript FTW!`. 
It should prompt us with something like this: ```
 _________________
< JavaScript FTW! >
 -----------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
```
This command installed the package in a temporary folder and run the command with the same name as the repository. 

Just to mention the `npx cowsay JavaScript FTW!` command will work just fine because the package exists on NPM as well.

As we just covered how to use it, next we should learn how to write a command that can be used from the CLI (or using NPM).

To save some time I will list the instructions:
* Create a new folder
* Open a terminal in the folder
* `package.json` - for that we use can use `npm --init` and accept the defaults or customize the inputs like name, description, license, etc.
* Create the main file of the application - create, let's say, a file named `index.js`
* In the `package.json` we will add the commands section:
```
"bin": {
        "awesome-command": "index.js",
    }
```
* Add in the `index.js` on the first line `#!/usr/bin/env node`
For example:
```
#!/usr/bin/env node
console.log("Awesome Command");
```
* Good job, now if we publish the package and install it, we will be able to use it, but... Let's say we are in a hurry and we just want to see if it works, so, what can we do? We `npm link`. This command will add it to the global packages like it would have installed it with the `-g` flag.

* Run `awesome-command` from any terminal and it will print `Awesome Command`

Sooo, how does the NPX helps? We already are able to run the command from any terminal. Well, that is true, but only now and definitely not always. 

If we would have installed the package locally, then we wouldn't have been able to run `awesome-command` in a terminal and expect it to work. We would have had to add it to the `scripts` section in the `package.json` like this:
```
"scripts": {
    "awesome": awesome-command
  },
```
and then `npm run awesome` or... run `npx awesome-command`.

Now comes the good part, what if we want to make the command available over the internet?

Well then we publish the npm package and anyone can choose to 
`npm -install <package>` it or `npx <package>`. Remember only to have one of the commands match the name of the package. 

But what if we don't want to publish the package? 
Then we can just host the package on Github in a new repository and anyone will be able to install it using `npm -install user/<repository>` or run it using `npx github:<user>/<repository>`. Again remember to have one of the commands in the `bin` section match the name of the repository.

Ending thoughts, if the command accepts extra arguments we can always add them after the command name, for example `npx github:<user>/<repository> arg1 arg2`.

I hope you enjoyed reading the article as much as I enjoyed writing it.