DEV Community

Cover image for Let's settle things out [2]: NPM Vs. YARN VS. PNPM
Ayoub Abidi
Ayoub Abidi

Posted on

 

Let's settle things out [2]: NPM Vs. YARN VS. PNPM

Last year I wrote an article to compare between NPM and Yarn (NPM vs Yarn: let's settle things out) and since then I always used yarn as my main package manager but lately I saw some hype over a new package manager called PNPM and I think it has promising future.
This article will probably be more about PNPM since it the newest one and we already did define and compare the other two in the previous article.

What is PNPM?

PNPM is a drop-in replacement for npm. It is built on top of npm and is much faster and more efficient than its predecessor. It is highly disk efficient and solves inherent issues in npm. In this article, we will discuss pnpm in detail. We will explain how it works and will go through why pnpm is a perfect replacement for npm or yarn.

Why not NPM or YARN?

NPM uses flattened node_modules. The flattened dependency results in many issues, such as:
The algorithm for flattening a dependency tree is complex
 Some of the packages have to be duplicated inside another project's node_modules folder.
Modules have access to packages they do not depend on
 Let's explain this with a basic example. One of your projects needs an express module, and express has a dependency package named "debug".
Your code can require('debug'), even if you do not depend on it explicitly in the package.json file. Let's discuss two scenarios that can cause issues:

Express updates its debug dependency with breaking changes.
Express does not depend on debugging anymore.

In both cases, your code will fail because it has an implicit dependency to debug. That is a big problem. Similarly, if you work with a large mono repo, then it will be much more difficult to track particular dependencies a project uses.
 Duplicate packages are another issue here. Now yarn is slightly better in terms of optimizing disk space as it makes use of hoisting, however that approach fails in some cases.

How does PNPM solve these problems?

PNPM uses hard links and symlinks to maintain a semistrict node_modules structure. So what's the difference between a hard link and a soft link? 
Well, a hard link is a different reference to the same file. In soft link, you create a new file, and the contents of the file point to another path. Symlinks are symbolic links that pnpm uses to create a nested structure of dependencies.

The pnpm version of the express and node modules.

The first thing you will notice is that your code cannot access the "debug" package because it is not directly under the root level node_modules directory.

PNPM has created a special folder named ".pnpm" that contains hard links to all the modules.

When you download a dependency, pnpm first checks whether the dependency is present in this store or not. If it finds the dependency in the store, pnpm fetches it by creating a hard link.
Because of this approach, pnpm re-uses the same packages if they are already installed for another project. This brings us to the many benefits which pnpm provides. Let's discuss some of those.

Performance and Disk Efficiency

Image description
For NPM It is still a bit slower when compared to Yarn and PNPM. Yarn uses the same flatten node_modules directory but is comparable to NPM in regards to speed and installs packages parallely.
Image description
On the other hand PNPM is 3 times faster and more efficient than NPM.
With both cold and hot cache, PNPM is faster than Yarn.
Pnpm simply links files from the global store, while yarn copies files from its cache. Package versions are never saved more than once on a disk.
The algorithm of pnpm does not use a flatten dependency tree, which makes it easier to implement, maintain, and requires less computation.
This was the method used in NPM 3 and earlier, but nesting was problematic, and thus packages had to be copied several times for each package that depended on them.

Security

NPM: There have been some security vulnerabilities that have directly affected many projects due to the way npm handles bad packages.
YARN: Checksums stored in yarn.lock have been used by Yarn Classic and Yarn Berry ever since. Yarn also prevents you from installing malicious packages; if a mismatch is detected, the installation will be aborted.
PNPM: Similar to Yarn, PNPM also uses checksums and in addition to the use of checksums, pnpm also verifies the integrity of its code before executing it.

Structure of the projects

We all know that with npm install it takes the package-lock.json and generate node_modules folder. yarn create yarn.lock file and a node_modules folder (besides .yarn/cache/, other locations for storing yarn classic versions can be used (.yarn/releases/)), but unlike NPM, PNPM doesn't create a flattened dependency tree. In node_modules, everything had its own node_modules folder within package.json, and every dependency was precisely specified in package.json. Before npm version 3, the node_modules structure was predictable.
The problem with this approach was twofold:

  • windows was frequently having trouble with long directory paths caused by packages with too deep dependency trees
  • packages were copied several times to satisfy multiple dependencies PNPM solved this issue without flattening the dependency tree. Each package's dependencies were grouped together in a node_modules folder and symlinks were used to group dependencies together, so the directory tree is flat.
.
├── node_modules/
│   └── .pnpm/
├── .npmrc
├── package.json
└── pnpm-lock.yml
Enter fullscreen mode Exit fullscreen mode

A package.json file is created once you install the dependencies using pnpm i, also a node_modules folder is generated but the structure of it will differ completely from npm and yarn because of its content-addressable storage approach.

Conclusion

Pnpm has brought many improvements, built on top of existing npm features. pnpm has adopted all the good things of npm while removing its weaknesses, making pnpm the best of both worlds.
I recommend you do install pnpm and try it for yourself.

npm install -g pnpm
Enter fullscreen mode Exit fullscreen mode

Image description

Sources

Top comments (0)

An Animated Guide to Node.js Event Loop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.