This commit is contained in:
pgonzal 2018-09-24 09:50:46 -07:00
Родитель 3626627148
Коммит bef37355ae
3 изменённых файлов: 25 добавлений и 24 удалений

Просмотреть файл

@ -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).