# npm Learn how to use [npm][npm], the most popular [Node.js][node] package manager, and the largest code registry in the world with over a quarter million packages. This material is part of [web development courses](https://github.com/MediaComem/comem-webdev) for [Media Engineering](https://heig-vd.ch/formations/bachelor/filieres/ingenierie-des-medias). **You will need** * A Unix CLI **Recommended reading** * [Command line](../cli/) * [Node.js](../node/) --- class: center, middle ## What is npm? .breadcrumbs[
npm
] > "npm is the **package manager** for JavaScript. Find, share, and reuse packages of code from hundreds of thousands of developers — and assemble them in powerful new ways." --- ### Why use a package manager? .breadcrumbs[
npm
>
What is npm?
] * Use code or applications that **other developers** have written to solve particular problems * Regularly check if there are any **upgrades** and download them * **Share** your own code with the community or **reuse** code across projects
--- ### There are many package managers .breadcrumbs[
npm
>
What is npm?
] For programming languages: | Package manager | Language | | :--- | :--- | | Composer | PHP | | Maven | Java | | npm | Node.js | | RubyGems | Ruby | | pip | Python | For operating systems: | Package manager | OS | | :--- | :--- | | Advanced Package Tool (apt) | Debian, Ubuntu | | Homebrew (brew) | Mac OS X | | Yellowdog Updater, Modified (yum) | RHEL, Fedora, CentOS | --- ### The npm registry .breadcrumbs[
npm
>
What is npm?
] > "The [npm registry][npm] hosts over a quarter million packages of reusable code — the largest code registry in the world."
--- ### npm packages .breadcrumbs[
npm
>
What is npm?
] An npm **package** or **module** is basically a **reusable piece of code** that you can install and use. It's composed of: * A directory with some files in it (what will be installed) * A [package.json][package.json] file with some metadata about the package: ```json { "name": "my-project", "version": "1.3.2", "description": "It's great", "main": "index.js", "scripts": { "start": "node index.js" }, "dependencies": { "express": "^4.13.3", "lodash": "~3.1.0" }, "keywords": [ "awesome", "project" ], "author": "John Doe
", "license": "MIT" } ``` --- class: center, middle ## The npm command .breadcrumbs[
npm
] npm is also a set of command line tools that work together with the registry. --- ### How do I use it? .breadcrumbs[
npm
>
The npm command
] ```bash $> npm help Usage: npm
where
is one of: access, adduser, bin, bugs, c, cache, completion, config, ddp, dedupe, deprecate, dist-tag, docs, edit, explore, get, `help`, help-search, i, `init`, `install`, install-test, it, link, list, ln, login, logout, ls, outdated, owner, pack, ping, prefix, prune, `publish`, rb, rebuild, repo, restart, root, run, run-script, s, se, search, set, shrinkwrap, star, stars, `start`, stop, t, tag, team, test, tst, un, uninstall, unpublish, unstar, up, update, v, version, view, whoami npm
-h quick help on
npm -l display full usage info npm help
search for help on
npm help npm involved overview ``` --- class: center, middle ## npm init .breadcrumbs[
npm
] Create a new package --- ### Interactively create a package.json file .breadcrumbs[
npm
>
npm init
] Create and move into a new project directory: ```bash $> cd /path/to/projects $> mkdir npm-demo $> cd npm-demo ``` Run `npm init`: ```bash $> npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. ... Press ^C at any time to quit. name: (npm-demo) version: (1.0.0) description: npm demo entry point: (index.js) test command: git repository: keywords: npm, demo author: John Doe
license: (ISC) ``` --- ### What it looks like .breadcrumbs[
npm
>
npm init
] ```json { "name": "npm-demo", "version": "1.0.0", "description": "npm demo", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "npm", "demo" ], "author": "John Doe
", "license": "ISC" } ``` Read the [documentation][package.json] to find out everything you can configure in this file. --- class: center, middle ## npm install .breadcrumbs[
npm
] Install a package --- ### Installing packages .breadcrumbs[
npm
>
npm install
] When you install a package with the `npm install` command, npm creates a `node_modules` directory in the current working directory. It then saves the downloaded packages in that directory: ```bash $> npm install lodash npm-demo@1.0.0 /path/to/projects/npm-demo └── lodash@4.17.4 $> ls node_modules package.json package-lock.json $> ls node_modules lodash ```
--- ### Using installed packages .breadcrumbs[
npm
>
npm install
] Any script that is in the same directory as `package.json` and `node_modules` can `require()` the installed packages: Create a `script.js` file in the project and run it:: .grid-60[ ```js const lodash = require('lodash'); let numbers = [ 1, 1, 2, 3, 2 ]; console.log(lodash.uniq(numbers)); ``` ] .grid-40[ ```bash $> node script.js [ 1, 2, 3 ] ``` ] .container[ You have used the `uniq` function from the `lodash` package, which returns an array with its duplicate elements removed.
] --- ### Tracking installed packages .breadcrumbs[
npm
>
npm install
] Now remove the `node_modules` directory: ```bash rm -fr node_modules ``` Your script should no longer work since the `lodash` package is no longer available: ```bash $> node script.js module.js:471 throw err; ^ Error: Cannot find module 'lodash' ``` Deleting the `node_modules` directory is not a common real-world scenario, However, it can get quite large, so most people have it in their `.gitignore` file in their Git repositories, since you just have to run `npm install` to get your dependencies back. That means that when **cloning** your project, your colleagues **won't** get the `node_modules` directory. --- #### Re-installing dependencies manually .breadcrumbs[
npm
>
npm install
>
Tracking installed packages
] .grid-80[ You could reinstall all these packages manually, but imagine that you have **dozens** of dependencies. Do you want each team member to **re-type** the same `npm install` commands all the time? This is the typical list of dependencies for a **barebones** Express web application: ] .grid-20[
] --- ### npm saves the dependencies to package.json .breadcrumbs[
npm
>
npm install
] npm automatically tracks the dependencies you install. There is a `--save` option that was required for that in earlier versions, but it's the default now. When you ran `npm install`, a new `dependencies` section should have appeared in your `package.json` file:
--- ### npm install with a package.json .breadcrumbs[
npm
>
npm install
] Delete the `node_modules` directory again and simply run `npm install` with no other arguments: ```bash $> rm -fr node_modules $> npm install npm-demo@1.0.0 /path/to/projects/npm-demo └── lodash@4.17.4 ``` npm has installed the `lodash` package again. If you **don't specify a package** to install, the install command will **read** the `package.json` and **install the dependencies** listed there. .grid-40[ The `package-lock.json` also contains the precise versions of the packages you installed. That way, your entire team can reproduce the exact same package structure as on your machine. ] .grid-60[
] --- ### The --save-dev option .breadcrumbs[
npm
>
npm install
] You often use two kinds of packages: * **Production dependencies** that your program or application needs to run (e.g. a database client) * **Development dependencies** that you use during development but do not need to run the application (e.g. a live-reload server) .grid-45[ Use the `--save-dev` option to save your development dependencies: ```bash $> npm install --save-dev gulp ``` A `devDependencies` section will be added to your `package.json`: ] .grid-55[
] --- ### The --production option .breadcrumbs[
npm
>
npm install
] .grid-45[ Use `npm install` with no arguments when you want to install **all dependencies**, including development dependencies: ```bash $> npm install ```
] .grid-55[ Use the `--production` option to install **only production dependencies** (e.g. on a server, where you will only need to *run* your program and will not need your development tools): ```bash $> npm install --production ```
] --- ### The --global option .breadcrumbs[
npm
>
npm install
] Some packages can be installed **globally**. Use the `--global` or `-g` option: ```bash $> npm install --global http-server ``` **If you get an `EACCES` error**, execute the following commands: ```bash $> mkdir ~/.npm-global $> npm config set prefix '~/.npm-global' ``` And add this line to your CLI configuration file (e.g. `~/.bashrc` or `~/.bash_profile`): ```bash export PATH=~/.npm-global/bin:$PATH ``` Re-open your CLI, then retry the installation, which should work this time: ```bash $> npm install --global http-server ``` --- #### Global packages .breadcrumbs[
npm
>
npm install
>
The --global option
] Global packages are **NOT installed in the current directory**. They are installed in a **system directory** and are **global to your machine** (you don't need to re-install them for each project).
.grid-50[ Global packages provide **new commands** that you can use in your CLI. In this case, the `http-server` package is a simple command-line HTTP server: ] .grid-50[ ```bash $> http-server Starting up http-server, serving ./ Available on: http://127.0.0.1:8080 http://10.178.123.132:8080 Hit CTRL-C to stop the server ``` ] --- #### Where are global packages installed? .breadcrumbs[
npm
>
npm install
>
The --global option
] Use `npm config` to find out where global packages are installed on your machine: ```bash $> npm config get prefix /usr/local $> ls /usr/local/lib/node_modules http-server ``` You *cannot* use `--save` with global packages. You **do not need to** since they are global to your machine and available anywhere in the CLI. However, if you **reset** your machine or Node.js installation, you will have to **reinstall** manually. --- class: center, middle ## Common mistakes .breadcrumbs[
npm
] It happens. --- ### Missing `package.json` file .breadcrumbs[
npm
>
Common mistakes
] If you **forgot to add a `package.json` file** to your project, npm will still install your dependencies and log a warning that is **easy to miss**: ```bash $> npm install --save lodash npm WARN `saveError` ENOENT: no such file or directory, open '/path/to/projects/npm-demo/package.json' /path/to/projects/npm-demo └── lodash@4.17.4 ```
--- ### Wrong directory .breadcrumbs[
npm
>
Common mistakes
] Npm will not know if you are in the **wrong directory**. It will simply **install packages there**. Of course, you will **NOT** be able to `require()` them from your project:
--- class: center, middle ## The behavior of `require()` .breadcrumbs[
npm
] --- ### Requiring your own modules .breadcrumbs[
npm
>
The behavior of `require()`
] You can require your own Node.js scripts with **relative file paths**: .grid-50[
] .grid-50[
] .container[ Beware of **circular dependencies**. In this example, you should do one or the other, **not both**. ] --- ### Requiring packages installed with npm .breadcrumbs[
npm
>
The behavior of `require()`
] You can require packages you installed with npm **by their name**:
--- #### Global packages installed with npm .breadcrumbs[
npm
>
The behavior of `require()`
>
Requiring packages installed with npm
] You **CANNOT** require packages you installed **globally** with npm. They provide **new commands** but cannot be used in code:
--- ### Requiring core Node.js modules .breadcrumbs[
npm
>
The behavior of `require()`
] When you give **a name** to `require()`, it will also look for a **core Node.js modules** with that name:
--- ### Require summary .breadcrumbs[
npm
>
The behavior of `require()`
] Statement | What is required :--- | :--- `require('./script')` | The `script.js` file in the current directory (relative to the file using `require()`) `require('./dir/script')` | The `script.js` file in the `dir` directory (relative to the file using `require()`) `require('../script')` | The `script.js` file in the parent directory (relative to the file using `require()`) `require('my-module')` | The `my-module` npm package (if found in `node_modules` in the same directory *or any parent directory*)
**OR**
The core Node.js module with that name (if there is one) --- ## More complex packages .breadcrumbs[
npm
] The npm registry has many packages, some small, some big. Let's install [Express][express], a web application framework: ```bash $> npm install express ``` Create a `server.js` file with the following content: ```js const express = require('express'); const app = express(); app.get('/', function(req, res) { res.send('Hello ' + req.query.name + '!'); }); app.listen(3000, function () { console.log('Example app listening on port 3000!'); }); ``` --- #### Run a web app .breadcrumbs[
npm
>
More complex packages
] Run the file: ```bash $> node server.js Example app listening on port 3000! ``` Visit [http://localhost:3000?name=World](http://localhost:3000?name=World) in your browser. You have a running web application server! --- class: center, middle ## npm scripts .breadcrumbs[
npm
] npm is not only a package *installer*, it's also a package **manager** --- ### Lifecycle scripts .breadcrumbs[
npm
>
npm scripts
] For programs that can be **long-lived**, such as **web servers**, npm defines **standard lifecycle scripts** that you should use to control your program. Here are a few: Command | Purpose :--- | :--- `npm start` | Run your program `npm stop` | Stop your program `npm restart` | Restart your program `npm test` | Run automated tests for your program Read the [documentation][npm-scripts] to learn about all the available lifecycle scripts. --- ### The scripts property .breadcrumbs[
npm
>
npm scripts
] .grid-40[ In order for your program to **respond** to these `npm start|stop|...` commands, the corresponding **scripts** should be defined in your `package.json` file under the `scripts` property: ] .grid-60[
] .container[ Here we define that running `npm start` should **execute** the `server.js` file with Node.js: ```bash $> npm start > npm-demo@1.0.0 start /path/to/projects/npm-demo > node server.js Example app listening on port 3000! ``` ] --- ### Custom scripts .breadcrumbs[
npm
>
npm scripts
] You can also define your own custom scripts: ```json { "name": "npm-demo", * "scripts": { * "hello": "echo Hello World" * }, ... } ``` These scripts are run with `npm run