Do you want to request a _feature_ or report a _bug_?
Feature
What is the current behavior?
N/A
What is the expected behavior?
Provide a CLI command yarn install --peer
which will install peer dependencies specified in package.json
. That way development / testing can use the peers such as react/ng2/grunt.
@jpollard-cs I am not referring to adding a package as a peer dependency, I am referring to having a means to install all packages currently listed as peer dependencies.
Otherwise there is not a viable means of developing plugins.
npm install
Would install all packages declared in package.json dependencies section.
yarn add --peer
I expected this to install all packages declared in package.json peerDependencies section.
Is there a way to install a declared packages in peerDependencies?
My use case is development / testing of a react native module.
Here's NPM issue, which they closed: https://github.com/npm/npm/issues/11213
Apparently not important to NPM devs.
+1 this is important for library authors
I already wrote this on the NPM issue, but for Yarn people:
I wrote a cli program install a package's peer dependendencies:
# If you're using npm
npm install -g install-peerdeps
# If you're using yarn
yarn global add install-peerdeps
cd my-project-directory
install-peerdeps <package>[@<version>]
# for example
install-peerdeps @angular/core
# will install all of angular's peerdeps
If you have any problems with it please open an issue on the repo!
@nathanhleung, that package appears to install all of your dependencies peer dependencies. Which isn't quite what this ticket is about. This about installing your own package's peer dependencies.
I have fixed it with a package to do that https://www.npmjs.com/package/@team-griffin/install-self-peers
@nathanhleung you rocks.
Hmm... If one needs dependencies for development / testing, shouldn't one put them under devDependencies
? Not trying to drop a bomb or anything...
@nikolakanacki Totally see where you're coming from, I think the weirdness is that it'd be both a peer dependency and dev dependency, since you should never force your consumers installing your dev dependencies. I vote making it easy to install peers!
@nikolakanacki If you author a package that relies on another package that the user installs, you don't want it in devDependencies, that may result in a duplicate of that package in a different version., and won't makes sense in some cases...
The package looks up rules available in ESLint that are not configured in your config.
For it to make sense for a user, it needs to check the ESLint package they installed, and not some specific version your package comes with (or latest
).
So, it's a peer
dependency.
Now if you want to contribute to the project, you want to have ESLint installed in node_modules so you can test your code, without doing some npm-link with a dummy project that installs ESLint.
When the user runs yarn
, the system should not install peer deps and warn they're missing (this works).
So... a flag that makes yarn install peer deps if they're not already installed would kindly solve that problem.
yarn add <package> --peer
installs it to node_modules and adds it to package.jsonyarn add <other_package>
after that removes the installed package from node_modulesI'm currently following @nikolakanacki model and it seems to work. I agree it can be confusing and I would prefer a yarn install --peer
to install dependencies
, devDependencies
and peerDependencies
but this works just as good to me.
If I'm getting this right @kyleholzinger / @gaastonsr, you're not looking to install peerDependencies
in development mode (cd
-ed into the repo / package which has peerDependencies
, fresh clone, need to develop on those peer deps) but add them to the target project once you install the package which has peer deps?
To clarify: You install eslint-find-rules
which complains that you need eslint
as a dependency (it's a peerDependency
of eslint-find-rules
), so now you want an easy way of adding those dependencies in the peer
you're working on (current project which depends on eslint-find-rules
)? Something like "Resolve and add as new dependencies (modify package.json
and yarn.lock
) best matched peer dependencies my current dependencies require"?
If this is your point it could be super useful, I thought that you were referring to auto-installing them when developing.
The feature could be introduced for more then pure convenience, for example: multiple dependencies could depend on the same package from the peer target, but require different versions of it - this feature could make the best of it by trying to resolve to a single best-matching target (if possible).
Something to think about definitely.
If this is your point it could be super useful, I thought that you were referring to auto-installing them when developing.
This is what I'm looking for. Installing peerDependencies when I'm developing a package.
Yeah exactly @nikolakanacki! I feel like there's a great opportunity for us to help people out with managing their peer deps.
@gaastonsr need to add it to devDependencies
then - it's as simple as that. Your package is broken for development otherwise. Once you clone the project and run yarn
- everything should be installed and you should be able to run tests, etc.
Two simple and totally unrelated questions one should ask before installing said dependency in cases like this:
peerDependencies
.dependencies
(and should not be listed there) for whatever reason: Put it in devDependencies
.In other words: All the packages which are expected to be present during development and are not listed as a direct dependency of the package being developed should reside in devDependencies
. Duplicates are not an issue - nowhere in the docs does it states that dupes are not allowed / encouraged in these cases.
@nikolakanacki When we build a plugin for a package we should depend on the installed package version by the user, if we add it as a devDependency
, we'll inevitably install a different version and it will be used instead of the user's version.
Unless we defined the dependency as *
, but then Yarn should be somehow deterministic and prefer the user installed package instead of ours.
Currently it's not so:
@alexilyaev I think @nikolakanacki means to install it both as a peerDependency and devDependency.
This has the problem that we need to keep both in sync. For me it works good for now but I don't think it's ideal.
@alexilyaev when you declare a peerDependency
you declare its version as well. Unless target project has the version of that peer dependency installed which also satisfies the version you defined - yarn
/ npm
will report an error (missing peer dependency, something like that).
Non the less devDependency
has nothing to do with it, it is the one getting installed when running yarn
or npm install
inside the source package (the one declaring a peer dependency, eg: a plugin), and it is not even consulted when the package is being used by a third party package / project (a peer).
The point is: I don't see how all this is relevant?
I can see the pain of keeping them in sync, but you could easily write a bash
/ javascript
/ <whatever>
script that would check this as a post-install step in the package.json
.
The point I'm trying to make is that in no way should we break the devDependencies
sentiment, or worse yet introduce "running yarn
or npm install
does not necessarily installs all the required dependencies of this package" concept.
On the other hand yarn
introduced an even more strict policy when it comes to this, it clears up the packages not otherwise defined as dependencies
or devDependencies
so you don't run into issues later on.
@nikolakanacki Let's say my plugin accepts ^7.0.0
and the latest of the peer is 7.9.0
and the user defined in their package.json
7.4.0
.
if I'll have ^7.0.0
in devDependencies
as well, wouldn't Yarn install (for the user) both 7.9.0
and 7.4.0
?
If it does, my plugin might mistakingly use the installed 7.9.0
instead of 7.4.0
.
@alexilyaev Your package will always, as any other package in any other case, use the highest available version which satisfies the "semver range" defined in your package for this peer dep.
I'd be more specific but I don't quite understand the case you've presented, could you please clarify?
~It will warn you that you have a peerDependency
incompatibility, your plugin expects ^7.0.0
and you have version 7.4.0
.~ Updated: ^7.0.0
satisfies 7.4.0
.
wouldn't Yarn install (for the user) both 7.9.0 and 7.4.0?
Yarn doesn't install peerDependencies
for you and won't install the devDependencies
of your plugin just the dependencies in dependencies
.
@gaastonsr you're absolutely right except that ^7.0.0
is satisfied by 7.4.0
.
Peer dependencies never get installed, dev dependencies do not get installed by default if the package is not the main package. The "end-user" needs to define which peer dependencies it want's to satisfy by adding them to regular "dependencies" of the project, along with the range. It can either satisfy or not satisfy the "semver range" you require in your plugin, and the user will be notified of the latter.
Semver ranges explained by npm: https://docs.npmjs.com/misc/semver
When in doubt always check: http://jubianchi.github.io/semver-check/
@nikolakanacki to be able to easily install packages peerdependencies would be great!
@nikolakanacki Ok, so indeed when the end-user installs the package, devDependencies
do not get installed, so a package author should add peerDependencies
to devDependencies
as well.
So, this solves the local development issue.
But, it seems that a lot of projects didn't add the peer dependency as a dev dependency.
So I guess we should start spreading the word and get projects on board.
This will inevitably lead to long discussions on why it worked with npm but not with Yarn, and regardless of the results, it's going to take a while and not all projects might do the change.
So... I'm proposing to still support a way to install peer dependencies, at least so we won't have to use install-peerdeps
anymore.
What's the actual issue here? It does not seem installing one list of deps would be more complicated than installing another list of deps. Peer dependencies have been around for some years. How has this not bothered anyone?
@nikolakanacki solution makes perfect sense. It's what we're using for our library development. You need devDependencies
setup properly in the library for isolated testing (outside of a host project that supplies the needed peerDependencies
) and you need peerDependencies
for integrated testing and to ensure the host project doesn't end up with redundant/duplicated package installations because the libraries it consumes are using the same dependencies
and _not_ making proper use of peerDependencies
and devDependencies
.
There is the small headache of keepin them in sync. But as @nikolakanacki pointed out this could easily be mitigated through some post-install
scripting.
What solution?
I've run through comments fast enough and didn't notice a simple solution:
Please always install peerDependencies as regular dependencies, if it's in top level package
It perfectly fits development/test cases and does not affect installation of package as dependency. Similar to logic we have for yarn.lock. There is no need for extra "development" or whatever mode.
Actually, due to other yarn bugs related to peerDependencies, it seems exactly how it behaves in some cases.
Very much agreed, if you run ‘yarn install’ in a repo, it should install any peer dependencies that are not already listed in deps. I don’t really see how it’s different than dev dependencies in that regard— if you’re developing on that module, you _need_ these modules to be installed
I'm closing this since I can't get a clear picture of what the issue is and what the proposed solution is if there are any.
Feel free to reopen with a clarification or filing a new bug.
@BYK are you really sure you are doing right thing closing issues with 55 thumbs up and 34 comments just because it is not clear to you?
I think, it's quite straightforward: make sure peerDependencies are installed when set in top-level package.
Or let's say another way: treat peerDependencies as regular dependencies when set in current package
Adding peer dependencies also as dev dependencies, as proposed further up in this thread, will break flow-typed: https://github.com/flowtype/flow-typed/issues/379
@andvgal I'm just trying to tidy up the issues and all the discussion here from months ago was overwhelming and hard to summarize.
I think, it's quite straightforward: make sure peerDependencies are installed when set in top-level package.
Or let's say another way: treat peerDependencies as regular dependencies when set in current package
This was a great summary thank you. Reopening the issue but we need to think very carefully about the implications of installing peerDependencies by default if we decide to go that way.
Or - at least - provide a way to separately install the peer dependencies without touching the package.json file. When using add to install a peer dependency, the entry in the JSON file is modified. If you have set up your semver expression in a way different than what yarn writes by default, it is changed.
I think the idea of adding a --peer switch to install is fine, but I actually like to be able to install them one by one, as I often link some of these modules, and I go back and forth between a link and actually having the module installed. With npm, I can just run 'npm i
@jimsugg, I have been using yarn add <package...> -p
, to manually install peer dependencies already listed in the package.json, which is definitely an anti-pattern. It seems like peer dependencies should be automatically installed in development environments (if it is in-fact a peer dependency, then there should at the least be tests requiring the package).
I was looking for the same thing and came up with this Bash one-liner to install all listed peer deps (requires you to have jq installed): yarn add $(jq -r '.peerDependencies|keys|join(" ")' package.json)
.
I hope this helps someone else.
@EdwardDrapkin Thanks for that, legendary idea! I extended it and ended up adding an npm script to do this:
"install:peers": "yarn add -P $(jq -r '.peerDependencies | to_entries | map(\"\\(.key)@\\(.value | tostring)\") | join(\" \")' package.json)",
Just maintains the version spec from peerDependencies
as well ;) Only hitch here after is if you don't want to use the latest
tag, but rather another you're working on like next
or something.
@shousper here's a way without the jq
dependency:
node -e "const peers = Object.entries(require('./package.json').peerDependencies || {}).map(d => d.join('@')).join(' '); if (peers.length) process.stdout.write('yarn add -P --no-lockfile ' + String(peers));" | sh
Is there a scenario where you would not want to install a peer dependency of package Foo
when you are working directly on Foo
? I can't think of one. If Bar
is required to use Foo
, you need it when working on Foo
, and since it's a peer dependency, it can't be a regular dependency. It would then have to be installed only when working directly on the package, which is what dev dependencies do.
Because of that, I think it makes sense for yarn to treat peerDependencies the same as devDependencies but then also do what they do now, which is generate warnings. I typically just make every peer dependency a devdependency, so this would save some duplication.
Is there a reason doing that would be a problem? It would probably be a breaking change so it would have to wait until 2.0, but other than that it seems like it should be fine.
One issue may be that you want a more specific version installed for dev than your peer requirement. In that case, I would say that you should be able to override the peer version for local installs by duplicating it in devDependencies. For example
peerDepdency: react@^16.0.0
devDependency: react@~16.1.0
Would limit the local installation of react to ~16.1.0, but allow any v16 version as a peer dependency. I'm not totally sure where something like that would be necessary, but it doesn't seem invalid.
I agree @bdwain , I understand semantically what the difference between a peer and dev dependency is, but in practice they're installed the exact same way; if you're in development of the module, you need to install both dev and peer dependencies, and if you're using the module, then you only install its listed actual dependencies. If that's the case, I don't see a very good reason to not have dev and peer dependencies behave differently in the install
command
@bdwain @kyleholzinger I disagree, because peerDependencies
are strictly meant to inform the need of a dependency, not to instruct the actual action of installing the dependency.
This ensures that the issue of transient dependency versions which also exist in the root/top-level package are not silently (and incorrectly) being used. Consider babel-core
as an example.
The lacking support here in context of yarn is the ability to define as both a peer and dev dep, as described here.
That said, to keep in line with the default install spec for peer deps and to provide better dev experience .... maybe yarn could introduce a --include-peers
option for the install command?
@hulkish While I agree with the sentiment, when would be an example when you would want to declare something as a peer dependency, but _not_ as a dev dependency?
If I understand the usage correctly, especially with yarn, the list of peer dependencies is always a subset of the dev dependencies. If this is the case, then I feel like this should be officially recognized and you should not need to declare peer dependencies as dev dependencies.
The only reason I bring that up is while I think adding a command/option that would add something as both a dev and peer dependency feels like it would increase the complexity of yarn in general, and I feel like there's a solution somewhere here that's nice and simple 😄
@kyleholzinger
@hulkish While I agree with the sentiment, when would be an example when you would want to declare something as a peer dependency, but not as a dev dependency?
When you don't need it for your unit tests or.build to run. Per my experience, this is actually the only need to add them in both places, to begin with.
I think the solution here is for yarn to introduce an option that allows auto-installing peers. Keep in kind that the primary benefit of using peerDependencies is to gain vision on when incompatible transient dependencies are being used. The key here is to not break the default behavior of peer deps on install.
I think @hulkish was talking about a scenario where you rely on a dependency of a dependency to pull in one of your peer dependencies. However, I don’t think this would cause any issues because the transitive dependency would still need to match the range specified by the peer dependency, which has to be a large range anyway. If the transitive dependency was more specific than the peer dependency, that range would take precedence and all requirements would still be satisfied.
@hulkish
When you don't need it for your unit tests or.build to run
Totally get that! Although that begs the question: if something is a peer dependency, but you don't need it for your unit test or build to run, then why do you have it as a peer dependency?
Keep in kind that the primary benefit of using peerDependencies is to gain vision on when incompatible transient dependencies are being used
This I strongly agree with, I think peer dependencies are amazing right now from the consumer of the module that's declaring the dependency on a library with peer dependencies, my main gripe/pain point is when developing on modules that have peer dependencies. Sorry if there was any confusion!
My main ask/suggestion/hope-to-get-it-approved-to-work-on would be that when you yarn install
(not in production) in a module that has peer dependencies in its own package.json
that both its dev dependencies _as well as_ its peer dependencies get installed. That's the key difference, right now only dev dependencies get installed, so you have to declare deps as both dev dependencies and peer dependencies.
@bdwain @hulkish
I think @hulkish was talking about a scenario where you rely on a dependency of a dependency to pull in one of your peer dependencies
I'm specifically talking about when you do yarn install
when developing a module with peer dependencies, not when you add a module with peer dependencies to another project
@bdwain not exactly, it's definitely a slippery thing to describe. I'll try to use an example:
Let's say this is your top level package:
"dependencies": {
"foo": "^4.0.0",
"react": "^15.0.0"
}
then, your foo/package.json:
"dependencies": {
"react": "^16.0.0"
}
Per this dependency tree, when you run yarn/npm install, your node_modules dir will look like this:
node_modules/
react/ <-- @^15.0.0
foo/node_modules/react/ <-- @^16.0.0
At this point, unless you (for whatever reason) decide to voluntarily inspect your node_modules nested dir structure - you would never know there is a problem. This is not the fault ot the package manager - it completed its job accurately.
So, peerDependencies is intended to solve this use case by treating them as more of a validation check instead of an instruction to install.
"dependencies": {
"foo": "^4.0.0",
"react": "^15.0.0"
}
then, your foo/package.json:
"peetDependencies": {
"react": "^16.0.0"
}
First, let's be clear that at this point both use cases have the same problem of react versions being incompatible with each other.
The difference in this use case is; Instead of this problem silently existing. When you run npm/yarn install - the package manager has a duty to report the incompatibility as an error or warning.
Hope this explains it better.
@kyleholzinger
I'm specifically talking about when you do yarn install when developing a module with peer dependencies, not when you add a module with peer dependencies to another project
I understand. I think that the default behavior for peer deps should remain as-is. But, I think an easy solution is to allow this to be configurable via cli and/or env vars and/or .yarnrc
. Something like --install-peers-as-dev
@hulkish
But, I think an easy solution is to allow this to be configurable via cli and/or env vars and/or .yarnrc. Something like --install-peers-as-dev
Hell yes! I personally think they shouldn't be both in dev dependencies and peer dependencies, but that could be a separate discussion. I think adding this option would be a solid compromise and a great way to solve the problem in the meantime-- I'm gonna check it out and try to throw something together :)
@kyleholzinger this is a good place to start https://github.com/yarnpkg/yarn/blob/master/src/cli/commands/install.js#L58
Also, I encourage in your pr that while forwarding peerDependencies to be installed as dev - you want to make sure any compatibility warnings or errors are still reported.
@hulkish I understand what peer dependencies are. My point was that in practice, you always need them installed for development purposes, so they should be treated as devDependencies in addition to their role of giving warnings when versions mismatch.
If a package Foo has a peer dependency on Bar, the only scenario where you would not want Bar installed when working directly on Foo would be if your build and automated tests had no need of Bar. But if that were the case, that would just mean your build/tests did not exercise the functionality that required the peer dependency on Bar in the first place, which should not be the common case.
I don't really think an option to enable auto-installing of peer dependencies is the right thing to do because it would be needed way more often than not (unless you also specified peers as dev dependencies, which defeats the point). If an option is needed more often than not, it should be the default and there should be an option to disable it instead. yarn install
should work without options for the most common cases, and needing peer dependencies to be treated as dev dependencies is the most common case. Adding an extra step for the average user is just a worse experience.
And adding them automatically to both dev and peer still has the problem of duplicating the dependency in two places, which IMO is a problem and should not be necessary.
Either way, those warnings/errors need to be reported.
How is it possible that we don't have this feature yet? I am new to creating npm packages, but it looks like it is part of the core workflow of developing npm packages.
Same @biels! I actually totally forgot I said I was gonna work on this so haven't started yet, I'll try to work on it when I can though so we can at least have people put this option in a .yarnrc
and not have to worry about it all the time
I think this feature is extremely important.
I can think of many use-cases, especially when it comes to library authors.
Let's say I want to develop a component library which has react
and react-dom
as peerDependencies
(I don't want them to eventually be bundled by whoever uses it, that would duplicate those two libraries and could cause problems, which I have experienced before).
I want to test my component library with those peerDependencies
installed, so I'd like to run yarn --include-peerDeps
(or something like that) on CI and on my machine, but when someone runs yarn
on their own package I want them to use their own react
and react-dom
dependencies to run their tests (doesn't matter how they do it).
I also think that since we've got modules out there that do exactly this and have plenty of downloads it already justifies making this feature native. (The old motto of "make something people want" applies here IMO)
I can't see how this could be a bad practice since it would have to be explicitly toggled through --include-peerDeps
.
I'm happy to discuss and help with the implementation if needed.
@lucasfcosta couldn't agree more! I don't have a ton of time to work on it these days so have been trying to poke around when I can, but can't seem to get the option truthy from the command line option. Would love a helping hand though :)
@lucasfcosta here's my bad implementation of where I thought the option might live, I have no idea though. Was trying to follow the pattern of a couple other of the command line options, but didn't seem to work.
I'm currently taking the duplication approach (devDependencies and peerDependencies) but would very much love this feature so I can stop doing that.
I need that too. in the meantime i've done a little node task
const pkg = require('./package.json');
const entries = Object.entries(pkg.peerDependencies);
const shell = require('shelljs');
let deps = ['yarn add'];
for ([dep, version] of entries) {
deps[deps.length] = `${dep}@${version}`;
}
deps.push('--peer');
const cmd = deps.join(' ');
console.log('Installing peer deps!\n -----', cmd);
const result = shell.exec(cmd);
if (result.code !== 0) {
shell.echo('Error: installing peer dependencies');
shell.exit(1);
}
Cool! Now we can just paste it into yarn and add a flag or whatever.
On Thu, Oct 4, 2018, 17:29 Pasquale Mangialavori notifications@github.com
wrote:
I need that too. in the meantime i've done a little node task
`const pkg = require('./package.json');
const entries = Object.entries(pkg.peerDependencies);
const shell = require('shelljs');let deps = ['yarn add'];
for ([dep, version] of entries) {
deps[deps.length] = ${dep}@${version};
}deps.push('--peer');
const cmd = deps.join(' ');
console.log('Installing peer deps!n -----', cmd);
const result = shell.exec(cmd);if (result.code !== 0) {
shell.echo('Error: installing peer dependencies');
shell.exit(1);
}`—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/yarnpkg/yarn/issues/1503#issuecomment-427063046, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AE64MGxna2iQ-BFNiC52mIVro8sydPu1ks5uhilsgaJpZM4KiMuo
.
I'm also taking the duplication approach as @RWOverdijk said. Love to see this feature in the future.
Btw, does anyone have a better solution so that we don't need to add one package twice(devDependencies and peerDependencies)?
Hello from the future. This is still an issue for package/lib developers. Duplicate deps shouldn't be the answer.
I would definitely like to see this feature added. Without adding react
to my package's devDependencies
, I'm unable to run tests on my code.
A flag for installing the packages in the local peerDependencies
object would be nice but I also don't see _any_ downside to making installing _only_ local peerDependencies
the default behavior. And semantically it makes sense, the peer dependencies need to be there for the package to work everywhere else, why would it be any different locally?
My opinion on the usage for a flag would be the following because of its alignment with the
yarn add --peer
command.
yarn --peer
# and
yarn install --peer
At the very least the flag should be introduced.
I wonder if using separate test
app is a good solution here? You could then add all your peerDependencies
as dependencies
of the test
app. This seems to do the following:
peerDependencies
out of devDependencies
in your libraryInvalid hook call
error when you forget to clear out node_modules
from your package when using local dependencies, like "my-package": "file:/path/to/my-package"
If more info would be helpful for folks, I created a demo repo in an effort to model this approach and document the issue:
https://github.com/jamstooks/package-peer-dependencies
For now, you should be able to run npx install-peerdeps <package>
and the CLI then asks you whether you want to use Yarn for installing, if you have a yarn lock etc. in the folder. At least that worked for me just now.
More discussion from Arcanis ("fail the install on missing peer deps") and Isaac ("install peer deps automatically") over here in this NPM RFC:
This blog post helped me with this issue: https://dev.to/yvonnickfrin/how-to-handle-peer-dependencies-when-developing-modules-18fa
I have a related issue I think.
For the minimal repro I have this list of dependencies:
"dependencies": {
"prismic-reactjs": "^1.2.0"
},
"peerDependencies": {
"react": "^16.12.0"
},
"devDependencies": {
"react": "^16.12.0",
"redux": "^4.0.5"
}
Explanation: my package relies on react
presence at runtime and also needs it for testing. redux
is here for demo purposes, see below.
Now, prismic-reactjs
also relies on react
as its peer dependency.
What happens after yarn --production
is called?
React is both _installed_ and _hoisted_
I would expect _none_ of the two to happen.
For the demo purposes redux
is added here which is _not_ installed which (I think) proves the transient peer dependency is the cause of the issue.
Repro repo: https://github.com/emirotin/yarn-react-repro. Run test.sh
for the quick check.
npm has this feature now with v7... any reason not add this to yarn?
@sajadghawami as far as I know, @arcanis has some pretty big reservations about doing this:
Most helpful comment
+1 this is important for library authors