• Overview of differences between NPM, YARN and PNPM
  • Written by Alex Kras
  • The Nuggets translation Project

I’m not an expert on package managers. Instead, I didn’t realize NPM was using local caches until recently. Unbeknownst to this time, I wrote this article entitled Omg -NPM cloning finally Makes sense and gave some of my incorrect ideas. This forced me to go back and re-examine the differences between these package managers these days.

I have been using NPM for the past 5 years. When YARN first came out, I did some yarn, too. And I learned about PNPM a week ago in my article “Why We Should Use PNPM”.

Over the past week, I’ve been spending time reading about NPM, YARN and PNPM to summarize and share my findings. My target audience is long-term NPM users, and I don’t want to spend too much time learning about how many alternatives there are to NPM, like myself. I’m only going to focus on the three most commonly mentioned (for me) and not include them: IED, NPM-install, and NPMD, because I don’t know anything about them.

And it’s important to point out, until the time of writing this article is not a competitive library’s goal is to replace the NPM registry (is the place where storage bag), their purpose is to replace NPM command line client, provide another available user interface, and behavior, and its function is similar.

NPM

NPM has been around since the beginning of Node.js and is one of the reasons the project is so successful. The NPM team has done a great job of keeping NPM backward compatible and working continuously in multiple environments.

As you can see from the reference on their website, the design concept of NPM is based on Semantic Versioning (Semver).

Given a version number major,’minor’, ‘patch’ :

  • A MAJOR revision means you’ve made an incompatible API change.
  • The MINOR version means you’re adding functionality in a backward compatible way.
  • The PATCH version means you’ve made backwards-compatible bug fixes

NPM uses a file called package.json, where the user can run NPM install to store all dependencies for the project

For example, running NPM install –save loadsh will add this entry to package.json.

"Dependencies ": {"loadsh": "^4.17.4"}Copy the code

Note the symbol before ^ the loadsh version number. This symbol tells NPM to install any packages that are the same as the MAJOR version. So if I run NPM install a year later, NPM will install the latest loadsh with MAJOR version 4. For example, it could be [email protected] (@ is a version that NPM convention uses to specify package names). You can see all the supported in this symbol: docs.npmjs.com/misc/semver.

The reason for this is because the MINOR version’s changes should (in theory) only contain backward-compatible shoreification. Therefore, installing the latest version of the package can resolve important bugs or security issues.

On the other hand, it can lead to multiple developers having different versions of packages installed on their machines, even though they share the same package.json file, which can potentially lead to difficult debugging and “it’s fine on my machine” situations.

Most NPM packages rely heavily on other NPM packages. This leads to circular dependencies and increases the possibility of version mismatches.

You can disable the default behavior of adding ^ before the version of a package by using the NPM config set save-exact true command, but this locks only high-level dependencies. Since each imported package has its own package.json file, where dependencies may contain ^, there is no way to ensure nested content through package.json.

To solve this problem, NPM provides a shrinkwrap command. This command generates an npm-shrinkwrap. Json file, specifying explicit versions for all packages and nested dependencies.

This means that even with the nPm-shrinkwrap. Json file, NPM locks only the version of the package, not the contents of the package. Even though NPM now prevents users from releasing the same version of the package multiple times, the NPM management still has the right to force updates to certain packages.

Here’s a quote from the Shrinkwrap document page:

If you want to lock down specified bytes contained in a package, for example if you are 100% confident that you can redistribute or build, then you should check your dependencies into source control or pursue some other mechanism that validates the content rather than the version.

NPM Version 2 past tense is installed for all imported dependencies within each package. If you have A project that leads to project A, project A leads to project B, and project B leads to project C, the structure tree of all dependencies would look like this:

node_modules
- package-A
-- node_modules
--- package-B
----- node_modules
------ package-C
-------- some-really-really-really-long-file-name-in-package-c.js
Copy the code

The structure can get quite long. This may just be an annoyance on Unix-based systems, but there are already many jailbreakers on Windows that can solve the problem of file paths longer than 260 characters.

NPM Version 3 addresses this problem by flattening the dependency tree, so the structure of the three projects will look like this:

node_modules
- package-A
- package-B
- package-C
-- some-file-name-in-package-c.js
Copy the code

The result of this change is to change the file path of A long file from./node_modules/ package-a /node_modules/ package-b /node-modules/some-file-name-in-package-c.js to . / node_modules/some – file – name – in – package – SAN Antonio s.

You can learn more about NPM 3 dependent solutions here.

