Improve wording
This commit is contained in:
Родитель
3626627148
Коммит
bef37355ae
|
@ -169,8 +169,8 @@ scale monorepo. Here's some potential problems that can result:
|
|||
signatures ***for the same class from the same version of the same package***. This can
|
||||
lead to highly confusing compiler errors.
|
||||
|
||||
**How Rush helps:** Rush's symlinking strategy eliminates duplication for all
|
||||
direct dependencies that are local projects in the monorepo. Unfortunately
|
||||
doppelgangers are still possible for any indirect dependencies of your projects
|
||||
if your Rush repo is configured for NPM or Yarn. But if you're using PNPM,
|
||||
the doppelganger problem is completely eliminated.
|
||||
**How Rush helps:** Rush's symlinking strategy eliminates doppelgangers only for dependencies
|
||||
that are local projects in the monorepo. If you're using NPM or Yarn as your package manager,
|
||||
unfortunately doppelgangers are still possible for any indirect dependencies. Whereas if you
|
||||
use PNPM with Rush, the doppelganger problem is fully solved (because PNPM's installation model
|
||||
accurately simulates a true directed acyclic graph).
|
||||
|
|
|
@ -10,22 +10,23 @@ Want to learn more about how JavaScript package managers work?
|
|||
|
||||
## Some history and some theory
|
||||
|
||||
First, a little background: Everyone knows that software **packages** can depend on other
|
||||
**packages**. This [dependency graph](https://en.wikipedia.org/wiki/Dependency_graph)
|
||||
is a kind of [directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph)
|
||||
Everyone knows that software **packages** can depend on other **packages**, and the resulting
|
||||
[dependency graph](https://en.wikipedia.org/wiki/Dependency_graph) is a kind of
|
||||
[directed acyclic graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph)
|
||||
in computer science. Unlike a tree data structure, a directed acyclic graph can have
|
||||
diamond-shaped branches that rejoin. For example, library **A** might import definitions from
|
||||
libraries **B** and **C**, but then **B** and **C** can both import from **D**, which creates
|
||||
a "**diamond dependency**" between these four packages. Conventionally the programming language's
|
||||
**module resolver** looks up imported packages by traversing edges of this graph, although
|
||||
the packages themselves are normally installed in a central store to be shared by different projects.
|
||||
(in other systems) the packages themselves are normally installed in a central store
|
||||
so they can be shared by many projects.
|
||||
|
||||
For historical reasons, NodeJS and NPM took a different approach of representing
|
||||
the graph physically on disk: With this approach, the graph's vertexes are package folder copies,
|
||||
and its edges are subfolder relationships, but with
|
||||
a [special rule](https://nodejs.org/api/modules.html#modules_all_together)
|
||||
the graph physically on disk: With this approach, the graph's vertexes are actual package folder copies,
|
||||
and its edges are subfolder relationships. But a folder tree's branches cannot rejoin to make diamonds,
|
||||
so NodeJS added a [special resolution rule](https://nodejs.org/api/modules.html#modules_all_together)
|
||||
whose effect is to introduce extra graph edges (pointing to the immediate children of all parent folders).
|
||||
From a computer science perspective, this rule relaxes the
|
||||
From a computer science perspective, this rule relaxes the file system's
|
||||
[tree data structure](https://en.wikipedia.org/wiki/Tree_(data_structure)) so that
|
||||
(1) it can now represent some (but not all) directed acyclic graphs, and (2) we pick up some
|
||||
extra ("phantom") edges that do not correspond to any declared package dependency.
|
||||
|
@ -44,7 +45,7 @@ NPM's approach has many unique characteristics that differ from traditional pack
|
|||
|
||||
- The installed **node_modules** tree is not unique. There are many possible ways to arrange
|
||||
package folders into a tree to approximate the directed acyclic graph, and there is no
|
||||
unique "normalized" arrangement. The tree you get depends on whatever heuristics your
|
||||
unique "normalized" arrangement. The tree you get depends on whatever heuristics the
|
||||
package manager chose to follow. NPM's own heuristics are even sensitive to
|
||||
[the order in which you add packages](http://npm.github.io/how-npm-works-docs/npm3/non-determinism.html).
|
||||
|
||||
|
@ -145,9 +146,9 @@ like this:
|
|||
|
||||
The intent is that we'll tell people to run `npm run deploy-app`, and our script will
|
||||
automatically deploy all the projects in the monorepo. That's why it's in the repo
|
||||
root folder. (Don't do that with Rush! Instead use its
|
||||
[custom commands]({% link pages/maintainer/custom_commands.md %} feature.)
|
||||
Since this hypothetical script needs to print colored text, we'll first ask people to run
|
||||
root folder. (Don't do that with Rush! Instead define a
|
||||
[custom command]({% link pages/maintainer/custom_commands.md %}).)
|
||||
Since this hypothetical script needs to print colored text, let's say we first ask people to run
|
||||
`npm install` in the repo root folder, which will install the **colors** library
|
||||
from the `devDependencies` above.
|
||||
|
||||
|
@ -169,11 +170,11 @@ The resulting folder tree would look like this:
|
|||
- ...
|
||||
```
|
||||
|
||||
But recall that NodeJS's module resolver can also look for dependencies in a parent folder.
|
||||
This means that our **lib/index.js** will be able to call `require("colors")` and find
|
||||
But recall that NodeJS's module resolver also looks for dependencies in parent folders.
|
||||
This means that our **my-library/lib/index.js** can call `require("colors")` and find
|
||||
the **colors** package, even if it doesn't appear anywhere under **my-library/node_modules**.
|
||||
This is an even more insidious way to pick up accidental phantom dependencies -- it can
|
||||
find **node_modules** folders that aren't even under your Git working directory!
|
||||
sometimes find **node_modules** folders that aren't even under your Git working directory!
|
||||
|
||||
**How Rush helps:** Rush's got you covered. The `rush install` command scans all
|
||||
potential parent folders and issues a warning if any phantom **node_modules** folders
|
||||
|
|
|
@ -27,17 +27,17 @@ The answer depends on your needs. The Rush developers don't endorse a particula
|
|||
|
||||
#### Considerations for PNPM
|
||||
|
||||
- PNPM is the only option that solves the [NPM doppelgangers]({% link pages/advanced/npm_doppelgangers.md %}) issue. In a complex monorepo, doppelgangers sometimes cause a lot of trouble, so PNPM has an important advantage in this regard.
|
||||
- PNPM is the only option that solves the [NPM doppelgangers]({% link pages/advanced/npm_doppelgangers.md %}) problem. In a complex monorepo, doppelgangers sometimes cause a lot of trouble, so PNPM has an important advantage in this regard.
|
||||
|
||||
- Although PNPM's symlinking strategy conforms to the modern NodeJS module resolution standard, many legacy packages do not, which causes compatibility problems. Teams who migrate existing projects from Yarn/NPM to PNPM often encounter "bad packages" that need workarounds or fixes. The incompatibilities generally reflect real problems with those packages: (1) forgetting to list dependencies in the **package.json** file, or (2) implementing homebrew module resolution without handling symlinks according to the standard. Most "bad" packages have straightforward fixes, but it can be daunting for a small team. (The [PNPM Gitter chat room](https://gitter.im/pnpm/pnpm) is a great resource for help, though.)
|
||||
- Although PNPM's symlinking strategy correctly follows the modern NodeJS module resolution standard, many legacy packages do not, which causes compatibility problems. Teams who migrate existing projects from Yarn/NPM to PNPM often encounter "bad packages" that need workarounds or fixes. The incompatibilities generally reflect real problems with those packages: (1) forgetting to list dependencies in the **package.json** file, or (2) implementing homebrew module resolution without handling symlinks according to the standard. Most "bad" packages have straightforward fixes, but it may seem daunting for a small team. (The [PNPM Gitter chat room](https://gitter.im/pnpm/pnpm) is a great resource for help, though.)
|
||||
|
||||
- PNPM is newer and less widely used than NPM or Yarn, but it's a solid piece of software. Microsoft uses PNPM in Rush repos with hundreds of projects and hundreds of PRs per day, and we've found it to be very fast and reliable.
|
||||
- PNPM is newer and less widely used than NPM or Yarn, but it's a solid piece of software. Microsoft uses PNPM in Rush repos with hundreds of projects and hundreds of PRs per day, and we've found it to be very fast and reliable.
|
||||
|
||||
- PNPM is currently the only option that supports the `--strict-peer-dependencies` protection (see `"strictPeerDependencies"` in **rush.json**).
|
||||
|
||||
#### Considerations for Yarn
|
||||
|
||||
- Rush's support for Yarn is relatively new and unproven, so we're eager to hear about issues and get them fixed. If you can't use PNPM, Yarn is your best bet for support from the Rush developers.
|
||||
- Rush's support for Yarn is relatively new and unproven, so we're eager to hear about issues and get them fixed.
|
||||
|
||||
- Yarn installs faster than NPM (although somewhat slower than PNPM).
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче