-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Use ranges to define versions of dependencies for converged components #17499
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# RFC: Use ranges to define versions of dependencies | ||
|
||
@layershifter @ling1726 @miroslavstastny | ||
|
||
## Summary | ||
|
||
This RFC proposes to continue use caret (`^`) and tilde (`~`) for production dependencies of converged packages. | ||
|
||
## Problem statement | ||
|
||
The are two options to manage packages: | ||
|
||
- ranges via carets (`^1.0.0`), tildes (`~1.0.0`) or signs (`>=1.0.0`, `1.0.0 || 2.0.0`) | ||
- exact versions | ||
|
||
The preferred approach may vary on use case: applications and libraries follow different practices. Fluent UI is a library, so we should focus on the best experience for customers. | ||
|
||
Usage of exact versions in our dependencies solves a problem with different versions for us and customers so there will be a guarantee that they will use same versions as we. This should guarantee us there will be no unknown bugs caused by third party dependencies in different versions. This is a huge benefit. | ||
|
||
However, an approach with exact versions creates a different set of problems for consumers. Let's assume that we have two packages and ours will use an exact version: | ||
|
||
```json | ||
{ | ||
"name": "@fluentui/react-COMPONENT", | ||
"dependencies": { | ||
"lodash": "4.17.20" | ||
} | ||
} | ||
``` | ||
|
||
```json | ||
{ | ||
"name": "eslint", | ||
"dependencies": { | ||
"lodash": "^4.17.21" | ||
} | ||
} | ||
``` | ||
|
||
This will result in two versions of installed packages by a package manager (`yarn` in this case): | ||
|
||
``` | ||
lodash@4.17.20: | ||
version "4.17.20" | ||
resolved "https://..." | ||
integrity sha512-... | ||
|
||
lodash@^4.17.21: | ||
version "4.17.21" | ||
resolved "https://..." | ||
integrity sha512-... | ||
``` | ||
|
||
Thus a single package gets included multiple times in a Webpack bundle due to different package versions. This situation will happen without any warning, resulting in extra bloat in consumer's bundle and may lead to hard-to-find bugs. | ||
|
||
It's also harder for consumers in this case to consume security patches, for example `lodash@4.17.20` contains [a security vulnerability](https://snyk.io/vuln/SNYK-JS-LODASH-1018905) but this version will be inside consumer's application without additional movements from their side. If we will use a caret ("lodash": "^4.17.20") only a single version (a latest in a range) will be installed: | ||
|
||
``` | ||
lodash@^4.17.20, lodash@^4.17.21: | ||
version "4.17.21" | ||
resolved "https://..." | ||
integrity sha512-... | ||
``` | ||
|
||
There are workaround that customers can use in this case ([`yarn resolutions`](https://classic.yarnpkg.com/en/docs/selective-version-resolutions/), [webpack aliases](https://webpack.js.org/configuration/resolve/#resolvealias)) to use a proper version. But we should not create an additional walls for customers to properly consumer the library. | ||
|
||
There is a Webpack plugin (similar to [duplicate-package-checker-webpack-plugin](https://github.com/darrenscerri/duplicate-package-checker-webpack-plugin)) that prevents imports of duplicate versions on Teams side. | ||
|
||
## Detailed Design or Proposal | ||
|
||
Use semver ranges to define production dependencies for our customers. Exact versions can be used in non-distributed code (build and infra tools). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A couple possible issues/nuances here that I wonder if we should include in the proposal re: different versions for production and dev dependencies:
{
"packages": ["@fluentui/converged1", "@fluentui/converged2"],
"dependencies": ["lodash"]
}
{
"resolutions": {
"**/@fluentui/*/lodash": "4.17.21"
}
} However this might not work because the resolutions spec says a single There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do you mean our repo, correct? Can please expand a bit more there, I did not get the problem.
IMO we should not guarantee this, for example: we don't restrict people to use the same version of React as in our repo, why it should be different for other dependencies? It means that we should be accurate in choosing dependencies, they should follow semver. However, {
"dependencies": {
"@fluentui/react-components": "^9.0.0-alpha.36",
"@popperjs/core": "^2.9.2"
},
"resolutions": {
"**/@fluentui/*/@popperjs/core": "2.8.0"
}
} This results in two versions installed:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
With syncpack you're only allowed to depend on one semver spec for a given dep, unless you set up a
I meant within our repo, not from a customer standpoint. Yarn may sometimes decide to resolve The resolutions suggestion was also meant to be used within our repo. (If it doesn't work as I wrote it, we could do some more experimenting.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ecraig12345 so this thread is related only to our repo correct?
As I know @Hotell proposed to move out all dev dependencies to the root
Honestly I don't think that I understand what solves usage of exact versions for dev dependencies.
Are these statements correct? |
||
|
||
_Optionally_: Distribute with packages `VERSIONS` file that will contain versions of dependencies that are used on our side in machine readable format that can be potentially used by customers in their pipelines. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's not be too hasty, as I said will follow up with OSS CELA on the actual requirements ASAP There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CELA conclusion: we can only run enhanced license scan on specific versions we use, so this idea could work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By "this idea" do you mean the VERSIONS file? How would that work from a consumer's perspective, specifically re: legal? (Feel free to respond on teams if needed.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My initial idea was that we can implement a Webpack plugin that will ensure that included dependencies match versions defined in |
||
|
||
## Pros and Cons | ||
|
||
<!-- Enumerate the pros and cons of the proposal. Make sure to think about and be clear on the cons or drawbacks of this propsoal. If there are multiple proposals include this for each. --> | ||
|
||
## Discarded Solutions | ||
|
||
We potentially can use `peerDependencies` like React does, however these is no much sense in it: React does it to intentionally avoid multiple versions (it was not possible before React 17, [facebook/react#1939](https://github.com/facebook/react/issues/1939)). However, it creates issues for customers as they will need to install our dependencies, too: | ||
|
||
```bash | ||
$ yarn add @fluentui/react-COMPONENT DEPENDENCY1 DEPENDENCY2 ... DEPENDENCY999 | ||
``` | ||
|
||
_[NPMv7](https://blog.npmjs.org/post/631877012766785536/release-v700) installs `peerDependencies` by default._ | ||
|
||
## Open Issues | ||
|
||
NA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a heads up, this is not necessarily true--if a dep on
lodash@^4.17.20
resolved to4.17.20
already exists in the lockfile, and that semver spec is still referenced by another package, yarn may add a separate entry forlodash@^4.17.21
=>4.17.21
instead of resolving both to4.17.21
.(Doesn't affect the proposal since this is an issue with yarn in general, but I wanted to call it out for awareness.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you're totally right 👍 But with ranges we can at least deduplicate dependencies manually or via tools (
yarn-deduplicate
for Yarn v1 oryarn dedupe
for V2).