зеркало из https://github.com/microsoft/rnx-kit.git
docs(metro-plugin-duplicates-checker): add section about deduping (#2941)
This commit is contained in:
Родитель
7aae48f047
Коммит
f82018c955
|
@ -0,0 +1,2 @@
|
||||||
|
---
|
||||||
|
---
|
|
@ -61,3 +61,171 @@ checkForDuplicatePackages(mySourceMap, {
|
||||||
| bannedModules | string[] | `[]` | List of modules that are banned. |
|
| bannedModules | string[] | `[]` | List of modules that are banned. |
|
||||||
| ignoredModules | string[] | `[]` | List of modules that can be ignored. |
|
| ignoredModules | string[] | `[]` | List of modules that can be ignored. |
|
||||||
| throwOnError | boolean | `true` | Whether to throw when duplicates are found. |
|
| throwOnError | boolean | `true` | Whether to throw when duplicates are found. |
|
||||||
|
|
||||||
|
## Resolving Duplicates
|
||||||
|
|
||||||
|
So you have duplicates in your bundle, now what? Depending on your specific
|
||||||
|
needs, we have several options.
|
||||||
|
|
||||||
|
Let's use a specific example:
|
||||||
|
|
||||||
|
```
|
||||||
|
error @fluentui-react-native/text (found 2 copies)
|
||||||
|
warn 0.21.14 /~/node_modules/@fluentui-react-native/text
|
||||||
|
warn 0.22.7 /~/node_modules/@fluentui-react-native/link/node_modules/@fluentui-react-native/text
|
||||||
|
```
|
||||||
|
|
||||||
|
This one occurs because `@fluentui-react-native/link` declares a dependency on
|
||||||
|
`@fluentui-react-native/text` using a wide version range, `>=0.21.14 <1.0.0`.
|
||||||
|
|
||||||
|
Our project depends on `@fluentui-react-native/text@^0.21.14`, but package
|
||||||
|
managers will typically still try to resolve `>=0.21.14 <1.0.0` instead of using
|
||||||
|
the existing resolution. This results in the duplicate error we see above.
|
||||||
|
|
||||||
|
From here, we have several options:
|
||||||
|
|
||||||
|
- [Manual Dedupe](#manual-dedupe)
|
||||||
|
- [Using Tools](#using-tools)
|
||||||
|
- [Help Metro Resolve Correct Version](#help-metro-resolve-correct-version)
|
||||||
|
- [Last Resort: Force Resolution](#last-resort-force-resolution)
|
||||||
|
|
||||||
|
### Manual Dedupe
|
||||||
|
|
||||||
|
This method is error-prone, especially if you have a lot of duplicates. It works
|
||||||
|
if you have very few entries. It varies a lot depending on the package manager
|
||||||
|
you're using.
|
||||||
|
|
||||||
|
The project in our example uses Yarn Classic: Open `yarn.lock` and look for
|
||||||
|
`@fluentui-react-native/text`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
"@fluentui-react-native/text@0.21.14", "@fluentui-react-native/text@^0.21.14":
|
||||||
|
version "0.21.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fluentui-react-native/text/-/text-0.21.14.tgz#04918a9558770ec551cbdac87ca1534bfccaeffb"
|
||||||
|
integrity sha1-BJGKlVh3DsVRy9rIfKFTS/zK7/s=
|
||||||
|
dependencies:
|
||||||
|
"@fluentui-react-native/adapters" ">=0.11.3 <1.0.0"
|
||||||
|
"@fluentui-react-native/framework" "0.11.10"
|
||||||
|
"@fluentui-react-native/interactive-hooks" ">=0.24.12 <1.0.0"
|
||||||
|
"@fluentui-react-native/theme-tokens" ">=0.25.4 <1.0.0"
|
||||||
|
"@fluentui-react-native/tokens" ">=0.21.6 <1.0.0"
|
||||||
|
"@uifabricshared/foundation-compose" "^1.14.12"
|
||||||
|
tslib "^2.3.1"
|
||||||
|
|
||||||
|
"@fluentui-react-native/text@>=0.21.14 <1.0.0":
|
||||||
|
version "0.22.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fluentui-react-native/text/-/text-0.22.7.tgz#bd11768d3cd69337ad2ec4be76ee88d6749ca24f"
|
||||||
|
integrity sha1-vRF2jTzWkzetLsS+du6I1nScok8=
|
||||||
|
dependencies:
|
||||||
|
"@fluentui-react-native/adapters" ">=0.12.0 <1.0.0"
|
||||||
|
"@fluentui-react-native/framework" "0.13.6"
|
||||||
|
"@fluentui-react-native/interactive-hooks" ">=0.25.7 <1.0.0"
|
||||||
|
"@fluentui-react-native/theme-tokens" ">=0.26.5 <1.0.0"
|
||||||
|
"@fluentui-react-native/tokens" ">=0.22.5 <1.0.0"
|
||||||
|
"@uifabricshared/foundation-compose" "^1.14.20"
|
||||||
|
tslib "^2.3.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
We can see there are two entries, one being resolved to 0.21.14 and the other to
|
||||||
|
0.22.7. In this case, since we want to keep 0.21.x and the version ranges just
|
||||||
|
happens to be satisfied by this. We can merge the two entries like below:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
"@fluentui-react-native/text@0.21.14", "@fluentui-react-native/text@>=0.21.14 <1.0.0", "@fluentui-react-native/text@^0.21.14":
|
||||||
|
version "0.21.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fluentui-react-native/text/-/text-0.21.14.tgz#04918a9558770ec551cbdac87ca1534bfccaeffb"
|
||||||
|
integrity sha1-BJGKlVh3DsVRy9rIfKFTS/zK7/s=
|
||||||
|
dependencies:
|
||||||
|
"@fluentui-react-native/adapters" ">=0.11.3 <1.0.0"
|
||||||
|
"@fluentui-react-native/framework" "0.11.10"
|
||||||
|
"@fluentui-react-native/interactive-hooks" ">=0.24.12 <1.0.0"
|
||||||
|
"@fluentui-react-native/theme-tokens" ">=0.25.4 <1.0.0"
|
||||||
|
"@fluentui-react-native/tokens" ">=0.21.6 <1.0.0"
|
||||||
|
"@uifabricshared/foundation-compose" "^1.14.12"
|
||||||
|
tslib "^2.3.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we should only have one copy of `@fluentui-react-native/text`.
|
||||||
|
|
||||||
|
Our example is relatively simple. Sometimes you have to go further up the
|
||||||
|
dependency chain and dedupe dependees.
|
||||||
|
|
||||||
|
Fortunately, we can use tools in most cases.
|
||||||
|
|
||||||
|
### Using Tools
|
||||||
|
|
||||||
|
If you're using Yarn Classic, there is a tool, [`yarn-deduplicate`][], for
|
||||||
|
deduplicating everything in `yarn.lock`. You can run it like so:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npx yarn-deduplicate
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, it will try to dedupe to the highest version. In our example,
|
||||||
|
however, we want to keep using 0.21.x. We should also limit the number of
|
||||||
|
packages that get deduped to make it easier to review later. `yarn-deduplicate`
|
||||||
|
provides many options, but we'll be using the `fewer` strategy and the
|
||||||
|
`--scopes` flag to only target `@fluentui-react-native` packages:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npx yarn-deduplicate --strategy fewer --scopes @fluentui-react-native
|
||||||
|
```
|
||||||
|
|
||||||
|
You can read more about `yarn-deduplicate` and available options here:
|
||||||
|
https://github.com/scinos/yarn-deduplicate#readme
|
||||||
|
|
||||||
|
If you're using modern Yarn or other package managers, check out their built-in
|
||||||
|
dedupe command:
|
||||||
|
|
||||||
|
- **Yarn:** https://yarnpkg.com/cli/dedupe
|
||||||
|
- **npm:** https://docs.npmjs.com/cli/commands/npm-dedupe
|
||||||
|
- **pnpm:** https://pnpm.io/cli/dedupe
|
||||||
|
|
||||||
|
### Help Metro Resolve Correct Version
|
||||||
|
|
||||||
|
If, for some reason, you cannot dedupe the package, you can instead configure
|
||||||
|
Metro to resolve the correct version by telling it which version to use (with
|
||||||
|
[`resolver.extraNodeModules`][]) and blocking every other copy (with
|
||||||
|
[`resolver.blockList`][]):
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
resolver: {
|
||||||
|
extraNodeModules: {
|
||||||
|
"@fluentui-react-native/text":
|
||||||
|
"/~/my-project/node_modules/@fluentui-react-native/text",
|
||||||
|
},
|
||||||
|
blockList: [
|
||||||
|
/(?<!\/~\/my-project)\/node_modules\/@fluentui-react-native\/text\/.*/,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
You don't have to write these entries manually. We have helper functions in
|
||||||
|
[`@rnx-kit/metro-config`][] for generating them dynamically.
|
||||||
|
|
||||||
|
### Last Resort: Force Resolution
|
||||||
|
|
||||||
|
As a last resort, if everything else fails, you can manually override package
|
||||||
|
resolutions. We don't recommend this solution because it forces a single version
|
||||||
|
in all workspaces. For example, if you have two projects that have nothing to do
|
||||||
|
with each other, they will both be forced to use the same version even though
|
||||||
|
they could be using different versions. It also adds maintenance overhead
|
||||||
|
because you will have to manually update the version as dependees update theirs.
|
||||||
|
|
||||||
|
If you've decided that you have no other options, you can find the appropriate
|
||||||
|
documentation for your package manager below:
|
||||||
|
|
||||||
|
- **Yarn:** https://yarnpkg.com/configuration/manifest#resolutions
|
||||||
|
- **npm:** https://docs.npmjs.com/cli/v10/configuring-npm/package-json#overrides
|
||||||
|
- **pnpm:** https://pnpm.io/package_json#pnpmoverrides
|
||||||
|
|
||||||
|
<!-- References -->
|
||||||
|
|
||||||
|
[`@rnx-kit/metro-config`]:
|
||||||
|
https://github.com/microsoft/rnx-kit/blob/main/packages/metro-config/README.md#ensuring-a-single-instance-of-a-package
|
||||||
|
[`resolver.blockList`]: https://metrobundler.dev/docs/configuration/#blocklist
|
||||||
|
[`resolver.extraNodeModules`]:
|
||||||
|
https://metrobundler.dev/docs/configuration/#extranodemodules
|
||||||
|
[`yarn-deduplicate`]: https://github.com/scinos/yarn-deduplicate
|
||||||
|
|
Загрузка…
Ссылка в новой задаче