* feat(pacquet): port catalogs (types, protocol-parser, resolver, config)
Adds four new crates mirroring upstream's `catalogs/*` packages:
- pacquet-catalogs-types: `Catalog`/`Catalogs` map aliases plus
`DEFAULT_CATALOG_NAME`.
- pacquet-catalogs-protocol-parser: `parse_catalog_protocol`; folds
`catalog:` shorthand into `"default"` to match upstream.
- pacquet-catalogs-resolver: `resolve_from_catalog` with the four
upstream `PnpmError` codes (`CATALOG_ENTRY_NOT_FOUND_FOR_SPEC`,
`CATALOG_ENTRY_INVALID_RECURSIVE_DEFINITION`,
`CATALOG_ENTRY_INVALID_WORKSPACE_SPEC`,
`CATALOG_ENTRY_INVALID_SPEC`). Rust callers `match` on the result
enum directly instead of porting the TS-ergonomic
`matchCatalogResolveResult` visitor.
- pacquet-catalogs-config: `get_catalogs_from_workspace_manifest` plus
the `INVALID_CATALOGS_CONFIGURATION` mutual-exclusion check.
`pacquet-workspace`'s `WorkspaceManifest` now actually deserializes
the `catalog` and `catalogs` fields (previously dropped). The
resolver is not yet wired into the install path — `deps-installer`
hasn't been ported — but the crates are ready for that next step.
Tests are 1:1 ports of the upstream Jest suites.
* fix(pacquet): satisfy rustdoc and perfectionist lints in catalogs port
- catalogs-resolver: drop the intra-doc-link form on the
`pacquet_resolving_resolver_base::WantedDependency` reference; the
crate isn't a dependency, so rustdoc failed to resolve it under
`-D rustdoc::broken-intra-doc-links`.
- catalogs-resolver, catalogs-config: reorder the `CatalogResolutionError`
/ `InvalidCatalogsConfigurationError` derive lists to
`Debug, Display, Error, Diagnostic, Clone, PartialEq, Eq` so they
match the `prefix_then_alphabetical` rule that the CI-only
Perfectionist dylint enforces. `just ready` doesn't surface this lint
locally.
* feat(pacquet): resolve catalog: specifiers during install
Wires the catalogs port into the install path:
- `install.rs`: read `pnpm-workspace.yaml` after `find_workspace_dir`
and normalize via `get_catalogs_from_workspace_manifest` into a
`Catalogs` map. Adds `InstallError::{ReadWorkspaceManifest,
InvalidCatalogsConfiguration}` so the upstream
`ERR_PNPM_INVALID_CATALOGS_CONFIGURATION` propagates verbatim.
- `install_without_lockfile.rs`: threads the `Catalogs` map into
`ResolveDependencyTreeOptions`. (Frozen-lockfile catalog handling
needs a lockfile-snapshot pass and is a separate slice.)
- `resolve_dependency_tree`: replaces direct (importer-level)
`catalog:` bare specifiers with the catalog's recorded version
before the resolver chain dispatches. Catalog resolution does NOT
run on transitive deps, matching upstream's importer-only scope.
Misconfigured entries surface as `CatalogMisconfiguration` with
the upstream `ERR_PNPM_CATALOG_ENTRY_*` code instead of leaking
through to `SPEC_NOT_SUPPORTED_BY_ANY_RESOLVER`.
Tests:
- deps-resolver: two new unit tests prove direct-dep rewriting and
the misconfiguration code path.
- cli (e2e): `install_resolves_catalog_protocol` runs the binary
against a workspace with a `catalog:` entry and checks the
virtual-store layout; `install_surfaces_catalog_misconfiguration`
asserts the upstream message is surfaced when the catalog has no
matching alias.
* style(pacquet): apply rustfmt to catalogs test after rebase
* fix(pacquet): rename single-letter closure param in catalogs e2e test
Perfectionist's `single_letter_closure_param` lint (CI-only via
Dylint) flagged `|c|` in the box-drawing-strip filter.
简体中文 | 日本語 | 한국어 | Italiano | Português Brasileiro
Fast, disk space efficient package manager:
- Fast. Up to 2x faster than the alternatives (see benchmark).
- Efficient. Files inside
node_modulesare linked from a single content-addressable storage. - Great for monorepos.
- Strict. A package can access only dependencies that are specified in its
package.json. - Deterministic. Has a lockfile called
pnpm-lock.yaml. - Works as a Node.js version manager. See pnpm runtime.
- Works everywhere. Supports Windows, Linux, and macOS.
- Battle-tested. Used in production by teams of all sizes since 2016.
- See the full feature comparison with npm and Yarn.
To quote the Rush team:
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.
Platinum Sponsors
|
|
Gold Sponsors
|
|
|
|
|
|
|
|
|
|
|
Silver Sponsors
|
|
|
|
|
|
|
|
|
⏱️ Time.now |
Support this project by becoming a sponsor.
Background
pnpm uses a content-addressable filesystem to store all files from all module directories on a disk. When using npm, if you have 100 projects using lodash, you will have 100 copies of lodash on disk. With pnpm, lodash will be stored in a content-addressable storage, so:
- If you depend on different versions of lodash, only the files that differ are added to the store.
If lodash has 100 files, and a new version has a change only in one of those files,
pnpm updatewill only add 1 new file to the storage. - All the files are saved in a single place on the disk. When packages are installed, their files are linked from that single place consuming no additional disk space. Linking is performed using either hard-links or reflinks (copy-on-write).
As a result, you save gigabytes of space on your disk and you have a lot faster installations!
If you'd like more details about the unique node_modules structure that pnpm creates and
why it works fine with the Node.js ecosystem, read this small article: Flat node_modules is not the only way.
💖 Like this project? Let people know with a tweet
Getting Started
Benchmark
pnpm is up to 2x faster than npm and Yarn classic. See all benchmarks here.
Benchmarks on an app with lots of dependencies: