Both pnpm (as of v2.17) and Yarn (as of v1.12) support fast, concurrent installations in monorepos. However, there is a big difference between how they store dependencies in monorepos. Yarn tries to hoist all dependencies from all workspace packages into the root node_modules
of the monorepo, which means that packages have access to dependencies of other packages in the workspace. This is described in the Yarn docs:
Be careful when publishing packages in a workspace. If you are preparing your next release and you decided to use a new dependency but forgot to declare it in the package.json file, your tests might still pass locally if another package already downloaded that dependency into the workspace root. However, it will be broken for consumers that pull it from a registry, since the dependency list is now incomplete so they have no way to download the new dependency. Currently, there is no way to throw a warning in this scenario.
Like Yarn, pnpm hoists all packages to the root. However, pnpm stores all dependencies in a hidden folder and only links the direct dependencies of every package into their node_modules
.
Let's see how Yarn and pnpm work on a simple example:
- there is a small monorepo with two packages:
foo
andbar
-
foo
hasis-negative@1.0.0
as a dependency -
bar
hasis-positive@1.0.0
as a dependency
Yarn in action
To make this repo work with Yarn, there should be a package.json
in the root of the repo with the following content:
{
"private": true,
"workspaces": ["foo", "bar"]
}
To install all dependencies of all workspace packages, you should run yarn install
.
See results here
In this case, Yarn will create a single node_modules
in the root of the repo with both is-negative
and is-positive
. It means that both foo
and bar
will have access to the dependencies of each other.
pnpm in action
To make pnpm install dependencies in this repo, you'll need to create a pnpm-workspace.yaml
in the root of the repo (it can be empty) and a .npmrc
file with the following content:
shared-workspace-shrinkwrap = true
link-workspace-packages = true
To install all dependencies of all workspace packages with pnpm, you should run pnpm multi install
(or just pnpm m i
).
See results here
Like Yarn, pnpm creates a node_modules
in the root of the repo. However, if you open that folder, you'll see that all directories and files are hidden there:
node_modules
+ .registry.npmjs.org
+ .modules.yaml
+ .shrinkwrap.yaml
This node_modules
stores all the dependencies but they are hidden in .registry.npmjs.org
. Node's resolution algorithm will not find them.
Now if you check the directory of bar, you'll see a node_modules
there as well, with a single symlink called is-negative
. This symlink is pointing at ../../node_modules/.registry.npmjs.org/is-negative/1.0.0/node_modules/is-negative
. Likewise, there is a symlink to is-positive
in the node_modules
directory of foo
. So foo
is able to resolve only is-positive
and bar
is only able to resolve is-negative
🎉😊
As you can see, pnpm is strict not only when used with a single package.json
but also in a multi-package repository.
Top comments (0)