From Scratch - NPX
In this new article of the 'From Scratch' series, we will dissect the NPX tool.
The NPX tool is a command-line utility automatically installed when we install Node.js and NPM on our machine. It allows us to easily run NPM modules without having to install them manually. Below is an example that initializes a new Angular project using the @angular/cli
module:
npx @angular/cli new App
But if we take a closer look at its source code, this tool is essentially a simple rewriting utility. In fact, its only purpose is to regenerate an npm exec
command corresponding to the action we want to perform. In this article, we’ll try to understand how it works.
In Node.js, to access the arguments passed to the command line, we work with the argv
array. This array contains, as its first element, the executable used (in our case Node.js), and as its second element, the actual command: here, npx
.
As mentioned earlier, npx
is simply a rewriting tool. To achieve this, we just need to modify the argv
array so that it matches what the npm exec
command expects. We will:
- Replace the second element of
argv
to point to the NPM CLI script - Insert the string
exec
as the third argument
#!/usr/bin/env node
process.argv[1] = require.resolve("./npm-cli.js");
process.argv.splice(2, 0, "exec");
If we look at the documentation for the npm exec
command, here’s how it should be used to execute the same @angular/cli
module:
npx exec -- @angular/cli new App
Not a huge difference, apart from the --
. So, we’ll add that to our argv
array:
#!/usr/bin/env node
process.argv[1] = require.resolve("./npm-cli.js");
process.argv.splice(2, 0, "exec");
process.argv.splice(i, 0, "--");
And that’s it. We now just need to pass this modified process
object to the NPM CLI script so it can be executed:
#!/usr/bin/env node
const cli = require("../lib/cli.js");
process.argv[1] = require.resolve("./npm-cli.js");
process.argv.splice(2, 0, "exec");
process.argv.splice(i, 0, "--");
cli(process);
You might be thinking: is that really all? Well, yes. The script also includes some logic to transform the options so they match what NPM expects. But in my day-to-day usage, the few lines above are already sufficient to understand how NPX works internally.
You can find the complete source code of this tool in the NPM GitHub repository, which includes the part responsible for “translating” the command-line options.