preface

Generally, the guarantee engineers we contact have NPM, YARN and PNPM. Xiao Qi uses PNPM as a package management tool for almost all new projects in her work. So let’s talk about the benefits of changing to PNPM.

npm

Major changes have been made to NPM from iterations of v1-V3-V5.

NPM v1 nesting

NPM packages in node_modules are nested before v3.

Node_modules ├ ─ ─ A @1.0. 0│ ├ ─ ├ ─ garbage1.0. 0├ ─ ─ C @1.0. 0│ ├ ─ ├ ─ garbage2.0. 0└ ─ ─ D @1.0. 0└ ─ ─ node_modules └ ─ ─ @ B1.0. 0
Copy the code

As projects get bigger and more dependent packages become available, there are also problems.

  • The nested hierarchy deepens and the file path is too long.
  • A large number of packages are repeatedly installed. For example, [email protected] in the above example will be loaded in two copies.

NPM v3 flat

In V3, flat install dependent mode is implemented, with packages in node_modules flat.

Node_modules ├ ─ ─ A @1.0. 0├ ─ ─ @ B1.0. 0└ ─ ─ C @1.0. 0└ ─ ─ node_modules └ ─ ─ @ B2.0. 0├ ─ ─ D @1.0. 0
Copy the code

The changes to NPM V3, while avoiding the problem of deep nesting and repeated installation (note that only one version of multiple packages can be promoted), have a lot of uncertainty (i.e., the generated node_modules structure is uncertain).

For example 🌰 : if [email protected] depends on [email protected] and [email protected] depends on [email protected], what is the generated node_modules structure?

Node_modules ├ ─ ─ A @1.0. 0├ ─ ─ @ B1.0. 0└ ─ ─ node_modules └ ─ ─ C @1.02.├ ─ ─ C @1.01.
// Still the following situationNode_modules ├ ─ ─ A @1.0. 0└ ─ ─ node_modules └ ─ ─ C @1.01.├ ─ ─ @ B1.0. 0├ ─ ─ C @1.02.
Copy the code

Depending on where A and B are in package.json, it could be either.

NPM V5 flat + Lock

To address the uncertainty of the node_modules structure, package-lock.json files are generated by default in v5. Let’s just install the package-lock.json file that corresponds to swiper.

// package.json
{
  "name": "test"."version": "1.0.0"."description": ""."main": "index.js"."license": "ISC"."dependencies": {
    "swiper": "^ 8.0.7"}}// package-lock.json
{
  "name": "test"."version": "1.0.0"."lockfileVersion": 1."requires": true."dependencies": {
    "dom7": {
      "version": "4.0.4"."resolved": "https://registry.npmjs.org/dom7/-/dom7-4.0.4.tgz"."integrity": "sha512-DSSgBzQ4rJWQp1u6o+3FVwMNnT5bzQbMb+o31TjYYeRi05uAcpF8koxdfzeoe5ElzPmua7W7N28YJhF7iEKqIw=="."requires": {
        "ssr-window": "^ 4.0.0"}},"ssr-window": {
      "version": "4.0.2."."resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz"."integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ=="
    },
    "swiper": {
      "version": "8.0.7"."resolved": "https://registry.npmjs.org/swiper/-/swiper-8.0.7.tgz"."integrity": "sha512-GHjDfxSZdupfU7LrSVOpaNaT7R1D2zxopPGBFz1UOXOtsYvVJLg0k6NvkTAD7qn0ASl5pTti82qoYwvYvIkg4g=="."requires": {
        "dom7": "^ 4.0.4." "."ssr-window": "^ 4.0.2." "}}}}Copy the code

The package-lock.json file helps us keep track of each package version installed and the other package versions it depends on so that it can be installed from this file at the next installation. Json files such as package-lock.json and package.json ensure that the node_modules directory structure is always consistent, thus ensuring the certainty of installation dependencies.

yarn

yarn 1

Yarn1 was introduced to solve problems with NPM V3, at that time there was no NPM V5. The node_modules directory generated by yarn install has the same structure as NPM V5, and a yarn.lock file is generated by default. The certainty of yarn installation dependencies is guaranteed as long as the version of YARN is the same.

As in the previous example, the yarn.lock file generated by installing swiper using YARN is as follows:

# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
​
​
dom7@^4.04.:
  version "4.0.4"
  resolved "https://registry.npmjs.org/dom7/-/dom7-4.0.4.tgz#8b68c5d8e5e2ed0fddb1cb93e433bc9060c8f3fb"
  integrity sha512-DSSgBzQ4rJWQp1u6o+3FVwMNnT5bzQbMb+o31TjYYeRi05uAcpF8koxdfzeoe5ElzPmua7W7N28YJhF7iEKqIw==
  dependencies:
    ssr-window "^ 4.0.0"
​
ssr-window@ ^4.0. 0, ssr-window@ ^4.02.:
  version "4.0.2."
  resolved "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz#dc6b3ee37be86ac0e3ddc60030f7b3bc9b8553be"
  integrity sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==
​
swiper@^8.07.:
  version "8.0.7"
  resolved "https://registry.npmjs.org/swiper/-/swiper-8.0.7.tgz#9eefe26c703e627a6dc7237c0109e172ce06e3f6"
  integrity sha512-GHjDfxSZdupfU7LrSVOpaNaT7R1D2zxopPGBFz1UOXOtsYvVJLg0k6NvkTAD7qn0ASl5pTti82qoYwvYvIkg4g==
  dependencies:
    dom7 "^ 4.0.4." "
    ssr-window "^ 4.0.2." "Copy the code

