What is PNPM?

Performant NPM PNPM is a modern package management tool called Performant NPM.

Why use PNPM?

The p in PNPM stands for high performance, so the reason for using it is fast! Compared with yarn/ NPM, PNPM has significantly improved the performance of the two commonly used package management tools. According to the benchmark data provided by the authorities, PNPM is about twice faster than NPM/YARN in some comprehensive scenarios:

How do I use PNPM?

The installation

Install via NPM

npm install -g pnpm
Copy the code

Install via NPX

npx pnpm add -g pnpm
Copy the code

Installing on YARN

yarn add pnpm -g
Copy the code

use

Sense PNPM syntax combines NPM and YARN hahaha. Common commands are described in the following table:

Yarn command NPM command PNPM command
yarn npm install pnpm install
yarn add npm i [pnpm add ]
yarn npm run [pnpm ]

Why is PNPM fast?

why

This is because of a mechanism in computers called Hard Link, which allows users to find a file using different path references. PNPM stores the hard links **** of the project node_modules file in the global store directory.

For example, there is a 1MB dependency a in the project. In PNPM, it looks like this dependency takes up 1MB of both the node_modules directory and 1MB of the global store directory (adding up to 2MB). But because the hard Link mechanism allows the same 1MB space in two directories to be addressed from two different locations, the A dependency actually only takes 1MB of space, not 2MB.

In simple terms, PNPM makes use of cache. When installing a dependency, PNPM looks for the existing dependency packages in the store. If the dependency packages exist, PNPM directly uses the dependency packages in the Store.

The Store directory

${os.homedir}/. Pnpm-store = ${os.homedir}/. Pnpm-store = ${os.homedir}/. Pnpm-store = ${os.homedir}/.

const homedir = os.homedir() if (await canLinkToSubdir(tempFile, homedir)) { await fs.unlink(tempFile) // If the project is on the drive on which the OS home directory // then the store  is placed in the home directory return path.join(homedir, relStore, STORE_VERSION) }Copy the code

Of course, the user can also set the store directory location in.npmrc, but generally speaking, the store directory is relatively little perceived by the user.

Because of this mechanism, every time a dependency is installed, if it is the same dependency that is used by many projects, it is actually optimal (that is, the same version) to install only once.

If it is NPM or YARN, this dependency is used in multiple projects and is re-downloaded each time it is installed.

If a dependency exists in the sotre directory, the dependency will be hard-linked directly from the store directory to avoid the time consumed by the secondary installation. If the dependency does not exist in the Store directory, the dependency will be hard-linked directly from the store directory to avoid the time consumed by the secondary installation. I’ll download it once.

What if store files are too large

Of course, you might have a question here: If you install many, many different dependencies, does the Store directory get bigger and bigger?

The answer is, of course, there are, in view of this problem, the PNPM provides a command to solve this problem: PNPM store | PNPM.

This command also provides an option to use the PNPM store prune, which provides a way to remove packages that are not referenced by the global project. For example, [email protected] is referenced by a project. However, some modification caused the package to be updated to 1.0.1 in the project, so the 1.0.0 axios in the store became an unreferenced package, which can be removed from the store by executing the PNPM Store prune.

It is recommended to use this command occasionally, but not too often, because one day the unreferenced package may be referenced by a project, so you don’t have to download it again.

Node_modules structure

In PNPM website has a very classic article, introduce about PNPM node_modules structure: the Flat node_modules is not the only way | PNPM.

In this article, we introduced some of the file structures for node_modules in PNPM. For example, if you install a dependency called Express in your project using PNPM, you end up with two directory structures in node_modules:

node_modules/express/... Node_modules/PNPM/[email protected] / node_modules/XXXCopy the code

Node_modules: node_modules: node_modules: node_modules: node_modules: node_modules: node_modules:

▾ express
    ▸ lib
      History.md
      index.js
      LICENSE
      package.json
      Readme.md
Copy the code

In fact, this file is just a soft link, forming a soft link to a second directory (similar to a software shortcut) so that Node will eventually find the contents of the.pnpm directory while searching for a path.

PNPM is a virtual disk directory, and some of the express dependencies will be tiled into the.pnpm/[email protected]/node_modules/ directory, so that the dependencies can require, It also does not create a deep level of dependency.

In addition to ensuring that NodeJS can find dependency paths, it also largely ensures that dependencies are kept together.

PNPM has extremely strict distinction requirements for dependencies of different versions. If a dependency in a project actually depends on peerDeps in a specific version, there will be a strict distinction in the virtual disk directory. PNPM for details, please refer to: PNPM. IO/how peers – a… This article.

In summary, PNPM’s node_modules structure is essentially a mesh + tiled directory structure. This dependency structure is mainly based on the soft link (symlink) approach to complete.

Symlink and Hard Link mechanisms

PNPM uses hardlink to store node_modules in the hardlink global directory. Then reference dependency is through symlink to find the corresponding virtual disk directory (.pnpm directory) dependency address.

When the two work together, if a project relies on [email protected] and [email protected], the resulting node_modules structure might look something like this:

├ ─ imp // sci-imp/sci-imp/sci-imp/sci-imp/sci-imp/sci-imp/sci-imp/sci-imp/sci-imp/sci-imp/sci-imp/sci-imp / The PNPM/[email protected] / node_modules/foo └ ─ ─ the PNPM ├ ─ ─ [email protected] │ └ ─ ─ node_modules │ └ ─ ─ bar - > < store > / bar │ ├ ─ ─ index. The js │ └ ─ ─ package. Json └ ─ ─ [email protected] └ ─ ─ node_modules └ ─ ─ foo - > < store > / foo ├ ─ ─ index. The js └ ─ ─ package. The jsonCopy the code

The bar and foo directories in node_modules are soft-wired to real dependencies in the.pnpm directory, which are stored in the global store directory via hard link.

The current scenario is not applicable

compatibility

Are methods like Hard Link and Symlink compatible on all systems?

In fact, hard Link can be used on mainstream systems (Unix/Win) without problems, but symlink (soft connection mode) may have some compatibility problems on Windows, but PNPM also provides a corresponding solution to this problem:

Use a feature called “Soft connection” for Windows, which is more compatible than Symlink.

You may also wonder why PNPM uses Hard Links instead of symLink for all of its implementation.

In fact, dependencies in the store directory can also be found via soft links. Nodejs itself provides an argument called — preserve-Symlinks to support Symlink. But the fact that this parameter does not actually support Symlink well caused the author to abandon the scheme and use hard Links instead:

For details, see github.com/nodejs/node… The issue discussion.

The main issue with PNPM is compatibility issues with symlink in some scenarios. Please refer to discussion: github.com/nodejs/node…

In it, the author mentioned some scenarios where nodeJS soft connection is not applicable at present, hoping nodeJS can provide a link mode instead of using soft connection, and also mentioned the scenarios where PNPM cannot be used because of soft connection at present:

  • Electron application cannot use PNPM
  • Applications deployed on lambda cannot use PNPM

Refer to the link

pnpm.io/zh/

zhuanlan.zhihu.com/p/404784010