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
argvto point to the NPM CLI script - Insert the string
execas 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.