- package manager for JavaScript packages
- default package manager for Node.js runtime environment
- centralised registry of JavaScript packages
Creating packages
package.json
- contains package metadata as object, e.g. name, version, author, dependencies etc.
- can create interactively using
npm init
name
property
- package name, short but descriptive
- must be URL-safe characters, all lower-case, not start with underscore or dot
- must be unique in npm registry if package is unscoped
version
property
- package version
- follows semver (semantiv versioning) system
Release type | Version number | Convention |
---|---|---|
Patch | ~1.1.x | bug fix, backward compatible |
Minor | \^1.x.y | new features, backward compatible |
Major | x.y.z | changes that break backward compatibility |
- changes to the package should come with changes to the version
- no guarantee that other packages adhere to semver convention, i.e. a dependency of your package could introduce a non-backward compatible change in a minor or patch release, could break your package at any moment ⚠️
main
property
- sets
.js
to be used when package is required
bin
property
- sets
.js
to be used if package is invoked as script from command line - script must have proper shebang to be invoked with Node instead of as script
#!/usr/bin/env node
dependencies
property
- specifies packages the package depends on
- are installed along when the package itself is installed, i.e. for each usual user
devDependencies
property
- specifies packages the package depends on
- are installed only when executing
npm install
inside the package, i.e. not for usual user
index.js
- default file to be used as executable of the package
- can be named differently as long as specified in
main
property inpackage.json
'use strict';
/* ... */
module.exports = func1;
Set version number
npm version <semantic-version>
- shortcut in editing version attribute in .json
Publish
npm publish
goes to https://npmjs.com/package/<package>
- by default is tagged with latest, can tag as beta, etc.
Deprecate
npm deprecate <package-name>@<version> "<message>"
<version>
is optional, latest by default ???
Using packages
Other commands
npm list / ls
npm search
Installation
npm install / i <package-name>@<version>
- can specify version ranges of semver, see semver.org
- version is optional, latest is used by default, if inside another package and the package is inside
package.json
then this version is used by default - if inside another package, i.e. with
package.json
, automatically adds package topackage.json
, use--save-dev
to add only as dev dependency, uses minor version range ”\^” by default - if inside another package and no package-name is supplied, installs all packages as specified in
package.json
, if--production
flag then only the non dev dependencies, ifpackage-lock.js
is present it is used instead ofpackage.json
, i.e. guarantees exact dependency tree - by default installs package(s) locally in
./node_modules
and bins into./node_modules/.bin
within current folder or if inside package in root of package, in that folder can require in .js file or run withnpx
from command line -g
installs package(s) globally in<node-path>/lib/node_modules
and bins into<node-path>/bin
where, e.g./usr/local/
, can run in command line from anywhere
NPM Dependency Model
- installing a packages creates a dependency tree, each package has own dependencies, those get installed in the packages’ own
node_modules
directories, and the dependencies have their dependencies etc. pp. - this allows two multiple packages to have different versions of same dependency, no dependency conflicts, but problem because dependencies might be duplicated, eat a lot of space, or worse infinite recursion would happen for two inderdependent packages
- NPM puts first package and all its dependencies on top level, second package and all it’s dependencies as well except the duplicate dependencies, different version becomes nested while same versions are simply skipped, also skips if existing version is within specified semver range even though a newer version might be available, i.e. uses “oldest common denominator” of a dependency
- packages can still take up a lot of space, if first package depends on one version of another package, and all following packages on another versions of that other package, because then the first version of the other package occupies already the root level of the
.node_modules
folder, and all other versions need to be nested even if they are the same, it all depends on installation order, i.e. multiple copies of exact same dependencies can exist - even if fixes versions in
package.json
might get different installs on different times because dependencies themselves likely won’t have their dependencies fixed etc., if those dependencies don’t follow semrev guidelines might break the app because new version introduced incompatibility, could have a bug even if fixed own dependencies,npm install
is russian roulette package-lock.js
stores exact versions of whole dependency tree using hashes, is generated automatically as soon as NPM changes the dependency packages, makes dependency tree reproducible, can reproduce exact package regardeless of intermediate dependency updates, package is “locked”, should always be included in source control, but can’t be published with a package since it overwritespackage.json
disabling any intermediate dependency updates, can usenpm-shrinkwrap.json
as “publishablepackage-lock.json
” but not recommended
Update
npm update
- can update specific package, all packages, local, global
- check with npm outdated if update was successful
Dedupe
npm dedupe
- flattens dependency tree as much as possible, moves dependencies up the tree, removes duplicates if found
- doesn’t solve problem that one dependency version blocks many dependency of another version
Uninstall
npm uninstall <package-name>
- uninstall package locally or globally
- remove from (dev) dependency list using —save or —save-dev