In Progress
Unit 1, Lesson 21
In Progress

Understanding `npm run` (and why to avoid `npx`!)

In today’s episode, guest chef Jessica Kerr returns to dig deeper into how NPM scripts work, and delivers some strong opinions about the npx command!

Video transcript & code

npm. It's more than a package manager.

In episode 614 we used npm to install, track, and run a development-time tool.

I wanted to work on this brilliant web site.

The README recommended running live-server, but

`live

this command didn't even work, and

it wanted us to install the tool globally, ew.

I made it so that after we npm install dependencies, anyone can use npm run serve to execute the correct command.

There, now the README is better.

This command is defined inside package.json, in this 'scripts' tag

Package.json is the first file (after the README) that I look at in a new-to-me JavaScript project. Usually it contains lots of descriptive things too.

But after I clone this project

and install the packages, which includes live-server

npm can run live-server, to serve up the page

but why? where is it?

Let's ask it. Hey npm, where is live-server?

"clue": "which live-server"

npm run clue

Ah-ha, it is here inside this project, inside node_modules/.bin

yep, there it is. Along with some other things, executables defined by packages installed as transitive dependencies.

$ ll live-server
lrwxrwxrwx 1 jessi jessi 29 Dec 24 12:29 live-server -> ../live-server/live-server.js*

It's a link to something in the live-modules package installation.

What causes that?

cd ../live-server cat package.json

We can go look at the project definition for live-server.

...
 "bin": {
    "live-server": "live-server.js"
  },
...

Here the "bin" property defines the link. When you see this in a package.json, you know the project makes a command-line tool.

```> head live-server.js #!/usr/bin/env node ...


This one is a Node script. Defining scripts for `npm run` lets me call executables that are installed by npm.

$ npm run Scripts available in via npm run-script: serve live-server --verbose --ignore=README.md . clue echo $PATH


I like this because I don't have to install them globally on my computer, and expected version is declared in package.json, so it can be consistent between many developers working on a single project.

$ npm run serve -- -v

@ serve /home/jessi/code/satellite-of-love/shavalottayaks live-server --verbose --ignore=README.md . "-v"

live-server 1.2.1


There's a trick for `npm run`. Use `--` to say "pass the rest of these arguments to the script you're about to run.

$ node_modules/.bin/live-server . Serving "." at http://127.0.0.1:8080 Ready for changes


The negative is, if I want to run live-server here some other way, I have to give the path to node_modules bin. There's another way to run the utilities inside your node_modules bin. You could use `npx`.

$ npx live-server . Serving "." at http://127.0.0.1:8080 Ready for changes


npx comes with npm. It will run stuff from your locally installed modules, or your globally installed ones, or your path. But if it doesn't find it there, it will install it from the internet and run it without confirmation. So what if I'm wrong about the name, or make a typo?

$ npx liev-server npx: installed 2 in 1.972s liev-server running from /home/jessi/.npm/npx/13001/lib/node_modules/liev-server/index.js ____ _ | __ ) ___ ___ | | | _ \ / _ \ / _ | | | |) | () | () || |____/ ___/ ___/()


It just downloaded a module that anybody can publish to npm, and it ran it. This happens to be one that I created and published today. it says boo. it also tells me where it ran from. Let's look at that file, to see if it does anything else.

$ cat /home/jessi/.npm/_npx/13001/lib/node_modules/liev-server/index.js cat: /home/jessi/.npm/_npx/13001/lib/node_modules/liev-server/index.js: No such file or directory


Oh, it has deleted it. I don't even know what was run on my computer. I find this completely unacceptable. Do not use npx. or if you do, use it with the --no-install option.

$ npx --no-install liev-server not found: liev-server


In fact, I think I'll alias npx so that I never accidentally use it.

$ alias npx='npx --no-install' $ npx liev-server not found: liev-server ```

npm run good, npx bad.

And that's all I have to say about npm today. Happy Hacking!

Responses