format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
This commit is contained in:
@@ -3,7 +3,7 @@ name: pnpm
|
||||
description: Node.js package manager with strict dependency resolution. Use when running pnpm specific commands, configuring workspaces, or managing dependencies with catalogs, patches, or overrides.
|
||||
metadata:
|
||||
author: Anthony Fu
|
||||
version: "2026.1.28"
|
||||
version: '2026.1.28'
|
||||
source: Generated from https://github.com/pnpm/pnpm, scripts located at https://github.com/antfu/skills
|
||||
---
|
||||
|
||||
@@ -15,28 +15,28 @@ pnpm is a fast, disk space efficient package manager. It uses a content-addressa
|
||||
|
||||
## Core
|
||||
|
||||
| Topic | Description | Reference |
|
||||
|-------|-------------|-----------|
|
||||
| CLI Commands | Install, add, remove, update, run, exec, dlx, and workspace commands | [core-cli](references/core-cli.md) |
|
||||
| Configuration | pnpm-workspace.yaml, .npmrc settings, and package.json fields | [core-config](references/core-config.md) |
|
||||
| Workspaces | Monorepo support with filtering, workspace protocol, and shared lockfile | [core-workspaces](references/core-workspaces.md) |
|
||||
| Store | Content-addressable storage, hard links, and disk efficiency | [core-store](references/core-store.md) |
|
||||
| Topic | Description | Reference |
|
||||
| ------------- | ------------------------------------------------------------------------ | ------------------------------------------------ |
|
||||
| CLI Commands | Install, add, remove, update, run, exec, dlx, and workspace commands | [core-cli](references/core-cli.md) |
|
||||
| Configuration | pnpm-workspace.yaml, .npmrc settings, and package.json fields | [core-config](references/core-config.md) |
|
||||
| Workspaces | Monorepo support with filtering, workspace protocol, and shared lockfile | [core-workspaces](references/core-workspaces.md) |
|
||||
| Store | Content-addressable storage, hard links, and disk efficiency | [core-store](references/core-store.md) |
|
||||
|
||||
## Features
|
||||
|
||||
| Topic | Description | Reference |
|
||||
|-------|-------------|-----------|
|
||||
| Catalogs | Centralized dependency version management for workspaces | [features-catalogs](references/features-catalogs.md) |
|
||||
| Overrides | Force specific versions of dependencies including transitive | [features-overrides](references/features-overrides.md) |
|
||||
| Patches | Modify third-party packages with custom fixes | [features-patches](references/features-patches.md) |
|
||||
| Aliases | Install packages under custom names using npm: protocol | [features-aliases](references/features-aliases.md) |
|
||||
| Hooks | Customize resolution with .pnpmfile.cjs hooks | [features-hooks](references/features-hooks.md) |
|
||||
| Peer Dependencies | Auto-install, strict mode, and dependency rules | [features-peer-deps](references/features-peer-deps.md) |
|
||||
| Topic | Description | Reference |
|
||||
| ----------------- | ------------------------------------------------------------ | ------------------------------------------------------ |
|
||||
| Catalogs | Centralized dependency version management for workspaces | [features-catalogs](references/features-catalogs.md) |
|
||||
| Overrides | Force specific versions of dependencies including transitive | [features-overrides](references/features-overrides.md) |
|
||||
| Patches | Modify third-party packages with custom fixes | [features-patches](references/features-patches.md) |
|
||||
| Aliases | Install packages under custom names using npm: protocol | [features-aliases](references/features-aliases.md) |
|
||||
| Hooks | Customize resolution with .pnpmfile.cjs hooks | [features-hooks](references/features-hooks.md) |
|
||||
| Peer Dependencies | Auto-install, strict mode, and dependency rules | [features-peer-deps](references/features-peer-deps.md) |
|
||||
|
||||
## Best Practices
|
||||
|
||||
| Topic | Description | Reference |
|
||||
|-------|-------------|-----------|
|
||||
| CI/CD Setup | GitHub Actions, GitLab CI, Docker, and caching strategies | [best-practices-ci](references/best-practices-ci.md) |
|
||||
| Migration | Migrating from npm/Yarn, handling phantom deps, monorepo migration | [best-practices-migration](references/best-practices-migration.md) |
|
||||
| Performance | Install optimizations, store caching, workspace parallelization | [best-practices-performance](references/best-practices-performance.md) |
|
||||
| Topic | Description | Reference |
|
||||
| ----------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------- |
|
||||
| CI/CD Setup | GitHub Actions, GitLab CI, Docker, and caching strategies | [best-practices-ci](references/best-practices-ci.md) |
|
||||
| Migration | Migrating from npm/Yarn, handling phantom deps, monorepo migration | [best-practices-migration](references/best-practices-migration.md) |
|
||||
| Performance | Install optimizations, store caching, workspace parallelization | [best-practices-performance](references/best-practices-performance.md) |
|
||||
|
||||
@@ -21,16 +21,16 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'pnpm'
|
||||
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm test
|
||||
- run: pnpm build
|
||||
@@ -278,7 +278,7 @@ jobs:
|
||||
5. **Use `--filter`** in monorepos to build only what changed
|
||||
6. **Multi-stage Docker builds** for smaller images
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/continuous-integration
|
||||
- https://github.com/pnpm/action-setup
|
||||
|
||||
@@ -50,12 +50,14 @@ pnpm import
|
||||
pnpm is strict about dependencies. If code imports a package not in `package.json`, it will fail.
|
||||
|
||||
**Problem:**
|
||||
|
||||
```js
|
||||
// Works with npm (hoisted), fails with pnpm
|
||||
import lodash from 'lodash' // Not in dependencies, installed by another package
|
||||
import lodash from 'lodash'; // Not in dependencies, installed by another package
|
||||
```
|
||||
|
||||
**Solution:** Add missing dependencies explicitly:
|
||||
|
||||
```bash
|
||||
pnpm add lodash
|
||||
```
|
||||
@@ -65,17 +67,20 @@ pnpm add lodash
|
||||
pnpm reports peer dependency issues by default.
|
||||
|
||||
**Option 1:** Let pnpm auto-install:
|
||||
|
||||
```ini
|
||||
# .npmrc (default in pnpm v8+)
|
||||
auto-install-peers=true
|
||||
```
|
||||
|
||||
**Option 2:** Install manually:
|
||||
|
||||
```bash
|
||||
pnpm add react react-dom
|
||||
```
|
||||
|
||||
**Option 3:** Suppress warnings if acceptable:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
@@ -120,12 +125,14 @@ pnpm install
|
||||
### From npm Workspaces
|
||||
|
||||
1. Create `pnpm-workspace.yaml`:
|
||||
|
||||
```yaml
|
||||
packages:
|
||||
- 'packages/*'
|
||||
```
|
||||
|
||||
2. Update internal dependencies to use workspace protocol:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
@@ -143,18 +150,21 @@ pnpm install
|
||||
### From Yarn Workspaces
|
||||
|
||||
1. Remove Yarn-specific files:
|
||||
|
||||
```bash
|
||||
rm yarn.lock .yarnrc.yml
|
||||
rm -rf .yarn
|
||||
```
|
||||
|
||||
2. Create `pnpm-workspace.yaml` matching `workspaces` in package.json:
|
||||
|
||||
```yaml
|
||||
packages:
|
||||
- 'packages/*'
|
||||
```
|
||||
|
||||
3. Update `package.json` - remove Yarn workspace config if not needed:
|
||||
|
||||
```json
|
||||
{
|
||||
// Remove "workspaces" field (optional, pnpm uses pnpm-workspace.yaml)
|
||||
@@ -162,10 +172,11 @@ pnpm install
|
||||
```
|
||||
|
||||
4. Convert workspace references:
|
||||
|
||||
```json
|
||||
// From Yarn
|
||||
"@myorg/utils": "*"
|
||||
|
||||
|
||||
// To pnpm
|
||||
"@myorg/utils": "workspace:*"
|
||||
```
|
||||
@@ -184,7 +195,7 @@ pnpm -r run build
|
||||
# Lerna: run in specific package
|
||||
lerna run build --scope=@myorg/app
|
||||
|
||||
# pnpm equivalent
|
||||
# pnpm equivalent
|
||||
pnpm --filter @myorg/app run build
|
||||
|
||||
# Lerna: publish
|
||||
@@ -227,8 +238,8 @@ Most scripts work unchanged. Update pnpm-specific patterns:
|
||||
"build:all": "npm run build --workspaces",
|
||||
// pnpm: use -r flag
|
||||
"build:all": "pnpm -r run build",
|
||||
|
||||
// npm: run in specific workspace
|
||||
|
||||
// npm: run in specific workspace
|
||||
"dev:app": "npm run dev -w packages/app",
|
||||
// pnpm: use --filter
|
||||
"dev:app": "pnpm --filter @myorg/app run dev"
|
||||
@@ -250,6 +261,7 @@ Update CI configuration:
|
||||
```
|
||||
|
||||
Add to `package.json` for Corepack:
|
||||
|
||||
```json
|
||||
{
|
||||
"packageManager": "[email protected]"
|
||||
@@ -283,7 +295,7 @@ yarn install
|
||||
|
||||
Keep old lockfile in git history for easy rollback.
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/installation
|
||||
- https://pnpm.io/cli/import
|
||||
|
||||
@@ -28,6 +28,7 @@ pnpm install --prefer-offline
|
||||
```
|
||||
|
||||
Or configure globally:
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
prefer-offline=true
|
||||
@@ -95,6 +96,7 @@ store-dir=~/.pnpm-store
|
||||
```
|
||||
|
||||
Benefits:
|
||||
|
||||
- Packages downloaded once for all projects
|
||||
- Hard links save disk space
|
||||
- Faster installs from cache
|
||||
@@ -122,6 +124,7 @@ pnpm -r --parallel run build
|
||||
```
|
||||
|
||||
Control concurrency:
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
workspace-concurrency=8
|
||||
@@ -154,6 +157,7 @@ pnpm -r run build
|
||||
```
|
||||
|
||||
For explicit sequential builds:
|
||||
|
||||
```bash
|
||||
pnpm -r --workspace-concurrency=1 run build
|
||||
```
|
||||
@@ -201,6 +205,7 @@ shared-workspace-lockfile=true
|
||||
```
|
||||
|
||||
Benefits:
|
||||
|
||||
- Single source of truth
|
||||
- Faster resolution
|
||||
- Consistent versions across workspace
|
||||
@@ -251,7 +256,7 @@ Optimized `.npmrc` for performance:
|
||||
prefer-offline=true
|
||||
auto-install-peers=true
|
||||
|
||||
# Build optimization
|
||||
# Build optimization
|
||||
side-effects-cache=true
|
||||
# Only build what's necessary
|
||||
onlyBuiltDependencies[]=esbuild
|
||||
@@ -267,16 +272,16 @@ workspace-concurrency=4
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Scenario | Command/Setting |
|
||||
|----------|-----------------|
|
||||
| CI installs | `pnpm install --frozen-lockfile` |
|
||||
| Offline development | `--prefer-offline` |
|
||||
| Skip native builds | `neverBuiltDependencies` |
|
||||
| Parallel workspace | `pnpm -r --parallel run build` |
|
||||
| Build changed only | `pnpm --filter "...[origin/main]" build` |
|
||||
| Clean store | `pnpm store prune` |
|
||||
| Scenario | Command/Setting |
|
||||
| ------------------- | ---------------------------------------- |
|
||||
| CI installs | `pnpm install --frozen-lockfile` |
|
||||
| Offline development | `--prefer-offline` |
|
||||
| Skip native builds | `neverBuiltDependencies` |
|
||||
| Parallel workspace | `pnpm -r --parallel run build` |
|
||||
| Build changed only | `pnpm --filter "...[origin/main]" build` |
|
||||
| Clean store | `pnpm store prune` |
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/npmrc
|
||||
- https://pnpm.io/cli/install
|
||||
|
||||
@@ -10,6 +10,7 @@ pnpm provides a comprehensive CLI for package management with commands similar t
|
||||
## Installation Commands
|
||||
|
||||
### Install all dependencies
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
# or
|
||||
@@ -17,6 +18,7 @@ pnpm i
|
||||
```
|
||||
|
||||
### Add a dependency
|
||||
|
||||
```bash
|
||||
# Production dependency
|
||||
pnpm add <pkg>
|
||||
@@ -38,6 +40,7 @@ pnpm add <pkg>@^1.0.0
|
||||
```
|
||||
|
||||
### Remove a dependency
|
||||
|
||||
```bash
|
||||
pnpm remove <pkg>
|
||||
pnpm rm <pkg>
|
||||
@@ -46,6 +49,7 @@ pnpm un <pkg>
|
||||
```
|
||||
|
||||
### Update dependencies
|
||||
|
||||
```bash
|
||||
# Update all
|
||||
pnpm update
|
||||
@@ -66,6 +70,7 @@ pnpm up -i
|
||||
## Script Commands
|
||||
|
||||
### Run scripts
|
||||
|
||||
```bash
|
||||
pnpm run <script>
|
||||
# or shorthand
|
||||
@@ -79,6 +84,7 @@ pnpm run --if-present build
|
||||
```
|
||||
|
||||
### Execute binaries
|
||||
|
||||
```bash
|
||||
# Run local binary
|
||||
pnpm exec <command>
|
||||
@@ -88,6 +94,7 @@ pnpm exec eslint .
|
||||
```
|
||||
|
||||
### dlx - Run without installing
|
||||
|
||||
```bash
|
||||
# Like npx but for pnpm
|
||||
pnpm dlx <pkg>
|
||||
@@ -100,6 +107,7 @@ pnpm dlx degit user/repo my-project
|
||||
## Workspace Commands
|
||||
|
||||
### Run in all packages
|
||||
|
||||
```bash
|
||||
# Run script in all workspace packages
|
||||
pnpm -r run <script>
|
||||
@@ -115,6 +123,7 @@ pnpm --filter "@myorg/*" run lint
|
||||
```
|
||||
|
||||
### Filter patterns
|
||||
|
||||
```bash
|
||||
# By package name
|
||||
pnpm --filter <pkg-name> <command>
|
||||
@@ -136,6 +145,7 @@ pnpm --filter "...[origin/main]" build
|
||||
## Other Useful Commands
|
||||
|
||||
### Link packages
|
||||
|
||||
```bash
|
||||
# Link global package
|
||||
pnpm link --global
|
||||
@@ -146,6 +156,7 @@ pnpm link --global <pkg>
|
||||
```
|
||||
|
||||
### Patch packages
|
||||
|
||||
```bash
|
||||
# Create patch for a package
|
||||
pnpm patch <pkg>@<version>
|
||||
@@ -158,6 +169,7 @@ pnpm patch-remove <pkg>
|
||||
```
|
||||
|
||||
### Store management
|
||||
|
||||
```bash
|
||||
# Show store path
|
||||
pnpm store path
|
||||
@@ -170,6 +182,7 @@ pnpm store status
|
||||
```
|
||||
|
||||
### Other commands
|
||||
|
||||
```bash
|
||||
# Clean install (like npm ci)
|
||||
pnpm install --frozen-lockfile
|
||||
@@ -220,7 +233,7 @@ pnpm install -P
|
||||
pnpm install --no-optional
|
||||
```
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/cli/install
|
||||
- https://pnpm.io/cli/add
|
||||
|
||||
@@ -16,7 +16,7 @@ The recommended location for pnpm-specific configurations. Place at project root
|
||||
packages:
|
||||
- 'packages/*'
|
||||
- 'apps/*'
|
||||
- '!**/test/**' # Exclude pattern
|
||||
- '!**/test/**' # Exclude pattern
|
||||
|
||||
# Catalog for shared dependency versions
|
||||
catalog:
|
||||
@@ -67,7 +67,7 @@ shamefully-hoist=false
|
||||
# Store location
|
||||
store-dir=~/.pnpm-store
|
||||
|
||||
# Virtual store location
|
||||
# Virtual store location
|
||||
virtual-store-dir=node_modules/.pnpm
|
||||
|
||||
# Lockfile settings
|
||||
@@ -130,7 +130,7 @@ package-extensions[foo@1].peerDependencies.bar=*
|
||||
Settings are read in order (later overrides earlier):
|
||||
|
||||
1. `/etc/npmrc` - Global config
|
||||
2. `~/.npmrc` - User config
|
||||
2. `~/.npmrc` - User config
|
||||
3. `<project>/.npmrc` - Project config
|
||||
4. Environment variables: `npm_config_<key>=<value>`
|
||||
5. `pnpm-workspace.yaml` settings field
|
||||
@@ -180,7 +180,7 @@ pnpm reads specific fields from `package.json`:
|
||||
3. **Catalogs**: Centralized version management
|
||||
4. **Content-addressable store**: Shared across projects
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/pnpm-workspace_yaml
|
||||
- https://pnpm.io/npmrc
|
||||
|
||||
@@ -153,6 +153,7 @@ For CI/CD, you can share the store:
|
||||
## Troubleshooting
|
||||
|
||||
### Store corruption
|
||||
|
||||
```bash
|
||||
# Verify and fix store
|
||||
pnpm store status
|
||||
@@ -160,18 +161,20 @@ pnpm store prune
|
||||
```
|
||||
|
||||
### Hard link issues (network drives, Docker)
|
||||
|
||||
```ini
|
||||
# Use copying instead of hard links
|
||||
package-import-method=copy
|
||||
```
|
||||
|
||||
### Permission issues
|
||||
|
||||
```bash
|
||||
# Fix store permissions
|
||||
chmod -R u+w ~/.pnpm-store
|
||||
```
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/symlinked-node-modules-structure
|
||||
- https://pnpm.io/cli/store
|
||||
|
||||
@@ -39,12 +39,12 @@ Use `workspace:` protocol to reference local packages:
|
||||
|
||||
### Protocol Variants
|
||||
|
||||
| Protocol | Behavior | Published As |
|
||||
|----------|----------|--------------|
|
||||
| `workspace:*` | Any version | Actual version (e.g., `1.2.3`) |
|
||||
| `workspace:^` | Compatible version | `^1.2.3` |
|
||||
| `workspace:~` | Patch version | `~1.2.3` |
|
||||
| `workspace:^1.0.0` | Semver range | `^1.0.0` |
|
||||
| Protocol | Behavior | Published As |
|
||||
| ------------------ | ------------------ | ------------------------------ |
|
||||
| `workspace:*` | Any version | Actual version (e.g., `1.2.3`) |
|
||||
| `workspace:^` | Compatible version | `^1.2.3` |
|
||||
| `workspace:~` | Patch version | `~1.2.3` |
|
||||
| `workspace:^1.0.0` | Semver range | `^1.0.0` |
|
||||
|
||||
## Filtering Packages
|
||||
|
||||
@@ -87,6 +87,7 @@ pnpm --filter "[HEAD~5]" lint
|
||||
## Workspace Commands
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```bash
|
||||
# Install all workspace packages
|
||||
pnpm install
|
||||
@@ -99,6 +100,7 @@ pnpm --filter @myorg/app add @myorg/utils
|
||||
```
|
||||
|
||||
### Run scripts
|
||||
|
||||
```bash
|
||||
# Run in all packages with that script
|
||||
pnpm -r run build
|
||||
@@ -114,6 +116,7 @@ pnpm -r --stream run dev
|
||||
```
|
||||
|
||||
### Execute commands
|
||||
|
||||
```bash
|
||||
# Run command in all packages
|
||||
pnpm -r exec pwd
|
||||
@@ -164,6 +167,7 @@ When publishing, `workspace:` protocols are converted:
|
||||
```
|
||||
|
||||
Use `--no-git-checks` for publishing from CI:
|
||||
|
||||
```bash
|
||||
pnpm publish -r --no-git-checks
|
||||
```
|
||||
@@ -197,7 +201,7 @@ my-monorepo/
|
||||
└── package.json
|
||||
```
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/workspaces
|
||||
- https://pnpm.io/filtering
|
||||
|
||||
@@ -14,6 +14,7 @@ pnpm add <alias>@npm:<package>@<version>
|
||||
```
|
||||
|
||||
In `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
@@ -38,9 +39,10 @@ Install different versions side by side:
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
||||
```js
|
||||
import lodash3 from 'lodash3'
|
||||
import lodash4 from 'lodash4'
|
||||
import lodash3 from 'lodash3';
|
||||
import lodash4 from 'lodash4';
|
||||
```
|
||||
|
||||
### Replace Package with Fork
|
||||
@@ -130,7 +132,7 @@ Force all transitive dependencies to use an alias:
|
||||
```yaml
|
||||
# pnpm-workspace.yaml
|
||||
overrides:
|
||||
"underscore": "npm:lodash@^4.17.21"
|
||||
'underscore': 'npm:lodash@^4.17.21'
|
||||
```
|
||||
|
||||
This replaces all `underscore` imports (including in dependencies) with lodash.
|
||||
@@ -151,6 +153,7 @@ Aliases work with any valid pnpm specifier:
|
||||
## Best Practices
|
||||
|
||||
1. **Clear naming**: Use descriptive alias names that indicate purpose
|
||||
|
||||
```json
|
||||
"lodash-legacy": "npm:lodash@3"
|
||||
"lodash-modern": "npm:lodash@4"
|
||||
@@ -162,7 +165,7 @@ Aliases work with any valid pnpm specifier:
|
||||
|
||||
4. **Test thoroughly**: Aliased packages may have subtle differences in behavior
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/aliases
|
||||
-->
|
||||
|
||||
@@ -54,14 +54,14 @@ catalogs:
|
||||
react17:
|
||||
react: ^17.0.2
|
||||
react-dom: ^17.0.2
|
||||
|
||||
|
||||
react18:
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
|
||||
|
||||
testing:
|
||||
vitest: ^1.0.0
|
||||
"@testing-library/react": ^14.0.0
|
||||
'@testing-library/react': ^14.0.0
|
||||
```
|
||||
|
||||
Reference named catalogs:
|
||||
@@ -87,12 +87,12 @@ Reference named catalogs:
|
||||
|
||||
## Catalog vs Overrides
|
||||
|
||||
| Feature | Catalogs | Overrides |
|
||||
|---------|----------|-----------|
|
||||
| Purpose | Define versions for direct dependencies | Force versions for any dependency |
|
||||
| Scope | Direct dependencies only | All dependencies (including transitive) |
|
||||
| Usage | `"pkg": "catalog:"` | Applied automatically |
|
||||
| Opt-in | Explicit per package.json | Global to workspace |
|
||||
| Feature | Catalogs | Overrides |
|
||||
| ------- | --------------------------------------- | --------------------------------------- |
|
||||
| Purpose | Define versions for direct dependencies | Force versions for any dependency |
|
||||
| Scope | Direct dependencies only | All dependencies (including transitive) |
|
||||
| Usage | `"pkg": "catalog:"` | Applied automatically |
|
||||
| Opt-in | Explicit per package.json | Global to workspace |
|
||||
|
||||
## Publishing with Catalogs
|
||||
|
||||
@@ -153,7 +153,7 @@ catalog:
|
||||
# "dependencies": { "@myorg/utils": "workspace:^" }
|
||||
```
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/catalogs
|
||||
-->
|
||||
|
||||
@@ -15,20 +15,20 @@ Create `.pnpmfile.cjs` at workspace root:
|
||||
// .pnpmfile.cjs
|
||||
function readPackage(pkg, context) {
|
||||
// Modify package metadata
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
|
||||
function afterAllResolved(lockfile, context) {
|
||||
// Modify lockfile
|
||||
return lockfile
|
||||
return lockfile;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage,
|
||||
afterAllResolved
|
||||
}
|
||||
}
|
||||
afterAllResolved,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## readPackage Hook
|
||||
@@ -42,11 +42,11 @@ function readPackage(pkg, context) {
|
||||
if (pkg.name === 'some-broken-package') {
|
||||
pkg.peerDependencies = {
|
||||
...pkg.peerDependencies,
|
||||
react: '*'
|
||||
}
|
||||
context.log(`Added react peer dep to ${pkg.name}`)
|
||||
react: '*',
|
||||
};
|
||||
context.log(`Added react peer dep to ${pkg.name}`);
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -56,12 +56,12 @@ function readPackage(pkg, context) {
|
||||
function readPackage(pkg, context) {
|
||||
// Fix all lodash versions
|
||||
if (pkg.dependencies?.lodash) {
|
||||
pkg.dependencies.lodash = '^4.17.21'
|
||||
pkg.dependencies.lodash = '^4.17.21';
|
||||
}
|
||||
if (pkg.devDependencies?.lodash) {
|
||||
pkg.devDependencies.lodash = '^4.17.21'
|
||||
pkg.devDependencies.lodash = '^4.17.21';
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -71,9 +71,9 @@ function readPackage(pkg, context) {
|
||||
function readPackage(pkg, context) {
|
||||
// Remove optional dependency that causes issues
|
||||
if (pkg.optionalDependencies?.fsevents) {
|
||||
delete pkg.optionalDependencies.fsevents
|
||||
delete pkg.optionalDependencies.fsevents;
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -83,10 +83,10 @@ function readPackage(pkg, context) {
|
||||
function readPackage(pkg, context) {
|
||||
// Replace deprecated package
|
||||
if (pkg.dependencies?.['old-package']) {
|
||||
pkg.dependencies['new-package'] = pkg.dependencies['old-package']
|
||||
delete pkg.dependencies['old-package']
|
||||
pkg.dependencies['new-package'] = pkg.dependencies['old-package'];
|
||||
delete pkg.dependencies['old-package'];
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -99,11 +99,11 @@ function readPackage(pkg, context) {
|
||||
pkg.exports = {
|
||||
'.': {
|
||||
import: './dist/index.mjs',
|
||||
require: './dist/index.cjs'
|
||||
}
|
||||
}
|
||||
require: './dist/index.cjs',
|
||||
},
|
||||
};
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -114,10 +114,10 @@ Called after the lockfile is generated. Use for post-resolution modifications.
|
||||
```js
|
||||
function afterAllResolved(lockfile, context) {
|
||||
// Log all resolved packages
|
||||
context.log(`Resolved ${Object.keys(lockfile.packages || {}).length} packages`)
|
||||
|
||||
context.log(`Resolved ${Object.keys(lockfile.packages || {}).length} packages`);
|
||||
|
||||
// Modify lockfile if needed
|
||||
return lockfile
|
||||
return lockfile;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -128,9 +128,9 @@ The `context` object provides utilities:
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Log messages
|
||||
context.log('Processing package...')
|
||||
|
||||
return pkg
|
||||
context.log('Processing package...');
|
||||
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -147,14 +147,14 @@ For type hints, use JSDoc:
|
||||
* @returns {import('type-fest').PackageJson}
|
||||
*/
|
||||
function readPackage(pkg, context) {
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage
|
||||
}
|
||||
}
|
||||
readPackage,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
@@ -165,13 +165,13 @@ module.exports = {
|
||||
function readPackage(pkg, context) {
|
||||
switch (pkg.name) {
|
||||
case 'package-a':
|
||||
pkg.dependencies.foo = '^2.0.0'
|
||||
break
|
||||
pkg.dependencies.foo = '^2.0.0';
|
||||
break;
|
||||
case 'package-b':
|
||||
delete pkg.optionalDependencies.bar
|
||||
break
|
||||
delete pkg.optionalDependencies.bar;
|
||||
break;
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -181,9 +181,9 @@ function readPackage(pkg, context) {
|
||||
function readPackage(pkg, context) {
|
||||
// Remove all optional fsevents
|
||||
if (pkg.optionalDependencies) {
|
||||
delete pkg.optionalDependencies.fsevents
|
||||
delete pkg.optionalDependencies.fsevents;
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -192,22 +192,23 @@ function readPackage(pkg, context) {
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
if (process.env.DEBUG_PNPM) {
|
||||
context.log(`${pkg.name}@${pkg.version}`)
|
||||
context.log(` deps: ${Object.keys(pkg.dependencies || {}).join(', ')}`)
|
||||
context.log(`${pkg.name}@${pkg.version}`);
|
||||
context.log(` deps: ${Object.keys(pkg.dependencies || {}).join(', ')}`);
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
## Hooks vs Overrides
|
||||
|
||||
| Feature | Hooks (.pnpmfile.cjs) | Overrides |
|
||||
|---------|----------------------|-----------|
|
||||
| Complexity | Can use JavaScript logic | Declarative only |
|
||||
| Scope | Any package metadata | Version only |
|
||||
| Use case | Complex fixes, conditional logic | Simple version pins |
|
||||
| Feature | Hooks (.pnpmfile.cjs) | Overrides |
|
||||
| ---------- | -------------------------------- | ------------------- |
|
||||
| Complexity | Can use JavaScript logic | Declarative only |
|
||||
| Scope | Any package metadata | Version only |
|
||||
| Use case | Complex fixes, conditional logic | Simple version pins |
|
||||
|
||||
**Prefer overrides** for simple version fixes. **Use hooks** when you need:
|
||||
|
||||
- Conditional logic
|
||||
- Non-version modifications (exports, peer deps)
|
||||
- Logging/debugging
|
||||
@@ -227,7 +228,7 @@ function readPackage(pkg, context) {
|
||||
pnpm install --reporter=append-only
|
||||
```
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/pnpmfile
|
||||
-->
|
||||
|
||||
@@ -20,15 +20,15 @@ packages:
|
||||
overrides:
|
||||
# Override all versions of a package
|
||||
lodash: ^4.17.21
|
||||
|
||||
|
||||
# Override specific version range
|
||||
"foo@^1.0.0": ^1.2.3
|
||||
|
||||
'foo@^1.0.0': ^1.2.3
|
||||
|
||||
# Override nested dependency
|
||||
"express>cookie": ^0.6.0
|
||||
|
||||
'express>cookie': ^0.6.0
|
||||
|
||||
# Override to different package
|
||||
"underscore": "npm:lodash@^4.17.21"
|
||||
'underscore': 'npm:lodash@^4.17.21'
|
||||
```
|
||||
|
||||
### In package.json
|
||||
@@ -48,45 +48,54 @@ overrides:
|
||||
## Override Patterns
|
||||
|
||||
### Override all instances
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
lodash: ^4.17.21
|
||||
```
|
||||
|
||||
Forces all lodash installations to use ^4.17.21.
|
||||
|
||||
### Override specific parent version
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"foo@^1.0.0": ^1.2.3
|
||||
'foo@^1.0.0': ^1.2.3
|
||||
```
|
||||
|
||||
Only override foo when the requested version matches ^1.0.0.
|
||||
|
||||
### Override nested dependency
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"express>cookie": ^0.6.0
|
||||
"[email protected]>bar@^2.0.0>qux": ^1.0.0
|
||||
'express>cookie': ^0.6.0
|
||||
'[email protected]>bar@^2.0.0>qux': ^1.0.0
|
||||
```
|
||||
|
||||
Override cookie only when it's a dependency of express.
|
||||
|
||||
### Replace with different package
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
# Replace underscore with lodash
|
||||
"underscore": "npm:lodash@^4.17.21"
|
||||
|
||||
|
||||
# Use local file
|
||||
"some-pkg": "file:./local-pkg"
|
||||
|
||||
|
||||
# Use git
|
||||
"some-pkg": "github:user/repo#commit"
|
||||
```
|
||||
|
||||
### Remove a dependency
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"unwanted-pkg": "-"
|
||||
'unwanted-pkg': '-'
|
||||
```
|
||||
|
||||
The `-` removes the package entirely.
|
||||
|
||||
## Common Use Cases
|
||||
@@ -98,8 +107,8 @@ Force patched version of vulnerable package:
|
||||
```yaml
|
||||
overrides:
|
||||
# Fix CVE in transitive dependency
|
||||
"minimist": "^1.2.6"
|
||||
"json5": "^2.2.3"
|
||||
'minimist': '^1.2.6'
|
||||
'json5': '^2.2.3'
|
||||
```
|
||||
|
||||
### Deduplicate Dependencies
|
||||
@@ -108,22 +117,22 @@ Force single version when multiple are installed:
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"react": "^18.2.0"
|
||||
"react-dom": "^18.2.0"
|
||||
'react': '^18.2.0'
|
||||
'react-dom': '^18.2.0'
|
||||
```
|
||||
|
||||
### Fix Peer Dependency Issues
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"@types/react": "^18.2.0"
|
||||
'@types/react': '^18.2.0'
|
||||
```
|
||||
|
||||
### Replace Deprecated Package
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"request": "npm:@cypress/request@^3.0.0"
|
||||
'request': 'npm:@cypress/request@^3.0.0'
|
||||
```
|
||||
|
||||
## Hooks Alternative
|
||||
@@ -135,35 +144,35 @@ For more complex scenarios, use `.pnpmfile.cjs`:
|
||||
function readPackage(pkg, context) {
|
||||
// Override dependency version
|
||||
if (pkg.dependencies?.lodash) {
|
||||
pkg.dependencies.lodash = '^4.17.21'
|
||||
pkg.dependencies.lodash = '^4.17.21';
|
||||
}
|
||||
|
||||
|
||||
// Add missing peer dependency
|
||||
if (pkg.name === 'some-package') {
|
||||
pkg.peerDependencies = {
|
||||
...pkg.peerDependencies,
|
||||
react: '*'
|
||||
}
|
||||
react: '*',
|
||||
};
|
||||
}
|
||||
|
||||
return pkg
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage
|
||||
}
|
||||
}
|
||||
readPackage,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Overrides vs Catalogs
|
||||
|
||||
| Feature | Overrides | Catalogs |
|
||||
|---------|-----------|----------|
|
||||
| Affects | All dependencies (including transitive) | Direct dependencies only |
|
||||
| Usage | Automatic | Explicit `catalog:` reference |
|
||||
| Purpose | Force versions, fix issues | Version management |
|
||||
| Granularity | Can target specific parents | Package-wide only |
|
||||
| Feature | Overrides | Catalogs |
|
||||
| ----------- | --------------------------------------- | ----------------------------- |
|
||||
| Affects | All dependencies (including transitive) | Direct dependencies only |
|
||||
| Usage | Automatic | Explicit `catalog:` reference |
|
||||
| Purpose | Force versions, fix issues | Version management |
|
||||
| Granularity | Can target specific parents | Package-wide only |
|
||||
|
||||
## Debugging
|
||||
|
||||
@@ -177,7 +186,7 @@ pnpm why lodash
|
||||
pnpm list lodash --depth=Infinity
|
||||
```
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/package_json#pnpmoverrides
|
||||
- https://pnpm.io/pnpmfile
|
||||
|
||||
@@ -100,11 +100,12 @@ pnpm patch-commit <path>
|
||||
```bash
|
||||
pnpm patch-remove <pkg>@<version>
|
||||
|
||||
# Example
|
||||
# Example
|
||||
pnpm patch-remove express@4.18.2
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
1. Delete the patch file from `patches/`
|
||||
2. Remove entry from `patchedDependencies` in `package.json`
|
||||
3. Run `pnpm install`
|
||||
@@ -159,6 +160,7 @@ All workspace packages using `[email protected]` will have the patch applied.
|
||||
1. **Version specificity**: Patches are tied to exact versions. Update patches when upgrading dependencies.
|
||||
|
||||
2. **Document patches**: Add comments explaining why the patch exists:
|
||||
|
||||
```bash
|
||||
# In patches/README.md
|
||||
## express@4.18.2.patch
|
||||
@@ -180,6 +182,7 @@ ERR_PNPM_PATCH_FAILED Cannot apply patch
|
||||
```
|
||||
|
||||
The package version changed. Recreate the patch:
|
||||
|
||||
```bash
|
||||
pnpm patch-remove express@4.18.2
|
||||
pnpm patch express@4.18.2
|
||||
@@ -190,10 +193,11 @@ pnpm patch-commit <path>
|
||||
### Patch not applied
|
||||
|
||||
Ensure:
|
||||
|
||||
1. Version in `patchedDependencies` matches installed version exactly
|
||||
2. Run `pnpm install` after adding patch configuration
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/cli/patch
|
||||
- https://pnpm.io/cli/patch-commit
|
||||
|
||||
@@ -28,6 +28,7 @@ strict-peer-dependencies=true
|
||||
```
|
||||
|
||||
When strict, pnpm will fail if:
|
||||
|
||||
- Peer dependency is missing
|
||||
- Installed version doesn't match required range
|
||||
|
||||
@@ -57,17 +58,14 @@ Suppress warnings for missing peer dependencies:
|
||||
{
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"@babel/*",
|
||||
"eslint",
|
||||
"webpack"
|
||||
]
|
||||
"ignoreMissing": ["@babel/*", "eslint", "webpack"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use patterns:
|
||||
|
||||
- `"react"` - exact package name
|
||||
- `"@babel/*"` - all packages in scope
|
||||
- `"*"` - all packages (not recommended)
|
||||
@@ -115,17 +113,17 @@ function readPackage(pkg, context) {
|
||||
if (pkg.name === 'problematic-package') {
|
||||
pkg.peerDependencies = {
|
||||
...pkg.peerDependencies,
|
||||
react: '*'
|
||||
}
|
||||
react: '*',
|
||||
};
|
||||
}
|
||||
return pkg
|
||||
return pkg;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage
|
||||
}
|
||||
}
|
||||
readPackage,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Peer Dependencies in Workspaces
|
||||
@@ -141,7 +139,7 @@ Workspace packages can satisfy peer dependencies:
|
||||
}
|
||||
}
|
||||
|
||||
// packages/components/package.json
|
||||
// packages/components/package.json
|
||||
{
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.0 || ^18.0.0"
|
||||
@@ -187,10 +185,7 @@ catalog:
|
||||
{
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"eslint",
|
||||
"@typescript-eslint/parser"
|
||||
]
|
||||
"ignoreMissing": ["eslint", "@typescript-eslint/parser"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,6 +228,7 @@ pnpm list --depth=Infinity
|
||||
3. **Document suppressed warnings** explaining why they're safe
|
||||
|
||||
4. **Keep peer deps ranges wide** in libraries:
|
||||
|
||||
```json
|
||||
{
|
||||
"peerDependencies": {
|
||||
@@ -243,7 +239,7 @@ pnpm list --depth=Infinity
|
||||
|
||||
5. **Test with different peer versions** if you support multiple majors
|
||||
|
||||
<!--
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/package_json#pnpmpeerdependencyrules
|
||||
- https://pnpm.io/npmrc#auto-install-peers
|
||||
|
||||
Reference in New Issue
Block a user