[Bug] Yarn PnP behaves different than Yarn in workspaces when package.json scripts calling a dependency
See original GitHub issueDescribe the bug We are trying to make a switch from Yarn to Yarn2 + PnP while using workspaces.
In a monorepo setup we place devDependencies such as webpack
in root package.json
.
All workspaces are located under /apps
directory where they all have a dedicated package.json
file with their runtime dependencies and a build
script similar to that one:
{
"scripts": {
"build": "webpack --config webpack.config.js"
}
Running in Yarn v1 workspaces yarn workspaces run build
from root path, executes the build
script for each of the workspaces without a problem.
When switching to Yarn PnP running the same command produces the following error
command not found: webpack
To Reproduce I created a barebone morepo setup trying out various package management setups and technologies. The two that best describe this issue are the following.
-
Yarn with Yarn workspaces playing as expected when PnP is not enabled
- checkout https://github.com/DimitrK/monorepo-package-manager
- run
yarn install
- run
yarn workspace @acme/two run build
- Builds OK
-
A branch ready to play with Yarn 2 & PNP that produces this issue https://github.com/DimitrK/monorepo-package-manager/tree/pnp/yarn-v2
- Switch to branch
pnp/yarn-v2
(diff from master) - run
yarn set version berry
- run
yarn install
- run
yarn workspace @acme/two run build
- Throws
- Switch to branch
Environment if relevant (please complete the following information):
- OS: OSX 10.13
- Node version v13.10.1
- Yarn version: Tested on both 1.22.4 & 2.0.0-rc.29
Additional context The idea is to move common dev dependencies for all workspaces up in the monorepo root director. That would help us keep consistent, simple and uniform build processes plus dev configuration setup across all of our workspaces.
The following structure gives an approximate view on how package.json
files are placed:
.
|
├── apps
| ├── one
| | └── package.json //build script using webpack
| └── two
| | └── package.json
└── package.json //devDependencies such as webpack
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:12 (4 by maintainers)
Top GitHub Comments
All the above makes sense given how v2 has been designed. I’ve been thinking about this a bit more, what my actual problem is here. I think I was expecting everything to work more like Yarn 1, but I appreciate that what I thought was specifically defined behaviour isn’t actually in reality defined behaviour, it just works that way almost by accident. The colon script trick is useful. But it seems safer to just copy the big list of devDependencies across to each
package.json
. My issue is that this is fine when I’m standing the repo up for the first time and it’s all nice and clean. As time goes by though, adding new packages that need the exact same large set of dependencies is going to start getting messy (constraints will definitely help, but putting those aside for the minute). It’s just that some tooling to do that automatically & avoid human error creeping in would be nice. I dunno, something like acommonDependencies
field in the rootpackage.json
, and a plugin that read from it & went and automatically added them to each package’s devDependencies. Anyway…👍 on more Constraints documentation, really need to see and play around with a load of examples.
[caveat that following is coming after two-and-a-bit years of using Yarn 2 in prod, and thus I think this is sensible advice, but that it’s context-specific so others may have different opinions]
Just installing per package would [IMO] be the best thing to do.
Yes you can install everything at root only, have a set of colon-delimited script aliases at the root then share them.
But what we’ve found is that we started needing to [bash/node/etc] script everything global. We’d have a build that was global, would run against a package,
cwd
would be that directory, it would need to then run the script which was at the root, which would then need to path back to the directory to do stuff, and just became a big mess. I knew how and why and what, but there are other devs who are on my team (and other ones that aren’t, they had a worse time). TS stuff was a pain, particularly re the tests. With TS at root needed either a specialtsconfig
that was scoped to the whole repo or we just installed the test dependencies per package anyway: went for the latter. That and ESBuild not working from the root when we started testing it last year killed the attempt at global dev dependencies for us.It’s just miles easier to add all the dependencies you need to each package. Yarn will let you keep them all on the same versions really easily. When you first install it’ll ask if you want to use the existing version, and then
upgrade-interactive
lets you update everything and bring versions into line really easily. And there doesn’t need to be any confusing global scripting, can just add the scripts on a per-package basis.YMMV, but even though it seems like it’s more hassle, it’s not, it’s much less, much simpler.