One disadvantage of this approach is that NPM now has to traverse all project dependencies to decide how to flatten the node_modules folder. NPM is forced to build a dependency tree for all used modules, which can be costly. This is one of the reasons why NPM Install is slow to install. (See the update at the end.)

Since I haven’t paid close attention to the changes in NPM, I guess the reason NPM is slow is that I need to download everything from the web every time I run NPM Install.

As it turns out, I was wrong, and NPM does have a local cache where it keeps a compressed file of all the downloaded packages. You can run the NPM cache ls command to view the contents of the local cache. Local caching can speed up installation.

All in all, NPM is a mature, stable, and enjoyable package manager.

yarn

Yarn was launched in October 2016 and quickly gained 24K+ Star on Github. For comparison, NPM is only 12K+ star. The project features highly qualified developers such as Sebastian McKenzie (babel.js) and Yehuda Katz (ember.js, Rust, Bundler, etc.).

From what I’ve gathered so far, the primary purpose of YARN was to address the installation uncertainty of NPM due to semver-related behavior mentioned in the previous section. However, predictable dependency trees (if required) can be done with NPM Shrinkwarp, which is not the default behavior and depends on developers being aware of this option and acting accordingly.

Yarn takes a different approach. Each YARN installation generates a yarn.lock file similar to npm-shrinkwrap. Json, but by default. In addition to the general information, the yarn.lock file also contains a check of installation content to ensure that the same version of the package is used.

Because YARN is a newly rewritten NPM client, developers were able to properly parallelize all required operations and add some improvements, which also significantly improved the overall setup time. I think the increase in speed is the main reason for the popularity of YARN.

Like NPM, YARN uses local caching. Unlike NPM, YARN does not require a network connection to install cached dependencies and provides offline mode. This feature has been requested on NPM since 2012, but has not been resolved.

Yarn provides some other benefits. For example, it allows you to aggregate all licenses used in your project and see them easily.

One interesting thing is that the YARN documentation has changed its attitude towards NPM since it became popular.

The initial yarn release stated that the steps to install YARN were:

The easiest way to get started is:

npm install -g yarn
yarn
Copy the code

The current yarn installation method is as follows:

Note: Using NPM for installation is not recommended. NPM is nondeterministic, packages are unsigned, and NPM simply does basic SHA1 hashing without any integrity checks, which is risky for installing system-level applications.

In view of the preceding reasons, you are strongly advised to install YARN in the proper installation method for your operating system.

At this rate, I wouldn’t be surprised if YARN announced their own Registry to allow developers to slowly phase out NPM.

Also thanks to YARN, NPM has finally come to the point where they need to pay close attention to strongly requested issues. NPM’s initial response to the YARN release seemed to me to be “it’s cute”. Now, when I look back at the strongly requested “offline” feature I mentioned earlier that has been actively addressed as we discuss this point.

pnpm

As I mentioned earlier, I only learned about PNPM soon after reading Zoltan Kochan’s “Why Should We Use PNPM?” He is the author of NPM.

I won’t go into too much detail (because this post is already quite long), but you can pick up on some of it from my original blog post and the discussion on Twitter.

but

I want to point out that PNPM is faster than NPM and YARN.

The reason why it’s so fast? Because it uses hard and symbolic links in a clever way to avoid copying all locally cached source files, this is the most important aspect of beating YARN in terms of performance.

Using links is not easy, and there are a number of issues to consider.

As Sebastian pointed out on Twitter, he initially wanted to use symbolic links in YARN, but ended up fighting it for many reasons.

The project also has 2K+ Star on Github, and PNPM is able to make links work for a lot of people.

In addition, since March 2017 it offers all the benefits that YARN offers, including offline mode and deterministic installation.

conclusion

I think the developers of YARN and PNPM have done a good job. My personal preference is for deterministic installations, because I like to be in control and I don’t like surprises.

Whatever the final outcome of the competition (which reminds me of the io.js fork), I appreciate yarn for all the trouble NPM has caused so there are plenty of options before the dust settles.

I also think yarn probably considered hard links and soft links early on. What I would like to know is what the YARN team does with this idea, depending on how much damage PNPM does and how much users value installation speed.

I do think that YARN is a safe choice in general, but PNPM may be a better choice in some cases. For example, for a small to medium-sized team that needs to run a lot of integration tests and wants to install dependencies as quickly as possible.

Finally, it’s worth saying that I think NPM still provides a very useful solution for most user cases. Most developers can continue to use only the NPM client.

In any case, I thank all of our competitors for their efforts to stay ecologically healthy. When companies compete, it’s the users who benefit.