Intro To Dependencies, npm, and package.json
Dependencies in javascript projects are ubiquitous.
There are devDependencies: ones that are only needed during development, and not in a production environment.
There are dependencies, the ones needed for a prod env.
These are managed with npm, "the worlds largest software registry".
- Intro To Dependencies, npm, and package.json
A Dependency Is Someone Elses Code
Dependencies are pieces of code that do things, stored in directories, available to consume and use in (y)our projects, and maintained by others.
Devs use dependencies for all types of things and for all sorts of purposes:
- interfacing between rest-api's and databases
- cryptography functions
- "api" frameworks
- "frontend" frameworks
- manage linting & formatting rules
- managing the semantic version implementation
- bundling and transpiling
- interfacing with other third-party vendors (email, logging, payment systems, etc)
NPM, the Node Package manager
npm is a free node module registry overflowing with node modules that perform functionality with easy-to-use apis.
Get Started with npm
Download node and free node package manager command-line-interface (cli) comes included with the node download.
See The npm Manuals
The --help
flag and the -h
flag produce some manual-like details in the cli.
npm help
: npm can begun being investigated with npm help
from the command line.
npm help npm
: for a longer-form manual.
npm help <command-here>
or npm <command-here> -h
: for a manual about a specific command, i.e the install
has a mini-manual at npm install -h
or npm help install
.
package.json Is The Beginning Of A Node Module
a module, or a "package", is a project/directory that includes the package.json
file at the root of the dir.
Here's 2 ways to use the package.json file to being a node module.
First, the "template" way -
- create a directory to hold the thing (lets call ours "blog-demo-repo")
- run
npm init -y
: this will create a package.json file and fill it with some "template" content:
{
"name": "blog-demo-repo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Another approach is to leverage the npm cli for more details:
- create the directory, like above
- run
npm init
and a cli will "walk you through" creating apackage.json
file with more detail.
Also, npm init
can be run on a project that already has package.json
- the cli will ask the same questions, and if there are new answers, the package.json will be updated!
package.json has a bunch of fields
There is an entire doc about the fields in a package.json
file. Here's the fields to get started with:
name
: well, give it a name!version
: a semantic version string that meets the node-semver specs (carets, tildas, etc.)description
: this appears when someone searches for your module through npmmain
: the "entrypoint" of the project - where the code running should start atscripts
: an objects of commands (scripts) that npm can use (with a robust doc to go with it)keywords
: an array of stringsauthor
: this can include an object withname
,email
, andurl
license
: Check out something like choosealicense.com for options to consider - let consumers of the project know what they can and can't do with it
package.json Manages Dependencies And Dependency Versions
Lets install some dependencies & see how the project gets updated.
Using "npm install" to Add New Dependencies
From a cli, run npm install express
. express is a "fast, unopinionated, minimalist web framework for Node.js".
This will ajust the project in a few ways:
- updating package.json
- including a new file, package-lock.json
- including a new directory, node_modules
The package.json
file now includes notes on the dependency:
{
"name": "blog-demo-repo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.2"
}
}
express
is listed as one of the key/value pairs inside the dependencies
array. Here, express is included with any version greater-than or equal 4.8.12
and less than 5.0.0
.
The package-lock.json
is something like a record that documents exact versions of modules, including dependencies of the modules. This file is not intended to be modified by us mere humans - npm will make use of it.
Disabling The Package-Lock
The creation & management of the package-lock file can be disabled by setting package-lock=false
in a file called .npmrc
. The npmrc
file is like a configuration file for npm itself, detailing different and "lower level" content beyond the details in the package.json
.
Create a package-lock manually during package installation with npm i --package-lock
.
The node_modules directory stores the dependency code content.
Specifying The Version Of A Dependency
The latest version of express can be installed with either npm install express
or npm install express@latest
.
A Specific version of express can be installed with npm install express@<Major.minor.patch>
like npm install express@4.0.0
. A flag can be added to only save the exact version, which does not seem to be the default: npm install --save-exact express@4.0.0
.
Include All Patch Updates, which is the last dot of the semver range, which a tilde: npm install ~express@4.0.0
will install the latest 4.0.*
version.
Include All Minor Updates, which is the middle dot of the semver range, which a caret: npm install ^express@4.0.0
will install the latest 4.*.*
version.
Using "npm install" to Install All Dependencies
A common scenario is where developers download a module to work on the module. Perhaps I share the code of blog-demo-repo
with a friend. It is extremely common to keep the contents of the node_modules
directory out of the "shared" version of the project. This is where npm install
comes in.
Run npm install
at the root of the repo, and npm "figures out" what dependencies to install without having to name the dependencies explicitly. As long as a package.json (and potentially a package-lock.json) are present, npm knows what to do.
Using "npm install" to Install Development-Only Dependencies
Some project dependencies can and probably will be development-only dependencies (devDependencies) - things like linters, formatters, bundlers & compilers... things that aren't needed in a production environment.
For frontend projects, where the only goal is to product html+js+css for browsers to consume, all dependenciens might be devDependencies.
To add a dependency as a dev-only dependency, let's take eslint as the example.
Use npm install --save-dev eslint
or npm instal -D eslint
.
Leveraging NPM CLI Commands
There are a bunch of helpful cli commands that npm includes to interact with npm and dependencies.
For example, npm ls
will show dependencies in the cli:
> npm ls
blog-demo-repo@1.0.0 /Users/me/Desktop/blog-demo-repo
└── express@4.18.2
// with a depth of 1
// this will show the project dependencies, as well as 1 "level" deeper (the dependencies of the project dependencies)
// the depth value can reveal a lot at higher values
npm ls --depth=1
blog-demo-repo@1.0.0 /Users/me/Desktop/blog-demo-repo
└─┬ express@4.18.2
├── accepts@1.3.8
├── array-flatten@1.1.1
├── body-parser@1.20.1
├── content-disposition@0.5.4
├── content-type@1.0.5
├── cookie-signature@1.0.6
├── cookie@0.5.0
├── debug@2.6.9
├── depd@2.0.0
├── encodeurl@1.0.2
├── escape-html@1.0.3
├── etag@1.8.1
├── finalhandler@1.2.0
├── fresh@0.5.2
├── http-errors@2.0.0
├── merge-descriptors@1.0.1
├── methods@1.1.2
├── on-finished@2.4.1
├── parseurl@1.3.3
├── path-to-regexp@0.1.7
├── proxy-addr@2.0.7
├── qs@6.11.0
├── range-parser@1.2.1
├── safe-buffer@5.2.1
├── send@0.18.0
├── serve-static@1.15.0
├── setprototypeof@1.2.0
├── statuses@2.0.1
├── type-is@1.6.18
├── utils-merge@1.0.1
└── vary@1.1.2