Using Yarn Plug'n'Play
Plug'n'Play (PnP) is an innovative installation strategy for Node that tries to solve the challenges of using node_modules
for storing installed packages:
- slow installation process
- slow node runtime cold start
- expensive packages diffing when adding new packages
- no ability to restrict access and enforce hoisting/nesting
Instead of using the node_modules
folder, PnP
creates a map from package names to hoisted package versions and creates dependency edges between packages. The packages are kept in zip
archives which makes caching and restoring faster.
Read more about PnP
on Yarn's official docs.
Switching to Yarn v2+ (aka Berry)
When you run create-nx-workspace
with the optional --pm=yarn
flag, Nx uses the default yarn version set in your global .yarnrc.yml
file (usually in the root of your user folder). To check your current yarn version, run:
❯
yarn --version
If the version is in the 1.x.x
range, the workspace will be created with yarn classic. To migrate an existing yarn classic workspace to the modern version of yarn, also known as Berry
, run:
❯
yarn set version stable
This command will update .yarnrc.yml
with the path to the local yarn bin
of the correct version and will set the packageManager
property in the root package.json
:
{
// ...
"packageManager": "yarn@3.6.1"
}
Switching to PnP
Once you are on the modern version of yarn, you can use the following command to switch to PnP
:
❯
yarn config set nodeLinker pnp
Your .yarnrc.yml
will now have nodeLinker
set to a proper method:
nodeLinker: pnp
Once the config is changed you need to run the install again:
❯
yarn install
Running install generates a .pnp.cjs
file that contains a mapping of external packages and strips all the packages from the node_modules
. The contents of your node_modules
should now look like this:
node_modules/
└── .cache
└── nx
Dealing with Inaccessible Dependencies
When using Yarn Berry, Nx will set the nodeLinker
property to a backward compatible node-modules
value by default. This is to ensure your repository works out of the box.
Some packages come with broken dependency requirements so using strict PnP
can lead to broken builds. This results in errors similar to the one below:
❯
Error: [BABEL]: @babel/plugin-transform-react-jsx tried to access @babel/core (a peer dependency) but it isn't provided by your application; this makes the require call ambiguous and unsound. Required package: @babel/core
The problem above is something we need to fix by ensuring the requested peer dependency exists and is available:
❯
yarn add -D @babel/core
Sometimes, simply adding a missing package doesn't work. In those cases, the only thing we can do is contact the author of the package causing the issues and notify them of the missing dependency requirement. The alternative is to switch back to using the node-modules
node linker.