Deep thinking about modern package manager -- why do I recommend pnpm instead of NPM / yarn?

Shensanyuan 2021-02-23 04:04:08
deep thinking modern package manager

This article will share with you an excellent package manager in the industry ——pnpm. at present GitHub There has been a star 9.8k, Now it's relatively mature and stable . It consists of npm/yarn derived , But it solved npm/yarn Internal potential bug, And greatly optimized performance , Extended use scenarios . Here is the mind map of this article :

One 、 What is? pnpm ?

pnpm Of Official documents That's what it says :

Fast, disk space efficient package manager

therefore ,pnpm It's essentially a package manager , This is the same as npm/yarn There is no difference between , But two of its advantages as a killer are :

  • Package installation is extremely fast ;
  • Disk space utilization is very efficient .

It's also very easy to install . How easy it can be ?

npm i -g pnpm
 Copy code 

Two 、 Features Overview

1. Fast

pnpm How fast can packages be installed ? Start with React Take Bao as an example :

You can see , As the yellow part of pnpm, In most scenarios , The speed of package installation is obviously better than npm/yarn, Faster than npm/yarn fast 2-3 times .

Yes yarn The more familiar students may say ,yarn Not having PnP The installation mode Do you ? Directly remove node_modules, Write the contents of the dependency package on disk , Saved node file I/O The cost of , This will also speed up the installation .( For specific principles, see This article

Next , We take such a Warehouse For example , Let's take a look benchmark data , The main comparison is pnpm and yarn PnP:

You can see from it , Overall speaking ,pnpm The package installation speed of is obviously better than yarn PnP Of .

2. Efficient use of disk space

pnpm For internal use Content based addressing To store all the files on the disk , The great thing about this file system is :

  • The same package will not be installed repeatedly . use npm/yarn When , If 100 Every project depends on lodash, that lodash It's likely to be installed 100 Time , There's just... On the disk 100 This part of the code is written in three places . But in the use of pnpm It will only be installed once , There is only one place in the disk to write , If you use it again later, you will use it directly hardlink( Hard links , I don't know This article ).

  • Even different versions of a package ,pnpm It also greatly reuses previous versions of code . for instance , such as lodash Yes 100 File , One more file after the update , Then the disk will not be rewritten 101 File , It's keeping the original 100 File hardlink, Just write that A new file .

3. Support monorepo

With the increasing complexity of front-end engineering , More and more projects are starting to use monorepo. Previous management of multiple projects , We usually use multiple git Warehouse , but monorepo Our purpose is to use a git Warehouse to manage multiple subprojects , All subprojects are stored in the root directory packages Under the table of contents , So a subproject represents a package. If you haven't touched it before monorepo The concept of , I suggest you take a closer look This article And open source monorepo Management tools lerna, For the project directory structure, please refer to babel Warehouse .

pnpm And npm/yarn Another big difference is support monorepo, It is reflected in the function of each subcommand , For example, in the root directory pnpm add A -r, So all package Will be added A This dependence , Yes, of course --filter Field to package To filter .

4. High safety

Before using npm/yarn When , because node_module The flat structure of , If A rely on B, B rely on C, that A It can be used directly C Of , But the problem is A There is no statement C This dependence . So there will be this kind of illegal access . but pnpm The brain cavity is very big , We have created a set of dependency management , It solved the problem well , Safety guaranteed , How to embody Security 、 Avoiding illegal access depends on risk Of , Let's talk about it in detail later .

3、 ... and 、 Dependency management

npm/yarn install principle

It is mainly divided into two parts , First , perform npm/yarn install after , How the package gets to the project node_modules among . secondly ,node_modules How to manage dependence internally .

After executing the command , First, we build the dependency tree , And then for the packets under each node , There are four steps :

    1. Resolve the version interval of the dependent package to a specific version number
    1. Download the version dependent tar Package to local offline image
    1. Decompress the dependency from the offline image to the local cache
    1. Copy the dependency from the cache to the current directory node_modules Catalog

then , The corresponding package will arrive at the project node_modules among .

that , These depend on node_modules What kind of directory structure is inside , let me put it another way , What is the dependency tree of a project ?

stay npm1npm2 The nested structure is shown in , Like the following :

└─ foo
├─ index.js
├─ package.json
└─ node_modules
└─ bar
├─ index.js
└─ package.json
 Copy code 

If bar There is also dependence , Then it will continue to nest . Think about what's wrong with this design :

  1. The dependency level is too deep , It will cause the file path to be too long , Especially in window Under the system .
  2. A lot of duplicate packages are installed , It's a huge file . Like with foo There is one in the same level directory baz, Both depend on the same version of lodash, that lodash It's going to be between the two node_modules Is installed in , That is to say, repeat the installation .
  3. Module instances cannot be shared . such as React There are some internal variables , Introduced in two different packages React Not the same module instance , So you can't share internal variables , Lead to some unpredictable bug.

next , from npm3 Start , Include yarn, All set out to pass Flattening depends on The way to solve this problem . I believe that everyone has such an experience , I just pretend to be express, Why? node_modules There are so many things in it ?

you 're right , This is it. flat Depending on the results of Management . Compared with the previous Nested structure , The current directory structure is similar to the following :

├─ foo
| ├─ index.js
| └─ package.json
└─ bar
├─ index.js
└─ package.json
 Copy code 

All the dependencies are flattened node_modules Under the table of contents , There's no more deep nesting . So when you install a new package , according to node require Mechanism , I'll go to the higher authorities node_modules Look for , If a package of the same version is found, it will not be re installed , Solved the problem of a large number of packages repeatedly installed , And the level of dependency is not too deep .

The problem was solved , But think about this flat Treatment mode , Is it really impeccable ? Not at all . It still has many problems , Sort out :

    1. Structure dependent uncertainty .
    1. The flattening algorithm itself complexity Very high , Longer time consuming .
    1. It's still possible in the project Illegal access There is no declared dependency package

The latter two are easy to understand , In the first point uncertainty What does that mean? ? Here's a detailed explanation .

Suppose the project now relies on two packages foo and bar, The dependency of these two packages is like this again :

that npm/yarn install When , After flattening , It's like this

It's still like this ?

The answer is : It's possible . Depending on foo and bar stay package.json Position in , If foo The statement goes ahead , So that's the front structure , Otherwise, it's the back structure .

That's why there's a dependency structure Not sure problem , It's also lock file Cause of birth , Whether it's package-lock.json(npm 5.x Only then ) still yarn.lock, It's all about making sure install After that, there are certain node_modules structure .

For all that ,npm/yarn It still exists The flattening algorithm is complex and package Illegal access The problem of , Impact performance and safety .

pnpm Dependency management

pnpm The author of Zoltan Kochan Find out yarn I don't intend to solve these problems , So I started a new stove , Write a new package manager , It creates a new dependency management mechanism , Now let's find out .

Or to install express For example , Let's create a new directory , perform :

pnpm init -y
 Copy code 

And then execute :

pnpm install express
 Copy code 

Let's see node_modules:

 Copy code 

We saw it directly express, But here's the thing , It's just a Soft link , If you don't believe it, open it and have a look , There is no node_modules Catalog , If it's the real file location , So according to node The package loading mechanism of , It can't find a dependency . So where is its real location ?

We continue to .pnpm Looking for :

▾ node_modules
▾ .pnpm
▸ accepts@1.3.7
▸ array-flatten@1.1.1
▾ express@4.17.1
▾ node_modules
▸ accepts
▸ array-flatten
▸ body-parser
▸ content-disposition
▸ etag
▾ express
▸ lib
 Copy code 

good heavens ! in .pnpm/express@4.17.1/node_modules/express I found !

Just open a bag :

It seems to be the same rule , All are <package-name>@version/node_modules/<package-name> This directory structure . also express We all depend on .pnpm/express@4.17.1/node_modules below , These dependencies are all Soft link .

I want to see others .pnpm,.pnpm Although the directory presents a flat directory structure , But think about it , Along Soft link Slowly unfold , It's actually a nested structure !

▾ node_modules
▾ .pnpm
▸ accepts@1.3.7
▸ array-flatten@1.1.1
▾ express@4.17.1
▾ node_modules
▸ accepts -> ../accepts@1.3.7/node_modules/accepts
▸ array-flatten -> ../array-flatten@1.1.1/node_modules/array-flatten
▾ express
▸ lib
 Copy code 

take The bag itself and rely on Put it in the same node_module below , With native Node Fully compatible with , And then you can package Well organized with related dependencies , It's a wonderful design .

Now let's look back , In the root directory node_modules There's no longer a dazzle of dependence , It's the heel package.json The declared dependencies are basically consistent . Even if pnpm There will be some packages inside that will set up dependency Promotion , Will be promoted to the root node_modules among , But on the whole , Root directory node_modules It's much clearer and more standardized than before .

Four 、 Let's talk about safety

I don't know if you find out ,pnpm This way of relying on management also cleverly evades Illegal access depends on The problem of , That is, as long as a bag is not in package.json Declaration of dependency , So it's not accessible in the project .

But in npm/yarn It can't be done , Then you may ask , If A rely on B, B rely on C, that A Even without a statement C Dependence , Due to the existence of dependence on ascension ,C It's loaded into A Of node_modules Inside , Then I am A with C, There's no problem running , When I'm online , It can also work normally . Isn't it safe ?

Not really .

First of all , You need to know B The version of can change at any time , If I had depended on C@1.0.1, Now we have a new version , The new version of the B rely on C@2.0.1, So in the project A among npm/yarn install after , What's on it 2.0.1 Version of C, and A It's still C The old version of API, Maybe it's a mistake .

second , If B After the update , It may not be necessary C 了 , So when installing dependencies ,C It's not going to fit into node_modules Inside ,A It's quoted from C The code directly reports an error .

There's another situation , stay monorepo In the project , If A rely on X,B rely on X, One more C, It doesn't depend on X, But it uses X. Due to the existence of dependence on ascension ,npm/yarn Will be able to X Put it in the root directory node_modules in , such C You can run locally , Because according to node The package loading mechanism of , It can be loaded into monorepo In the root directory of the project node_modules Medium X. But think about it , once C Let it out alone , Users install it separately C, Then you can't find X 了 , Execute to reference X The error will be reported directly when the code of .

these , It's all about relying on the potential bug. If it's your own business code, it's OK , Just imagine if it's a toolkit for a lot of developers , Then the harm is very serious .

npm Some people want to solve this problem in the past , Appoint --global-style Parameter to prevent variable promotion , But doing so is like going back to the days of nested dependency , One night before liberation , The drawbacks of the nested dependency mentioned above are still exposed .

npm/yarn It seems difficult to solve the problem of relying on ascension itself , But the community already has specific solutions to this problem : dependency-check, Address :…

But there's no denying it ,pnpm Do it more thoroughly , The original set of dependency management not only solves the security problem of dependency Promotion , It also greatly optimizes performance in time and space .

5、 ... and 、 Daily use

Said so much , I guess you'll think pnpm It's complicated , Is it expensive to use ?

On the contrary ,pnpm It's very easy to use , If you had npm/yarn Using experience of , It can even migrate seamlessly to pnpm come up . If you don't believe me, let's take a few examples of daily use .

pnpm install

Follow npm install similar , Install all the dependencies under the project . But for the monorepo project , Will install workspace All of the following packages All dependencies of . But it can go through --filter Parameter to specify package, Only for those who meet the conditions package Do dependency installation .

Of course , You can also use , To install a single package :

// install axios
pnpm install axios
// install axios And will axios Added to the devDependencies
pnpm install axios -D
// install axios And will axios Added to the dependencies
pnpm install axios -S
 Copy code 

Of course , It can also be done through --filter To specify the package.

pnpm update

Update the package to the latest version according to the specified scope ,monorepo In the project, you can go through --filter To specify the package.

pnpm uninstall

stay node_modules and package.json Remove the specified dependency from .monorepo The project is the same as above . Examples are as follows :

// remove axios
pnpm uninstall axios --filter package-a
 Copy code 

pnpm link

Connect a local project to another project . Be careful , Using hard links , Instead of soft links . Such as :

pnpm link ../../axios
 Copy code 

in addition , We often use npm run/start/test/publish, These are directly replaced by pnpm It's the same , I won't repeat . For more postures, please refer to the official documents :

You can see , although pnpm There's a lot of complicated design inside , But it's actually not perceptive to users , It's very friendly to use . also , Now the author is still maintaining , at present npm Last week, there were downloads of 10w +, Experienced the test of large-scale users , Stability can also be guaranteed .

therefore , Taken together ,pnpm It's a comparison npm/yarn Better solution , Looking forward to the future pnpm More landing .

Reference material :

[1] pnpm Official documents :

[2] benchmark Warehouse :…

[3] Zoltan Kochan 《Why should we use pnpm?》:

[4] Zoltan Kochan 《pnpm's strictness helps to avoid silly bugs》:…

[5] Conarli《npm install Principle analysis 》:…

[6] yarn Official documents :

[7] 《Yarn Of Plug'n'Play characteristic 》:…

[8] 《Guide to Monorepos for Front-end Code》:…


  1. JavaScript advanced: Javascript object-oriented, JavaScript built-in object, JavaScript BOM, JavaScript encapsulation
  2. JavaScript advanced: Javascript object-oriented, JavaScript built-in object, JavaScript BOM, JavaScript encapsulation
  3. Vue determines whether the El form in the elementui is updated or changed. If it changes, it will prompt whether to save it. If it does not change, it will leave directly
  4. Algorithm problem: sum of two numbers -- JavaScript and Java implementation
  5. High performance nginx HTTPS tuning
  6. JQuery advanced
  7. day 30 jQuery
  8. JQuery:JQuery Basic syntax, jQuery selector, jQuery DOM, comprehensive case check box, comprehensive case random picture
  9. TCP/IP 开胃菜 之 HTTP
  10. JQuery:JQuery Basic syntax, jQuery selector, jQuery DOM, comprehensive case check box, comprehensive case random picture
  11. JavaScript data type
  12. [micro front end] the final chapter of micro front end - Qiankun guide and overall exploration of micro front end
  13. Solve Ajax cross domain problem [5 solutions]
  14. HTTP of TCP / IP appetizer
  15. Optimization of pod creation efficiency in serverless scenario
  16. Iqiyi Sports: experience the ultimate expansion and contraction of serverless, and increase the utilization rate of resources by 40%
  17. First knowledge of HTTP / 1.1
  18. First knowledge of HTTP / 1.1
  19. Webpack learning notes series 05 devserver
  20. Webpack learning notes series 04 - resource processing optimization
  21. How to build a high performance front end intelligent reasoning engine
  22. How to become a professional front end engineer in 2021?
  23. How to transform single / micro service application into serverless application
  24. How to transform single / micro service application into serverless application
  25. How to transform single / micro service application into serverless application
  26. How to connect the ground gas to the micro front end?
  27. How to connect the ground gas to the micro front end?
  28. How to connect the ground gas to the micro front end?
  29. Vue server rendering principle analysis and introduction
  30. Realize the correct loading of text message
  31. Building my own project scaffolding with yeoman
  32. JavaScript advanced prototype and prototype chain
  33. React background management front end system (based on open source framework development) start
  34. JS practical skills breakpoint debugging
  35. I'd like to share with you 20 super easy-to-use Chrome extension plug-ins
  36. Get page element location
  37. Use the powerful API of modern browser to record any interface in the browser and realize export, save and management
  38. Delayed code execution in flutter
  39. Reconfiguration experience of KOA middleware system
  40. Add comments to your blog
  41. Svg editor -- new path
  42. Detailed explanation of debounce and throttle of JavaScript function
  43. Anti shake and throttling and corresponding react hooks package
  44. C2m: the first CSDN article moved to MOOC script 5000 words, detailed painstaking development process, there are renderings and source code at the end of the article
  45. Front end, school recruitment, Taobao, guide
  46. [vue2 & G6] get started quickly
  47. Canvas from the beginning to the pig
  48. Take five minutes to standardize the code comments?
  49. Some thoughts on sass
  50. what?! You haven't filled in the award information yet
  51. How to get the interface + tsdoc needed by TS through swagger
  52. Binary tree
  53. Canvas drawing method in Web screenshot
  54. Front end docker image volume optimization (node + nginx / node + multi-stage construction)
  55. Become a big influence of technology? Coding pages quickly build personal blog
  56. Object and array deconstruction, spread operator, rest operator
  57. Analysis of Axios source code
  58. Two ways to delete useless code in project (Practical)
  59. Edit your picture with canvas
  60. Today's chat: 2-4 years to walk out of the resignation dilemma and comfort zone