Comparing the yarn.lock file with the package-lock.json file, we can see several differences:

  • Package-lock. json is different from yarn.lock format.

  • In NPM V5, only package-lock.json is required to ensure the correct node_modules directory structure, whereas yarn requires both yarn.lock and package.json files. (See the certainty of Yarn)

When using YARN as a package management tool, we also need the following points:

  • Yarn. lock is automatically generated. Do not manually change it
  • Upload the yarn.lock file to Git
  • Used when upgrading dependenciesyarn upgradeDo not manually modify the package.json and yarn.lock files
  • Do not delete the lock file, the whole reinstall. This will cause locked versions to be released, executeyarn installJson version range defined in package.jsonThe latest version, which may cause unexpected dependencies to be updated, possibly introducing bugs.

yarn2

Yarn2 is available in node_modules mode, which speeds up project installation while greatly reducing the speed of deleting an entire project. [Here by the way to mention a mouth, but more introduction 🤡]

npm install -g yarn@berry
Copy the code

pnpm

PNPM (Perfomance NPM) is a modern package management tool with great performance improvements.

The basic use

npm install -g pnpm // Install PNPM globally
​
pnpm add axios // Add to Dependencies
pnpm add axios -D   // Add to devDependencies
pnpm add -O [package] // Save to optionalDependencies
​
pnpm update  / / update
​
pnpm remove/uninstall / / delete
​
pnpm dlx  // Get the package from the source without installing it as a dependency, hot load it, and run any default command binaries it exposes.
​
pnpm link // Connect the local project to another project, in this case hardwired.
Copy the code

The basic features

  • Local installation speed: 2-3 times faster than NPM or YARN.
  • Efficient utilization of disk space: do not install the same package repeatedly even if the version is different.
  • High security: Avoids the risks of NPM/YARN illegal access dependencies and doppelgangers

How does PNPM improve performance?

In a word: PNPM uses the hard Link mechanism when installing dependencies, which allows users to find a file through different paths. PNPM stores the hard link to node_modules files in the global store directory.

Here are a few concepts: Hard Link, SymLink, and the global Store directory.

What are Hard Link and Symlink

It’s all essentially file access.

Hard link: If A is A hard link of B, then an indexNode of A points to the same pointer as an indexNode of B. Deleting either does not affect access to the other. Function: Allows a file to have multiple valid paths so that users can avoid deleting files by mistake.

Symlink (soft link or symbolic link) : Similar to desktop shortcuts. For example, A is the soft connection of B (both A and B are file names). The IndexNodes of A and B are different, but A is only the path to store B. When accessing A, the system will automatically find B. Deleting A has no effect on B, on the contrary, deleting B, A still exists, but it points to an invalid link.

The store directory

${os.homedir}/.pnpm-store/v3/files. PNPM stores the hard link of node_modules files in the global store directory, so when installing the same dependency in different projects, you don’t need to download it every time, you only need to install it once, avoiding the consumption of secondary installation. NPM and YARN need to be downloaded and installed again to be used in different projects.

The Store directory will also be used as the number of installed packages growspnpm store pruneCommand to delete packages that are no longer referenced. (Not recommended for frequent use)

PNPM mesh + tiled node_modules structure

When you install swiper using PNPM, a pnpm-lock.yaml file is automatically generated. Next, let’s look at how the node_modules structure in PNPM differs from NPM and YARN.

After the swiper package is installed, there are two directories in the root node_modules. One is the. PNPM virtual disk directory. Another swiper directory, the normal Node require path, this swiper we call swiper soft chain. PNPM /[email protected]/node_modules/swiper. This file is called the hard link of swiper. Will actually link to the global store.

Symlink was not used instead of Hard Link due to compatibility issues. Node.js provides a preserve-Symlinks parameter to support Symlink. However, this parameter does not support Symlink well, so the author abandoned it.

Common problems between NPM and YARN

NPM and YARN also implement package parity in installation dependencies, but there are still two problems: Phatom and Doppelgangers.

  • Phatom (illegal access dependency) : only A is declared in package.json. The depdencies of A have B, so B will also be installed when installed in A, and the project can still require B.
  • Doppelgangers: Different versions of a package will still be installed twice (you can’t flatten different versions of the same package), can cause the same package to be installed twice and still lose performance.

PNPM is a virtual disk directory that users can’t require. PNPM is a virtual disk directory that users can’t require. Secondly, PNPM installation dependencies always exist in the global Store directory hard links, a different dependency is always installed once.

Unique features of PNPM

In addition to solving the common problems of NPM and YARN, PNPM has the following unique features.

  • Manage node.js versions: In the.npmrc file, you can configure the Node version to run the project. PNPM will automatically install the specified version of Node.js and use it for executionpnpm runCommand orpnpm nodeCommand. (refer tonpmrc)
  • Content Addressable storage (CAS) : A storage mechanism in which fixed data is assigned a permanent location on hard disk and addressed using a unique content name, identifier, or address.

PNPM’s Monorepo policy

PNPM also has good support for Monorepo. So how do you build Monorepo projects using PNPM?

  • Globally configure pnpm-workshop.yaml

    packages:
      # all packages in subdirs of packages/ and components/
      - 'packages/**'
    Copy the code
  • Install globally common packages using PNPM

    pnpm install react react-dom -w / / root directory
    pnpm i dayjs -r --filter packageName  // Install under specified packages
    Copy the code
    • -w Installs the package in the root directory node_modules

    • -r installs the package under the specified package with the specified parameter –filter followed by the name of the package