[Feature] Injected Workspace Dependency Installs
- [ ] I'd be willing to implement this feature (contributing guide)
- [ ] This feature is important to have in this repository; a contrib plugin wouldn't do
Describe the user story
When working in a large workspace, Peer Dependencies don't currently work particularly conveniently. For example, if I have the following structure:
-
@my-project/uiwith a peer dependency on"react": "^18.0.0 || ^19.0.0", and a dev dependency on"react": "18.2.0" -
@my-project/appwith a dependency on@my-project/uiand on"react": "19.0.0" -
@my-project/webwith a dependency on@my-project/uiand on"react": "18.2.0"
Then any code within @my-project/ui will reference the Dev Dependency [email protected] even when referenced from the /app project which uses [email protected]. With a regular npm: or a file: dependency, it would resolve correctly to the [email protected] peer dependency.
This may be better explained by Rush's "Injected dependencies" documentation here.
Describe the solution you'd like
2 primary aspects to this:
- An "Injected" option for installing a
workspace:dependency, by coping the files rather thansymlinking - so devDependencies aren't installed - similar to how thelink:protocol works.- In PNPM, this is done through a peerDependenciesMeta.*.optional option.
- A
yarn reinject [package]command which re-copies the files for all Injections of a specific package (or all packages ifpackageis not specified).- For PNPM, similar functionality is currently available through unofficial separate packages, pnpm-sync or pnpm-sync-dependencies-meta-injected
Describe the drawbacks of your solution
The most likely drawback with this solution is the requirement to re-run a synchronisation script after building sub-projects - in the PNPM case, the sync command is often setup to automatically run through Monorepo tools (e.g. Rush or Turborepo).
Describe alternatives you've considered
The most obvious alternative here, which is what I'm currently using projects, is to just use the existing file: dependency protocol to reference workspace dependencies, but this loses many of the nice Workspaces features that yarn and monorepo tools provide, and re-synchronising after a change requires a full yarn install which takes a significant amount of time. Additionally, this means that the yarn.lock hash changes with any changes in that dependency.
Then any code within
@my-project/uiwill reference the Dev Dependency[email protected]even when referenced from the/appproject which uses[email protected]. With a regularnpm:or afile:dependency, it would resolve correctly to the[email protected]peer dependency.
No, that's only the case if you use the node_modules or pnpm linkers, which have this inherent limitation due to their reliance on the filesystem. The default pnp linker doesn't have that and always resolves peer dependencies right.
As you mention pnpm supports making copies of workspaces to mitigate this issue, but it feels more than a little clunky to me (not that they really have a much better choice, but I think we do).
Thanks for the clarification there!
Unfortunately, using pnp (or until very recently even pnpm) linking still isn't an option as far as I'm aware for React Native / Expo development. :(
Definitely agreed that it's clunky - but IMO a significantly less messy solution that using file: dependencies.