Skip to content

pnpm package manager

About 1286 wordsAbout 4 min

node

2022-05-10

pnpm is a new package manager that has faster installation speeds compared to npm and yarn, while saving disk space.

introduce

pnpm

pnpm is a package manager similar to npm and yarn.

The packages installed by pnpm will be stored in the same location on the hard disk. The soft-Ar package will be hard-linked to this location to realize the dependency of sharing the same version. For different versions of the same dependency, when pnpm update, the new version updated files are added to the storage center, rather than just copying the contents of the new version package for changes in one file.

pnpm has built-in support for monorepo, that is, a single warehouse with multiple packages.

Compare

pnpm/yarn/npm

| Features | pnpm | yarn | npm | | ------------------------------- | :----------------------------: | :----------------: | :----------------------: | --- | | Workspace support (monorepo) | ✔️ | ✔️ | ✔️ | ✔️ | | Quarantine node_modules | ✔️ - Default | ✔️ | ❌ | | Promoted node_modules | ✔️ | ✔️ | ✔️ - Default | | Automatic installation of peers | ✔️ - auto-install-peers=true | ❌ | ✔️ | | Plug'n'Play | ✔️ | ✔️ - Default | ❌ | | Zero Installation | ❌ | ✔️ | ❌ | | Fix dependencies | ✔️ | ✔️ | ❌ | | Manage nodejs version | ✔️ | ❌ | ❌ | | Locked file | ✔️ - pnpm-lock.yaml | ✔️ - yarn.lock | ✔️ - package-lock.json | | Support coverage | ✔️ | ✔️ - resolutions | ✔️ | | Content addressable storage | ✔️ | ❌ | ❌ | | Dynamic Package Execution | ✔️ - pnpm dlx | ✔️ - yarn dlx | ✔️ - npx | | Side-effects cache | ✔️ | ❌ | ❌ |

the difference

Unlike yarn/npm, pnpm does not use flat node_modules to manage dependencies. Instead, it is a node_modules structure based on symbolic links.

Each file in each package in node_modules is a hard link from the content addressable storage. Suppose there is a foo@1.0.0 dependency on bar@1.0.0 installed. pnpm will hard link two packages to node_modules as follows:

node_modules
└── .pnpm
 ├── bar@1.0.0
 └── node_modules
 └── bar -> <store>/bar
 ├── index.js
 └── package.json
 └── foo@1.0.0
 └── node_modules
 └── foo -> <store>/foo
 ├── index.js
 └── package.json

This is the only "real" file in node_modules. Once all packages are hard-linked to node_modules, Symbol links are created to build a nested dependency graph structure.

bar will be symbolically linked to the foo@1.0.0/node_modules folder, and then process the dependencies, foo will be symbolically linked to the node_modules folder in the root directory:

node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
 ├── bar@1.0.0
 └── node_modules
 └── bar -> <store>/bar
 └── foo@1.0.0
 └── node_modules
 ├── foo -> <store>/foo
 └── bar -> ../../bar@1.0.0/node_modules/bar

The advantage of this layout is that only packages that are truly in dependencies can be accessed. If it is a tile node_modules structure, all promoted packages can be accessed.

Advantages

  • Save disk space

The package is stored in global storage, pnpm creates a hard link from the global storage to the node_modules folder under the project, which points to the same location where the original file is located on the disk. Different software packages can share the space occupied by the same dependencies.

If it is a different version of a single dependency, such as version update, pnpm only installs the updated version files, rather than installing the entire new version of the package in full.

  • Fast installation speed

When installing a dependency in a package, if the dependency has been installed in the local global storage, it will not be reinstalled from the network, but will directly create a hard link to the package.

  • Built-in support monorepo

Supports single warehouse multiple packages, configure workspaces through pnpm-workspace.yaml, and reference workspace dependencies through workspace:* protocol.

Install

Install via npm

npm install -g pnpm

Install via Corepack

Starting in v16.13, Node.js released Corepack to manage the package manager. This is an experimental feature, so it needs to be enabled by running the following script:

corpack enabled

This will automatically install pnpm on the system. However, it may not be the latest version of pnpm. To upgrade, check Latest pnpm version and run:

