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
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
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 :
- Resolve the version interval of the dependent package to a specific version number
- Download the version dependent tar Package to local offline image
- Decompress the dependency from the offline image to the local cache
- 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 ？
npm2 The nested structure is shown in , Like the following :
node_modules └─ foo ├─ index.js ├─ package.json └─ node_modules └─ bar ├─ index.js └─ package.json Copy code
bar There is also dependence , Then it will continue to nest . Think about what's wrong with this design :
- The dependency level is too deep , It will cause the file path to be too long , Especially in window Under the system .
- A lot of duplicate packages are installed , It's a huge file . Like with
fooThere 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 .
- 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
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 :
node_modules ├─ 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 :
- Structure dependent uncertainty .
- The flattening algorithm itself complexity Very high , Longer time consuming .
- 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
.pnpm .modules.yaml express 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 ▸ firstname.lastname@example.org ▸ email@example.com ... ▾ firstname.lastname@example.org ▾ node_modules ▸ accepts ▸ array-flatten ▸ body-parser ▸ content-disposition ... ▸ etag ▾ express ▸ lib History.md index.js LICENSE package.json Readme.md Copy code
good heavens ！ in
.email@example.com/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
.firstname.lastname@example.org/node_modules below , These dependencies are all Soft link .
I want to see others
.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 ▸ email@example.com ▸ firstname.lastname@example.org ... ▾ email@example.com ▾ node_modules ▸ accepts -> ../firstname.lastname@example.org/node_modules/accepts ▸ array-flatten -> ../email@example.com/node_modules/array-flatten ... ▾ express ▸ lib History.md index.js LICENSE package.json Readme.md Copy code
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 : github.com/dependency-…
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 .
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.
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.
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
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 : pnpm.js.org/en/
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 :
 pnpm Official documents : pnpm.js.org/en/
 benchmark Warehouse : github.com/dependency-…
 Zoltan Kochan 《Why should we use pnpm?》：https://www.kochan.io/nodejs/why-should-we-use-pnpm.html
 Zoltan Kochan 《pnpm's strictness helps to avoid silly bugs》: www.kochan.io/nodejs/pnpm…
 Conarli《npm install Principle analysis 》: cloud.tencent.com/developer/a…
 yarn Official documents : classic.yarnpkg.com/en/docs
 《Yarn Of Plug'n'Play characteristic 》: loveky.github.io/2019/02/11/…
 《Guide to Monorepos for Front-end Code》: www.toptal.com/front-end/g…