How to get rid of node_modules with Yarn Plug’n’Play
Reduce your install time up to 70%. Ask me how! 😱
Anyone who knows me can confirm that I’m a long-standing lover of JavaScript and its entire ecosystem. As a Front-end engineer, Node-based package managers have been a crucial part of my toolset since 2013.
First, I used Bower, which was primarily focused on the front-end world. Then, in 2015, I sadly (ok, not really) realized that Bower was dying and NPM, the default package manager for Node, was the way to go for the front-end too. It was strange for me, at first, to use NPM for other things than Node modules, but I got used to the idea and migrated seamlessly.
Finally, just one year later, Facebook gave us Yarn, a modern and blazing fast alternative to NPM. I loved it at first sight! But some things were still problematic…
Inherited problems in Yarn
Besides the speed, Yarn brought a number of advantages when compared to the NPM version at the time, such as lock files, offline mode, network resilience, checksums and others. Nevertheless, Yarn borrowed some known problems from NPM:
node_modules here, there, everywhere
For each project on your machine that uses NPM or Yarn, a node_modules
folder is created. It doesn't matter if 10 projects use the exact same version of a given module, it will be copied over and over into each node_modules
folder of these projects.
Generating a new node_modules folder takes a really long time
Even taking a great leap forward in terms of installation speed, Yarn was constrained by node_modules limitations. Just creating the node_modules folder takes up to 70% of the time needed to run yarn install
(with a warm cache). It's a huge amount of files to be created on every installation. So, don't blame it on Yarn.
Dependencies not added to package.json
Here’s a scenario for you: Your app works perfectly in development, but crashes in production. After hours of investigation, you finally realize that you forgot to add a dependency to your package.json
. Yes, it can happen.
Slow module resolution at runtime
The boot time of your app is heavily impacted by the way Node resolves dependencies. It wastes time querying the file system to discover where a given dependency will be resolved from.
Yarn Plug’n’Play to the rescue!
All of the above problems were addressed by the Yarn team with the release of the Plug’n’Play feature last September.
When you enable PnP, instead of copying every needed file from the cache to the node_modules
folder, here's what Yarn does:
- It creates a single file with static resolution tables. These tables will contain a bunch of important info, such as: packages available in the dependency tree, how they relate between themselves and their location on the disk.
- A special resolver is used in order to help Node discovering where each dependency has been installed (under the Yarn cache folder). It solely relies on the resolution tables which were created previously. As these tables contain information about the entire dependency tree, the node_modules resolution process won’t need to make a lot of
stat
andreaddir
calls at runtime anymore, significantly reducing your app boot time. And as Yarn knows all of your dependencies, it will complain if you try to import a module that's not present in yourpackage.json
:
Using Yarn Plug’n’Play
Converting a project to make use of PnP is easy as 1–2–3. You just need to add a installConfig
section to your package.json
, with a pnp
key set to true
, like this one:
{
"installConfig": {
"pnp": true
}
}
Note: You need Yarn v1.12+ in order to use Plug’n’Play.
After that, just run yarn install
and everything inside your node_modules
folder will be deleted. From now on, every dependency will be resolved directly from Yarn's hot cache.
Using PnP in a new React project with create-react-app
If you use create-react-app 2+, the good news is that it works great with Yarn Plug’n’Play! Just append the --use-pnp
option to the create-react-app
command and you're good to go:
npx create-react-app your-app-name --use-pnp
Possible issues
As nothing is perfect in the world, PnP may incur new issues when used in projects relying on a custom install logic. If you need more info about these potential new issues, you can find a detailed explanation in this paper.
Conclusion
Plug’n’Play solves some really annoying problems in Yarn. Besides, it dramatically improves dependency caching on CIs, saving installation time and allowing our builds to get right to the point: running the tests!
And that’s it! Have fun with Yarn PnP.