corepack prepare pnpm@<version> --activate

Install using standalone scripts

On POSIX systems, you can use the following script to install pnpm even if Node.js is not installed:

curl -fsSL https://get.pnpm.io/install.sh | sh -

If you do not have curl installed, you can also use wget:

wget -qO- https://get.pnpm.io/install.sh | sh -

On Windows systems, if using Powershell:

iwr https://get.pnpm.io/install.ps1 -useb | iex

Install using Homebrew

brew install pnpm

Install using Scoop

scoop install nodejs-lts pnpm

use

pnpm is not much different from npm and yarn in use, but the difference that needs to be paid attention to is that pnpm will strictly verify all parameters. For example, pnpm install --target_arch x64 will fail because --target_arch x64 is not a valid parameter for pnpm install.

Common Commands

pnpm install

Alias ​​pnpm i

Equivalent to npm install / yarn

Used to install all dependencies of the project.

pnpm install official document

pnpm add <pkg>

Install the package and any packages it depends on. By default, any new package is installed as a production dependency.

pnpm add official document

pnpm remove

Alias: rm uninstall un

Remove related packages from node_modules and project's package.json.

pnpm remove official document

pnpm update

Alias: up upgrade

pnpm update updates the latest version of the package according to the specified range.

When used without parameters, all dependencies are updated. There are some patterns you can use to update specific dependencies.

pnpm update official document

For more commands, please refer to official document

Configuration

.npmrc

pnpm gets its configuration from the command line, environment variables, and .npmrc files.

The pnpm config command can be used to update and edit the contents of user and global .npmrc files.

The four related documents are:

  • Configuration file for each project (/path/to/my/project/.npmrc)
  • Configuration files for each workspace (directory containing the pnpm-workspace.yaml file)
  • Profile for each user (~/.npmrc)
  • Global configuration file (/etc/.npmrc)

pnpm-workspace.yaml

pnpm-workspace.yaml defines the root directory of the workspace and enables the workspace to include/exclude directories. By default, all subdirectories are included.

packages:
  # Define all subdirectories in the packages directory as one package
  - 'packages/*'
  # Define all subdirectories in the components directory as a package
  - 'components/**'
  # Exclude all directories under the test directory in any directory
  - '!**/test/**'

Workspace

pnpm has built-in support for a single repository (also known as a multi-package repository, multi-project repository, or monolithic repository), and you can create a workspace to merge multiple projects into a single repository.

A workspace root must have a pnpm-workspace.yaml file, or a .npmrc file.

Workspace protocol (workspace:)

By default, if available packages match the declared available range, pnpm will link these packages from the workspace. For example, if there is this dependency of "foo":"^1.0.0" in bar, then foo@1.0.0 is linked to bar. However, if there is "foo": "2.0.0" in the dependency of barandfoo@2.0.0does not exist in the workspace,foo@2.0.0will be installed fromnpm registry`. This behavior brings some uncertainty.

Fortunately, pnpm supports the workspace protocol workspace:. When using this protocol, pnpm will refuse to parse anything other than the package contained in the local workspace. Therefore, if set to "foo": "workspace:2.0.0", the installation will fail because "foo@2.0.0" does not exist in this workspace.

Example of usage:

The following items exist in the workspace:

+ packages/
 + foo/
 + bar/
 + qar/
 + zoo/

If individual projects take their directory name as their package name, then dependencies can be introduced in other projects as follows:

{
  "dependencies": {
    "foo": "workspace:*",
    "bar": "workspace:~",
    "qar": "workspace:^",
    "zoo": "workspace:^1.5.0"
  }
}

Tips

The package name that introduces dependencies is determined by the package package.json name, not the directory name under the workspace directory.

Publish Workspace

When the above example is published, it will be converted to

{
  "dependencies": {
    "foo": "1.5.0",
    "bar": "~1.5.0",
    "qar": "^1.5.0",
    "zoo": "^1.5.0"
  }
}

This feature allows you to publish converted packages to the remote end and can use packages in the local workspace normally without any other intermediate steps. Package users can also use it normally like regular packages and can still benefit from semantic versions.