feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
5
skills/pnpm/GENERATION.md
Normal file
5
skills/pnpm/GENERATION.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Generation Info
|
||||
|
||||
- **Source:** `sources/pnpm`
|
||||
- **Git SHA:** `a1d6d5aef9d5f369fa2f0d8a54f1edbaff8b23b3`
|
||||
- **Generated:** 2026-01-28
|
||||
42
skills/pnpm/SKILL.md
Normal file
42
skills/pnpm/SKILL.md
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
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"
|
||||
source: Generated from https://github.com/pnpm/pnpm, scripts located at https://github.com/antfu/skills
|
||||
---
|
||||
|
||||
pnpm is a fast, disk space efficient package manager. It uses a content-addressable store to deduplicate packages across all projects on a machine, saving significant disk space. pnpm enforces strict dependency resolution by default, preventing phantom dependencies. Configuration should preferably be placed in `pnpm-workspace.yaml` for pnpm-specific settings.
|
||||
|
||||
**Important:** When working with pnpm projects, agents should check for `pnpm-workspace.yaml` and `.npmrc` files to understand workspace structure and configuration. Always use `--frozen-lockfile` in CI environments.
|
||||
|
||||
> The skill is based on pnpm 10.x, generated at 2026-01-28.
|
||||
|
||||
## 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) |
|
||||
|
||||
## 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) |
|
||||
|
||||
## 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) |
|
||||
285
skills/pnpm/references/best-practices-ci.md
Normal file
285
skills/pnpm/references/best-practices-ci.md
Normal file
@@ -0,0 +1,285 @@
|
||||
---
|
||||
name: pnpm-ci-cd-setup
|
||||
description: Optimizing pnpm for continuous integration and deployment workflows
|
||||
---
|
||||
|
||||
# pnpm CI/CD Setup
|
||||
|
||||
Best practices for using pnpm in CI/CD environments for fast, reliable builds.
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
### Basic Setup
|
||||
|
||||
```yaml
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
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
|
||||
```
|
||||
|
||||
### With Store Caching
|
||||
|
||||
For larger projects, cache the pnpm store:
|
||||
|
||||
```yaml
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
### Matrix Testing
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
node: [18, 20, 22]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
cache: 'pnpm'
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm test
|
||||
```
|
||||
|
||||
## GitLab CI
|
||||
|
||||
```yaml
|
||||
image: node:20
|
||||
|
||||
stages:
|
||||
- install
|
||||
- test
|
||||
- build
|
||||
|
||||
variables:
|
||||
PNPM_HOME: /root/.local/share/pnpm
|
||||
PATH: $PNPM_HOME:$PATH
|
||||
|
||||
before_script:
|
||||
- corepack enable
|
||||
- corepack prepare pnpm@latest --activate
|
||||
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- .pnpm-store
|
||||
|
||||
install:
|
||||
stage: install
|
||||
script:
|
||||
- pnpm config set store-dir .pnpm-store
|
||||
- pnpm install --frozen-lockfile
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- pnpm test
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- pnpm build
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
### Multi-Stage Build
|
||||
|
||||
```dockerfile
|
||||
# Build stage
|
||||
FROM node:20-slim AS builder
|
||||
|
||||
# Enable corepack for pnpm
|
||||
RUN corepack enable
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files first for layer caching
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||
COPY packages/*/package.json ./packages/
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Copy source and build
|
||||
COPY . .
|
||||
RUN pnpm build
|
||||
|
||||
# Production stage
|
||||
FROM node:20-slim AS runner
|
||||
|
||||
RUN corepack enable
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/package.json ./
|
||||
COPY --from=builder /app/pnpm-lock.yaml ./
|
||||
|
||||
# Production install
|
||||
RUN pnpm install --frozen-lockfile --prod
|
||||
|
||||
CMD ["node", "dist/index.js"]
|
||||
```
|
||||
|
||||
### Optimized for Monorepos
|
||||
|
||||
```dockerfile
|
||||
FROM node:20-slim AS builder
|
||||
RUN corepack enable
|
||||
WORKDIR /app
|
||||
|
||||
# Copy workspace config
|
||||
COPY pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||
|
||||
# Copy all package.json files maintaining structure
|
||||
COPY packages/core/package.json ./packages/core/
|
||||
COPY packages/api/package.json ./packages/api/
|
||||
|
||||
# Install all dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Build specific package
|
||||
RUN pnpm --filter @myorg/api build
|
||||
```
|
||||
|
||||
## Key CI Flags
|
||||
|
||||
### --frozen-lockfile
|
||||
|
||||
**Always use in CI.** Fails if `pnpm-lock.yaml` needs updates:
|
||||
|
||||
```bash
|
||||
pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
### --prefer-offline
|
||||
|
||||
Use cached packages when available:
|
||||
|
||||
```bash
|
||||
pnpm install --frozen-lockfile --prefer-offline
|
||||
```
|
||||
|
||||
### --ignore-scripts
|
||||
|
||||
Skip lifecycle scripts for faster installs (use cautiously):
|
||||
|
||||
```bash
|
||||
pnpm install --frozen-lockfile --ignore-scripts
|
||||
```
|
||||
|
||||
## Corepack Integration
|
||||
|
||||
Use Corepack to manage pnpm version:
|
||||
|
||||
```json
|
||||
// package.json
|
||||
{
|
||||
"packageManager": "pnpm@9.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- run: corepack enable
|
||||
- run: pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
## Monorepo CI Strategies
|
||||
|
||||
### Build Changed Packages Only
|
||||
|
||||
```yaml
|
||||
- name: Build changed packages
|
||||
run: |
|
||||
pnpm --filter "...[origin/main]" build
|
||||
```
|
||||
|
||||
### Parallel Jobs per Package
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
detect-changes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
packages: ${{ steps.changes.outputs.packages }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: changes
|
||||
run: |
|
||||
echo "packages=$(pnpm --filter '...[origin/main]' list --json | jq -c '[.[].name]')" >> $GITHUB_OUTPUT
|
||||
|
||||
test:
|
||||
needs: detect-changes
|
||||
if: needs.detect-changes.outputs.packages != '[]'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
package: ${{ fromJson(needs.detect-changes.outputs.packages) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm --filter ${{ matrix.package }} test
|
||||
```
|
||||
|
||||
## Best Practices Summary
|
||||
|
||||
1. **Always use `--frozen-lockfile`** in CI
|
||||
2. **Cache the pnpm store** for faster installs
|
||||
3. **Use Corepack** for consistent pnpm versions
|
||||
4. **Specify `packageManager`** in package.json
|
||||
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
|
||||
-->
|
||||
291
skills/pnpm/references/best-practices-migration.md
Normal file
291
skills/pnpm/references/best-practices-migration.md
Normal file
@@ -0,0 +1,291 @@
|
||||
---
|
||||
name: migration-to-pnpm
|
||||
description: Migrating from npm or Yarn to pnpm with minimal friction
|
||||
---
|
||||
|
||||
# Migration to pnpm
|
||||
|
||||
Guide for migrating existing projects from npm or Yarn to pnpm.
|
||||
|
||||
## Quick Migration
|
||||
|
||||
### From npm
|
||||
|
||||
```bash
|
||||
# Remove npm lockfile and node_modules
|
||||
rm -rf node_modules package-lock.json
|
||||
|
||||
# Install with pnpm
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### From Yarn
|
||||
|
||||
```bash
|
||||
# Remove yarn lockfile and node_modules
|
||||
rm -rf node_modules yarn.lock
|
||||
|
||||
# Install with pnpm
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Import Existing Lockfile
|
||||
|
||||
pnpm can import existing lockfiles:
|
||||
|
||||
```bash
|
||||
# Import from npm or yarn lockfile
|
||||
pnpm import
|
||||
|
||||
# This creates pnpm-lock.yaml from:
|
||||
# - package-lock.json (npm)
|
||||
# - yarn.lock (yarn)
|
||||
# - npm-shrinkwrap.json (npm)
|
||||
```
|
||||
|
||||
## Handling Common Issues
|
||||
|
||||
### Phantom Dependencies
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
**Solution:** Add missing dependencies explicitly:
|
||||
```bash
|
||||
pnpm add lodash
|
||||
```
|
||||
|
||||
### Missing Peer Dependencies
|
||||
|
||||
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": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": ["react"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Symlink Issues
|
||||
|
||||
Some tools don't work with symlinks. Use hoisted mode:
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
node-linker=hoisted
|
||||
```
|
||||
|
||||
Or hoist specific packages:
|
||||
|
||||
```ini
|
||||
public-hoist-pattern[]=*eslint*
|
||||
public-hoist-pattern[]=*babel*
|
||||
```
|
||||
|
||||
### Native Module Rebuilds
|
||||
|
||||
If native modules fail, try:
|
||||
|
||||
```bash
|
||||
# Rebuild all native modules
|
||||
pnpm rebuild
|
||||
|
||||
# Or reinstall
|
||||
rm -rf node_modules
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## Monorepo Migration
|
||||
|
||||
### From npm Workspaces
|
||||
|
||||
1. Create `pnpm-workspace.yaml`:
|
||||
```yaml
|
||||
packages:
|
||||
- 'packages/*'
|
||||
```
|
||||
|
||||
2. Update internal dependencies to use workspace protocol:
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@myorg/utils": "workspace:^"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Install:
|
||||
```bash
|
||||
rm -rf node_modules packages/*/node_modules package-lock.json
|
||||
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)
|
||||
}
|
||||
```
|
||||
|
||||
4. Convert workspace references:
|
||||
```json
|
||||
// From Yarn
|
||||
"@myorg/utils": "*"
|
||||
|
||||
// To pnpm
|
||||
"@myorg/utils": "workspace:*"
|
||||
```
|
||||
|
||||
### From Lerna
|
||||
|
||||
pnpm can replace Lerna for most use cases:
|
||||
|
||||
```bash
|
||||
# Lerna: run script in all packages
|
||||
lerna run build
|
||||
|
||||
# pnpm equivalent
|
||||
pnpm -r run build
|
||||
|
||||
# Lerna: run in specific package
|
||||
lerna run build --scope=@myorg/app
|
||||
|
||||
# pnpm equivalent
|
||||
pnpm --filter @myorg/app run build
|
||||
|
||||
# Lerna: publish
|
||||
lerna publish
|
||||
|
||||
# pnpm: use changesets instead
|
||||
pnpm add -Dw @changesets/cli
|
||||
pnpm changeset
|
||||
pnpm changeset version
|
||||
pnpm publish -r
|
||||
```
|
||||
|
||||
## Configuration Migration
|
||||
|
||||
### .npmrc Settings
|
||||
|
||||
Most npm/Yarn settings work in pnpm's `.npmrc`:
|
||||
|
||||
```ini
|
||||
# Registry settings (same as npm)
|
||||
registry=https://registry.npmjs.org/
|
||||
@myorg:registry=https://npm.myorg.com/
|
||||
|
||||
# Auth tokens (same as npm)
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
|
||||
# pnpm-specific additions
|
||||
auto-install-peers=true
|
||||
strict-peer-dependencies=false
|
||||
```
|
||||
|
||||
### Scripts Migration
|
||||
|
||||
Most scripts work unchanged. Update pnpm-specific patterns:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
// npm: recursive scripts
|
||||
"build:all": "npm run build --workspaces",
|
||||
// pnpm: use -r flag
|
||||
"build:all": "pnpm -r run build",
|
||||
|
||||
// npm: run in specific workspace
|
||||
"dev:app": "npm run dev -w packages/app",
|
||||
// pnpm: use --filter
|
||||
"dev:app": "pnpm --filter @myorg/app run dev"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## CI/CD Migration
|
||||
|
||||
Update CI configuration:
|
||||
|
||||
```yaml
|
||||
# Before (npm)
|
||||
- run: npm ci
|
||||
|
||||
# After (pnpm)
|
||||
- uses: pnpm/action-setup@v4
|
||||
- run: pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
Add to `package.json` for Corepack:
|
||||
```json
|
||||
{
|
||||
"packageManager": "pnpm@9.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
## Gradual Migration
|
||||
|
||||
For large projects, migrate gradually:
|
||||
|
||||
1. **Start with CI**: Use pnpm in CI, keep npm/yarn locally
|
||||
2. **Add pnpm-lock.yaml**: Run `pnpm import` to create lockfile
|
||||
3. **Test thoroughly**: Ensure builds work with pnpm
|
||||
4. **Update documentation**: Update README, CONTRIBUTING
|
||||
5. **Remove old files**: Delete old lockfiles after team adoption
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If migration causes issues:
|
||||
|
||||
```bash
|
||||
# Remove pnpm files
|
||||
rm -rf node_modules pnpm-lock.yaml pnpm-workspace.yaml
|
||||
|
||||
# Restore npm
|
||||
npm install
|
||||
|
||||
# Or restore Yarn
|
||||
yarn install
|
||||
```
|
||||
|
||||
Keep old lockfile in git history for easy rollback.
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/installation
|
||||
- https://pnpm.io/cli/import
|
||||
- https://pnpm.io/limitations
|
||||
-->
|
||||
284
skills/pnpm/references/best-practices-performance.md
Normal file
284
skills/pnpm/references/best-practices-performance.md
Normal file
@@ -0,0 +1,284 @@
|
||||
---
|
||||
name: pnpm-performance-optimization
|
||||
description: Tips and tricks for faster installs and better performance
|
||||
---
|
||||
|
||||
# pnpm Performance Optimization
|
||||
|
||||
pnpm is fast by default, but these optimizations can make it even faster.
|
||||
|
||||
## Install Optimizations
|
||||
|
||||
### Use Frozen Lockfile
|
||||
|
||||
Skip resolution when lockfile exists:
|
||||
|
||||
```bash
|
||||
pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
This is faster because pnpm skips the resolution phase entirely.
|
||||
|
||||
### Prefer Offline Mode
|
||||
|
||||
Use cached packages when available:
|
||||
|
||||
```bash
|
||||
pnpm install --prefer-offline
|
||||
```
|
||||
|
||||
Or configure globally:
|
||||
```ini
|
||||
# .npmrc
|
||||
prefer-offline=true
|
||||
```
|
||||
|
||||
### Skip Optional Dependencies
|
||||
|
||||
If you don't need optional deps:
|
||||
|
||||
```bash
|
||||
pnpm install --no-optional
|
||||
```
|
||||
|
||||
### Skip Scripts
|
||||
|
||||
For CI or when scripts aren't needed:
|
||||
|
||||
```bash
|
||||
pnpm install --ignore-scripts
|
||||
```
|
||||
|
||||
**Caution:** Some packages require postinstall scripts to work correctly.
|
||||
|
||||
### Only Build Specific Dependencies
|
||||
|
||||
Only run build scripts for specific packages:
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
onlyBuiltDependencies[]=esbuild
|
||||
onlyBuiltDependencies[]=sharp
|
||||
onlyBuiltDependencies[]=@swc/core
|
||||
```
|
||||
|
||||
Or skip builds entirely for deps that don't need them:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"neverBuiltDependencies": ["fsevents", "cpu-features"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Store Optimizations
|
||||
|
||||
### Side Effects Cache
|
||||
|
||||
Cache native module build results:
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
side-effects-cache=true
|
||||
```
|
||||
|
||||
This caches the results of postinstall scripts, speeding up subsequent installs.
|
||||
|
||||
### Shared Store
|
||||
|
||||
Use a single store for all projects (default behavior):
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
store-dir=~/.pnpm-store
|
||||
```
|
||||
|
||||
Benefits:
|
||||
- Packages downloaded once for all projects
|
||||
- Hard links save disk space
|
||||
- Faster installs from cache
|
||||
|
||||
### Store Maintenance
|
||||
|
||||
Periodically clean unused packages:
|
||||
|
||||
```bash
|
||||
# Remove unreferenced packages
|
||||
pnpm store prune
|
||||
|
||||
# Check store integrity
|
||||
pnpm store status
|
||||
```
|
||||
|
||||
## Workspace Optimizations
|
||||
|
||||
### Parallel Execution
|
||||
|
||||
Run workspace scripts in parallel:
|
||||
|
||||
```bash
|
||||
pnpm -r --parallel run build
|
||||
```
|
||||
|
||||
Control concurrency:
|
||||
```ini
|
||||
# .npmrc
|
||||
workspace-concurrency=8
|
||||
```
|
||||
|
||||
### Stream Output
|
||||
|
||||
See output in real-time:
|
||||
|
||||
```bash
|
||||
pnpm -r --stream run build
|
||||
```
|
||||
|
||||
### Filter to Changed Packages
|
||||
|
||||
Only build what changed:
|
||||
|
||||
```bash
|
||||
# Build packages changed since main branch
|
||||
pnpm --filter "...[origin/main]" run build
|
||||
```
|
||||
|
||||
### Topological Order
|
||||
|
||||
Build dependencies before dependents:
|
||||
|
||||
```bash
|
||||
pnpm -r run build
|
||||
# Automatically runs in topological order
|
||||
```
|
||||
|
||||
For explicit sequential builds:
|
||||
```bash
|
||||
pnpm -r --workspace-concurrency=1 run build
|
||||
```
|
||||
|
||||
## Network Optimizations
|
||||
|
||||
### Configure Registry
|
||||
|
||||
Use closest/fastest registry:
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
registry=https://registry.npmmirror.com/
|
||||
```
|
||||
|
||||
### HTTP Settings
|
||||
|
||||
Tune network settings:
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
fetch-retries=3
|
||||
fetch-retry-mintimeout=10000
|
||||
fetch-retry-maxtimeout=60000
|
||||
network-concurrency=16
|
||||
```
|
||||
|
||||
### Proxy Configuration
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
proxy=http://proxy.company.com:8080
|
||||
https-proxy=http://proxy.company.com:8080
|
||||
```
|
||||
|
||||
## Lockfile Optimization
|
||||
|
||||
### Single Lockfile (Monorepos)
|
||||
|
||||
Use shared lockfile for all packages (default):
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
shared-workspace-lockfile=true
|
||||
```
|
||||
|
||||
Benefits:
|
||||
- Single source of truth
|
||||
- Faster resolution
|
||||
- Consistent versions across workspace
|
||||
|
||||
### Lockfile-only Mode
|
||||
|
||||
Only update lockfile without installing:
|
||||
|
||||
```bash
|
||||
pnpm install --lockfile-only
|
||||
```
|
||||
|
||||
## Benchmarking
|
||||
|
||||
### Compare Install Times
|
||||
|
||||
```bash
|
||||
# Clean install
|
||||
rm -rf node_modules pnpm-lock.yaml
|
||||
time pnpm install
|
||||
|
||||
# Cached install (with lockfile)
|
||||
rm -rf node_modules
|
||||
time pnpm install --frozen-lockfile
|
||||
|
||||
# With store cache
|
||||
time pnpm install --frozen-lockfile --prefer-offline
|
||||
```
|
||||
|
||||
### Profile Resolution
|
||||
|
||||
Debug slow installs:
|
||||
|
||||
```bash
|
||||
# Verbose logging
|
||||
pnpm install --reporter=append-only
|
||||
|
||||
# Debug mode
|
||||
DEBUG=pnpm:* pnpm install
|
||||
```
|
||||
|
||||
## Configuration Summary
|
||||
|
||||
Optimized `.npmrc` for performance:
|
||||
|
||||
```ini
|
||||
# Install behavior
|
||||
prefer-offline=true
|
||||
auto-install-peers=true
|
||||
|
||||
# Build optimization
|
||||
side-effects-cache=true
|
||||
# Only build what's necessary
|
||||
onlyBuiltDependencies[]=esbuild
|
||||
onlyBuiltDependencies[]=@swc/core
|
||||
|
||||
# Network
|
||||
fetch-retries=3
|
||||
network-concurrency=16
|
||||
|
||||
# Workspace
|
||||
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` |
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/npmrc
|
||||
- https://pnpm.io/cli/install
|
||||
- https://pnpm.io/filtering
|
||||
-->
|
||||
229
skills/pnpm/references/core-cli.md
Normal file
229
skills/pnpm/references/core-cli.md
Normal file
@@ -0,0 +1,229 @@
|
||||
---
|
||||
name: pnpm-cli-commands
|
||||
description: Essential pnpm commands for package management, running scripts, and workspace operations
|
||||
---
|
||||
|
||||
# pnpm CLI Commands
|
||||
|
||||
pnpm provides a comprehensive CLI for package management with commands similar to npm/yarn but with unique features.
|
||||
|
||||
## Installation Commands
|
||||
|
||||
### Install all dependencies
|
||||
```bash
|
||||
pnpm install
|
||||
# or
|
||||
pnpm i
|
||||
```
|
||||
|
||||
### Add a dependency
|
||||
```bash
|
||||
# Production dependency
|
||||
pnpm add <pkg>
|
||||
|
||||
# Dev dependency
|
||||
pnpm add -D <pkg>
|
||||
pnpm add --save-dev <pkg>
|
||||
|
||||
# Optional dependency
|
||||
pnpm add -O <pkg>
|
||||
|
||||
# Global package
|
||||
pnpm add -g <pkg>
|
||||
|
||||
# Specific version
|
||||
pnpm add <pkg>@<version>
|
||||
pnpm add <pkg>@next
|
||||
pnpm add <pkg>@^1.0.0
|
||||
```
|
||||
|
||||
### Remove a dependency
|
||||
```bash
|
||||
pnpm remove <pkg>
|
||||
pnpm rm <pkg>
|
||||
pnpm uninstall <pkg>
|
||||
pnpm un <pkg>
|
||||
```
|
||||
|
||||
### Update dependencies
|
||||
```bash
|
||||
# Update all
|
||||
pnpm update
|
||||
pnpm up
|
||||
|
||||
# Update specific package
|
||||
pnpm update <pkg>
|
||||
|
||||
# Update to latest (ignore semver)
|
||||
pnpm update --latest
|
||||
pnpm up -L
|
||||
|
||||
# Interactive update
|
||||
pnpm update --interactive
|
||||
pnpm up -i
|
||||
```
|
||||
|
||||
## Script Commands
|
||||
|
||||
### Run scripts
|
||||
```bash
|
||||
pnpm run <script>
|
||||
# or shorthand
|
||||
pnpm <script>
|
||||
|
||||
# Pass arguments to script
|
||||
pnpm run build -- --watch
|
||||
|
||||
# Run script if exists (no error if missing)
|
||||
pnpm run --if-present build
|
||||
```
|
||||
|
||||
### Execute binaries
|
||||
```bash
|
||||
# Run local binary
|
||||
pnpm exec <command>
|
||||
|
||||
# Example
|
||||
pnpm exec eslint .
|
||||
```
|
||||
|
||||
### dlx - Run without installing
|
||||
```bash
|
||||
# Like npx but for pnpm
|
||||
pnpm dlx <pkg>
|
||||
|
||||
# Examples
|
||||
pnpm dlx create-vite my-app
|
||||
pnpm dlx degit user/repo my-project
|
||||
```
|
||||
|
||||
## Workspace Commands
|
||||
|
||||
### Run in all packages
|
||||
```bash
|
||||
# Run script in all workspace packages
|
||||
pnpm -r run <script>
|
||||
pnpm --recursive run <script>
|
||||
|
||||
# Run in specific packages
|
||||
pnpm --filter <pattern> run <script>
|
||||
|
||||
# Examples
|
||||
pnpm --filter "./packages/**" run build
|
||||
pnpm --filter "!./packages/internal/**" run test
|
||||
pnpm --filter "@myorg/*" run lint
|
||||
```
|
||||
|
||||
### Filter patterns
|
||||
```bash
|
||||
# By package name
|
||||
pnpm --filter <pkg-name> <command>
|
||||
pnpm --filter "@scope/pkg" build
|
||||
|
||||
# By directory
|
||||
pnpm --filter "./packages/core" test
|
||||
|
||||
# Dependencies of a package
|
||||
pnpm --filter "...@scope/app" build
|
||||
|
||||
# Dependents of a package
|
||||
pnpm --filter "@scope/core..." test
|
||||
|
||||
# Changed packages since commit/branch
|
||||
pnpm --filter "...[origin/main]" build
|
||||
```
|
||||
|
||||
## Other Useful Commands
|
||||
|
||||
### Link packages
|
||||
```bash
|
||||
# Link global package
|
||||
pnpm link --global
|
||||
pnpm link -g
|
||||
|
||||
# Use linked package
|
||||
pnpm link --global <pkg>
|
||||
```
|
||||
|
||||
### Patch packages
|
||||
```bash
|
||||
# Create patch for a package
|
||||
pnpm patch <pkg>@<version>
|
||||
|
||||
# After editing, commit the patch
|
||||
pnpm patch-commit <path>
|
||||
|
||||
# Remove a patch
|
||||
pnpm patch-remove <pkg>
|
||||
```
|
||||
|
||||
### Store management
|
||||
```bash
|
||||
# Show store path
|
||||
pnpm store path
|
||||
|
||||
# Remove unreferenced packages
|
||||
pnpm store prune
|
||||
|
||||
# Check store integrity
|
||||
pnpm store status
|
||||
```
|
||||
|
||||
### Other commands
|
||||
```bash
|
||||
# Clean install (like npm ci)
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# List installed packages
|
||||
pnpm list
|
||||
pnpm ls
|
||||
|
||||
# Why is package installed?
|
||||
pnpm why <pkg>
|
||||
|
||||
# Outdated packages
|
||||
pnpm outdated
|
||||
|
||||
# Audit for vulnerabilities
|
||||
pnpm audit
|
||||
|
||||
# Rebuild native modules
|
||||
pnpm rebuild
|
||||
|
||||
# Import from npm/yarn lockfile
|
||||
pnpm import
|
||||
|
||||
# Create tarball
|
||||
pnpm pack
|
||||
|
||||
# Publish package
|
||||
pnpm publish
|
||||
```
|
||||
|
||||
## Useful Flags
|
||||
|
||||
```bash
|
||||
# Ignore scripts
|
||||
pnpm install --ignore-scripts
|
||||
|
||||
# Prefer offline (use cache)
|
||||
pnpm install --prefer-offline
|
||||
|
||||
# Strict peer dependencies
|
||||
pnpm install --strict-peer-dependencies
|
||||
|
||||
# Production only
|
||||
pnpm install --prod
|
||||
pnpm install -P
|
||||
|
||||
# No optional dependencies
|
||||
pnpm install --no-optional
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/cli/install
|
||||
- https://pnpm.io/cli/add
|
||||
- https://pnpm.io/cli/run
|
||||
- https://pnpm.io/filtering
|
||||
-->
|
||||
188
skills/pnpm/references/core-config.md
Normal file
188
skills/pnpm/references/core-config.md
Normal file
@@ -0,0 +1,188 @@
|
||||
---
|
||||
name: pnpm-configuration
|
||||
description: Configuration options via pnpm-workspace.yaml and .npmrc settings
|
||||
---
|
||||
|
||||
# pnpm Configuration
|
||||
|
||||
pnpm uses two main configuration files: `pnpm-workspace.yaml` for workspace and pnpm-specific settings, and `.npmrc` for npm-compatible and pnpm-specific settings.
|
||||
|
||||
## pnpm-workspace.yaml
|
||||
|
||||
The recommended location for pnpm-specific configurations. Place at project root.
|
||||
|
||||
```yaml
|
||||
# Define workspace packages
|
||||
packages:
|
||||
- 'packages/*'
|
||||
- 'apps/*'
|
||||
- '!**/test/**' # Exclude pattern
|
||||
|
||||
# Catalog for shared dependency versions
|
||||
catalog:
|
||||
react: ^18.2.0
|
||||
typescript: ~5.3.0
|
||||
|
||||
# Named catalogs for different dependency groups
|
||||
catalogs:
|
||||
react17:
|
||||
react: ^17.0.2
|
||||
react-dom: ^17.0.2
|
||||
react18:
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
|
||||
# Override resolutions (preferred location)
|
||||
overrides:
|
||||
lodash: ^4.17.21
|
||||
'foo@^1.0.0>bar': ^2.0.0
|
||||
|
||||
# pnpm settings (alternative to .npmrc)
|
||||
settings:
|
||||
auto-install-peers: true
|
||||
strict-peer-dependencies: false
|
||||
link-workspace-packages: true
|
||||
prefer-workspace-packages: true
|
||||
shared-workspace-lockfile: true
|
||||
```
|
||||
|
||||
## .npmrc Settings
|
||||
|
||||
pnpm reads settings from `.npmrc` files. Create at project root or user home.
|
||||
|
||||
### Common pnpm Settings
|
||||
|
||||
```ini
|
||||
# Automatically install peer dependencies
|
||||
auto-install-peers=true
|
||||
|
||||
# Fail on peer dependency issues
|
||||
strict-peer-dependencies=false
|
||||
|
||||
# Hoist patterns for dependencies
|
||||
public-hoist-pattern[]=*types*
|
||||
public-hoist-pattern[]=*eslint*
|
||||
shamefully-hoist=false
|
||||
|
||||
# Store location
|
||||
store-dir=~/.pnpm-store
|
||||
|
||||
# Virtual store location
|
||||
virtual-store-dir=node_modules/.pnpm
|
||||
|
||||
# Lockfile settings
|
||||
lockfile=true
|
||||
prefer-frozen-lockfile=true
|
||||
|
||||
# Side effects cache (speeds up rebuilds)
|
||||
side-effects-cache=true
|
||||
|
||||
# Registry settings
|
||||
registry=https://registry.npmjs.org/
|
||||
@myorg:registry=https://npm.myorg.com/
|
||||
```
|
||||
|
||||
### Workspace Settings
|
||||
|
||||
```ini
|
||||
# Link workspace packages
|
||||
link-workspace-packages=true
|
||||
|
||||
# Prefer workspace packages over registry
|
||||
prefer-workspace-packages=true
|
||||
|
||||
# Single lockfile for all packages
|
||||
shared-workspace-lockfile=true
|
||||
|
||||
# Save prefix for workspace dependencies
|
||||
save-workspace-protocol=rolling
|
||||
```
|
||||
|
||||
### Node.js Settings
|
||||
|
||||
```ini
|
||||
# Use specific Node.js version
|
||||
use-node-version=20.10.0
|
||||
|
||||
# Node.js version file
|
||||
node-version-file=.nvmrc
|
||||
|
||||
# Manage Node.js versions
|
||||
manage-package-manager-versions=true
|
||||
```
|
||||
|
||||
### Security Settings
|
||||
|
||||
```ini
|
||||
# Ignore specific scripts
|
||||
ignore-scripts=false
|
||||
|
||||
# Allow specific build scripts
|
||||
onlyBuiltDependencies[]=esbuild
|
||||
onlyBuiltDependencies[]=sharp
|
||||
|
||||
# Package extensions for missing peer deps
|
||||
package-extensions[foo@1].peerDependencies.bar=*
|
||||
```
|
||||
|
||||
## Configuration Hierarchy
|
||||
|
||||
Settings are read in order (later overrides earlier):
|
||||
|
||||
1. `/etc/npmrc` - Global config
|
||||
2. `~/.npmrc` - User config
|
||||
3. `<project>/.npmrc` - Project config
|
||||
4. Environment variables: `npm_config_<key>=<value>`
|
||||
5. `pnpm-workspace.yaml` settings field
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
# Set config via env
|
||||
npm_config_registry=https://registry.npmjs.org/
|
||||
|
||||
# pnpm-specific env vars
|
||||
PNPM_HOME=~/.local/share/pnpm
|
||||
```
|
||||
|
||||
## Package.json Fields
|
||||
|
||||
pnpm reads specific fields from `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": ["@babel/*"],
|
||||
"allowedVersions": {
|
||||
"react": "17 || 18"
|
||||
}
|
||||
},
|
||||
"neverBuiltDependencies": ["fsevents"],
|
||||
"onlyBuiltDependencies": ["esbuild"],
|
||||
"allowedDeprecatedVersions": {
|
||||
"request": "*"
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"express@4.18.2": "patches/express@4.18.2.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Key Differences from npm/yarn
|
||||
|
||||
1. **Strict by default**: No phantom dependencies
|
||||
2. **Workspace protocol**: `workspace:*` for local packages
|
||||
3. **Catalogs**: Centralized version management
|
||||
4. **Content-addressable store**: Shared across projects
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/pnpm-workspace_yaml
|
||||
- https://pnpm.io/npmrc
|
||||
- https://pnpm.io/package_json
|
||||
-->
|
||||
179
skills/pnpm/references/core-store.md
Normal file
179
skills/pnpm/references/core-store.md
Normal file
@@ -0,0 +1,179 @@
|
||||
---
|
||||
name: pnpm-store
|
||||
description: Content-addressable storage system that makes pnpm fast and disk-efficient
|
||||
---
|
||||
|
||||
# pnpm Store
|
||||
|
||||
pnpm uses a content-addressable store to save disk space and speed up installations. All packages are stored once globally and hard-linked to project `node_modules`.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Global Store**: Packages are downloaded once to a central store
|
||||
2. **Hard Links**: Projects link to store instead of copying files
|
||||
3. **Content-Addressable**: Files are stored by content hash, deduplicating identical files
|
||||
|
||||
### Storage Layout
|
||||
|
||||
```
|
||||
~/.pnpm-store/ # Global store (default location)
|
||||
└── v3/
|
||||
└── files/
|
||||
└── <hash>/ # Files stored by content hash
|
||||
|
||||
project/
|
||||
└── node_modules/
|
||||
├── .pnpm/ # Virtual store (hard links to global store)
|
||||
│ ├── lodash@4.17.21/
|
||||
│ │ └── node_modules/
|
||||
│ │ └── lodash/
|
||||
│ └── express@4.18.2/
|
||||
│ └── node_modules/
|
||||
│ ├── express/
|
||||
│ └── <deps>/ # Flat structure for dependencies
|
||||
├── lodash -> .pnpm/lodash@4.17.21/node_modules/lodash
|
||||
└── express -> .pnpm/express@4.18.2/node_modules/express
|
||||
```
|
||||
|
||||
## Store Commands
|
||||
|
||||
```bash
|
||||
# Show store location
|
||||
pnpm store path
|
||||
|
||||
# Remove unreferenced packages
|
||||
pnpm store prune
|
||||
|
||||
# Check store integrity
|
||||
pnpm store status
|
||||
|
||||
# Add package to store without installing
|
||||
pnpm store add <pkg>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Store Location
|
||||
|
||||
```ini
|
||||
# .npmrc
|
||||
store-dir=~/.pnpm-store
|
||||
|
||||
# Or use environment variable
|
||||
PNPM_HOME=~/.local/share/pnpm
|
||||
```
|
||||
|
||||
### Virtual Store
|
||||
|
||||
The virtual store (`.pnpm` in `node_modules`) contains symlinks to the global store:
|
||||
|
||||
```ini
|
||||
# Customize virtual store location
|
||||
virtual-store-dir=node_modules/.pnpm
|
||||
|
||||
# Alternative flat layout
|
||||
node-linker=hoisted
|
||||
```
|
||||
|
||||
## Disk Space Benefits
|
||||
|
||||
pnpm saves significant disk space:
|
||||
|
||||
- **Deduplication**: Same package version stored once across all projects
|
||||
- **Content deduplication**: Identical files across different packages stored once
|
||||
- **Hard links**: No copying, just linking
|
||||
|
||||
### Check disk usage
|
||||
|
||||
```bash
|
||||
# Compare actual vs apparent size
|
||||
du -sh node_modules # Apparent size
|
||||
du -sh --apparent-size node_modules # With hard links counted
|
||||
```
|
||||
|
||||
## Node Linker Modes
|
||||
|
||||
Configure how `node_modules` is structured:
|
||||
|
||||
```ini
|
||||
# Default: Symlinked structure (recommended)
|
||||
node-linker=isolated
|
||||
|
||||
# Flat node_modules (npm-like, for compatibility)
|
||||
node-linker=hoisted
|
||||
|
||||
# PnP mode (experimental, like Yarn PnP)
|
||||
node-linker=pnp
|
||||
```
|
||||
|
||||
### Isolated Mode (Default)
|
||||
|
||||
- Strict dependency resolution
|
||||
- No phantom dependencies
|
||||
- Packages can only access declared dependencies
|
||||
|
||||
### Hoisted Mode
|
||||
|
||||
- Flat `node_modules` like npm
|
||||
- For compatibility with tools that don't support symlinks
|
||||
- Loses strictness benefits
|
||||
|
||||
## Side Effects Cache
|
||||
|
||||
Cache build outputs for native modules:
|
||||
|
||||
```ini
|
||||
# Enable side effects caching
|
||||
side-effects-cache=true
|
||||
|
||||
# Store side effects in project (instead of global store)
|
||||
side-effects-cache-readonly=true
|
||||
```
|
||||
|
||||
## Shared Store Across Machines
|
||||
|
||||
For CI/CD, you can share the store:
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Store corruption
|
||||
```bash
|
||||
# Verify and fix store
|
||||
pnpm store status
|
||||
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
|
||||
- https://pnpm.io/npmrc#store-dir
|
||||
-->
|
||||
205
skills/pnpm/references/core-workspaces.md
Normal file
205
skills/pnpm/references/core-workspaces.md
Normal file
@@ -0,0 +1,205 @@
|
||||
---
|
||||
name: pnpm-workspaces
|
||||
description: Monorepo support with workspaces for managing multiple packages
|
||||
---
|
||||
|
||||
# pnpm Workspaces
|
||||
|
||||
pnpm has built-in support for monorepos (multi-package repositories) through workspaces.
|
||||
|
||||
## Setting Up Workspaces
|
||||
|
||||
Create `pnpm-workspace.yaml` at the repository root:
|
||||
|
||||
```yaml
|
||||
packages:
|
||||
# Include all packages in packages/ directory
|
||||
- 'packages/*'
|
||||
# Include all apps
|
||||
- 'apps/*'
|
||||
# Include nested packages
|
||||
- 'tools/*/packages/*'
|
||||
# Exclude test directories
|
||||
- '!**/test/**'
|
||||
```
|
||||
|
||||
## Workspace Protocol
|
||||
|
||||
Use `workspace:` protocol to reference local packages:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@myorg/utils": "workspace:*",
|
||||
"@myorg/core": "workspace:^",
|
||||
"@myorg/types": "workspace:~"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 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` |
|
||||
|
||||
## Filtering Packages
|
||||
|
||||
Run commands on specific packages using `--filter`:
|
||||
|
||||
```bash
|
||||
# By package name
|
||||
pnpm --filter @myorg/app build
|
||||
pnpm -F @myorg/app build
|
||||
|
||||
# By directory path
|
||||
pnpm --filter "./packages/core" test
|
||||
|
||||
# Glob patterns
|
||||
pnpm --filter "@myorg/*" lint
|
||||
pnpm --filter "!@myorg/internal-*" publish
|
||||
|
||||
# All packages
|
||||
pnpm -r build
|
||||
pnpm --recursive build
|
||||
```
|
||||
|
||||
### Dependency-based Filtering
|
||||
|
||||
```bash
|
||||
# Package and all its dependencies
|
||||
pnpm --filter "...@myorg/app" build
|
||||
|
||||
# Package and all its dependents
|
||||
pnpm --filter "@myorg/core..." test
|
||||
|
||||
# Both directions
|
||||
pnpm --filter "...@myorg/shared..." build
|
||||
|
||||
# Changed since git ref
|
||||
pnpm --filter "...[origin/main]" test
|
||||
pnpm --filter "[HEAD~5]" lint
|
||||
```
|
||||
|
||||
## Workspace Commands
|
||||
|
||||
### Install dependencies
|
||||
```bash
|
||||
# Install all workspace packages
|
||||
pnpm install
|
||||
|
||||
# Add dependency to specific package
|
||||
pnpm --filter @myorg/app add lodash
|
||||
|
||||
# Add workspace dependency
|
||||
pnpm --filter @myorg/app add @myorg/utils
|
||||
```
|
||||
|
||||
### Run scripts
|
||||
```bash
|
||||
# Run in all packages with that script
|
||||
pnpm -r run build
|
||||
|
||||
# Run in topological order (dependencies first)
|
||||
pnpm -r --workspace-concurrency=1 run build
|
||||
|
||||
# Run in parallel
|
||||
pnpm -r --parallel run test
|
||||
|
||||
# Stream output
|
||||
pnpm -r --stream run dev
|
||||
```
|
||||
|
||||
### Execute commands
|
||||
```bash
|
||||
# Run command in all packages
|
||||
pnpm -r exec pwd
|
||||
|
||||
# Run in specific packages
|
||||
pnpm --filter "./packages/**" exec rm -rf dist
|
||||
```
|
||||
|
||||
## Workspace Settings
|
||||
|
||||
Configure in `.npmrc` or `pnpm-workspace.yaml`:
|
||||
|
||||
```ini
|
||||
# Link workspace packages automatically
|
||||
link-workspace-packages=true
|
||||
|
||||
# Prefer workspace packages over registry
|
||||
prefer-workspace-packages=true
|
||||
|
||||
# Single lockfile (recommended)
|
||||
shared-workspace-lockfile=true
|
||||
|
||||
# Workspace protocol handling
|
||||
save-workspace-protocol=rolling
|
||||
|
||||
# Concurrent workspace scripts
|
||||
workspace-concurrency=4
|
||||
```
|
||||
|
||||
## Publishing Workspaces
|
||||
|
||||
When publishing, `workspace:` protocols are converted:
|
||||
|
||||
```json
|
||||
// Before publish
|
||||
{
|
||||
"dependencies": {
|
||||
"@myorg/utils": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
// After publish
|
||||
{
|
||||
"dependencies": {
|
||||
"@myorg/utils": "^1.2.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `--no-git-checks` for publishing from CI:
|
||||
```bash
|
||||
pnpm publish -r --no-git-checks
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use workspace protocol** for internal dependencies
|
||||
2. **Enable `link-workspace-packages`** for automatic linking
|
||||
3. **Use shared lockfile** for consistency
|
||||
4. **Filter by dependencies** when building to ensure correct order
|
||||
5. **Use catalogs** for shared external dependency versions
|
||||
|
||||
## Example Project Structure
|
||||
|
||||
```
|
||||
my-monorepo/
|
||||
├── pnpm-workspace.yaml
|
||||
├── package.json
|
||||
├── pnpm-lock.yaml
|
||||
├── packages/
|
||||
│ ├── core/
|
||||
│ │ └── package.json
|
||||
│ ├── utils/
|
||||
│ │ └── package.json
|
||||
│ └── types/
|
||||
│ └── package.json
|
||||
└── apps/
|
||||
├── web/
|
||||
│ └── package.json
|
||||
└── api/
|
||||
└── package.json
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/workspaces
|
||||
- https://pnpm.io/filtering
|
||||
- https://pnpm.io/npmrc#workspace-settings
|
||||
-->
|
||||
168
skills/pnpm/references/features-aliases.md
Normal file
168
skills/pnpm/references/features-aliases.md
Normal file
@@ -0,0 +1,168 @@
|
||||
---
|
||||
name: pnpm-aliases
|
||||
description: Install packages under custom names for versioning, forks, or alternatives
|
||||
---
|
||||
|
||||
# pnpm Aliases
|
||||
|
||||
pnpm supports package aliases using the `npm:` protocol. This lets you install packages under different names, use multiple versions of the same package, or substitute packages.
|
||||
|
||||
## Basic Syntax
|
||||
|
||||
```bash
|
||||
pnpm add <alias>@npm:<package>@<version>
|
||||
```
|
||||
|
||||
In `package.json`:
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"<alias>": "npm:<package>@<version>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Multiple Versions of Same Package
|
||||
|
||||
Install different versions side by side:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"lodash3": "npm:lodash@3",
|
||||
"lodash4": "npm:lodash@4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Usage:
|
||||
```js
|
||||
import lodash3 from 'lodash3'
|
||||
import lodash4 from 'lodash4'
|
||||
```
|
||||
|
||||
### Replace Package with Fork
|
||||
|
||||
Substitute a package with a fork or alternative:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"original-pkg": "npm:my-fork@^1.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All imports of `original-pkg` will resolve to `my-fork`.
|
||||
|
||||
### Replace Deprecated Package
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"request": "npm:@cypress/request@^3.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Scoped to Unscoped (or vice versa)
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"vue": "npm:@anthropic/vue@^3.0.0",
|
||||
"@myorg/utils": "npm:lodash@^4.17.21"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## CLI Usage
|
||||
|
||||
### Add with alias
|
||||
|
||||
```bash
|
||||
# Add lodash under alias
|
||||
pnpm add lodash4@npm:lodash@4
|
||||
|
||||
# Add fork as original name
|
||||
pnpm add request@npm:@cypress/request
|
||||
```
|
||||
|
||||
### Add multiple versions
|
||||
|
||||
```bash
|
||||
pnpm add react17@npm:react@17 react18@npm:react@18
|
||||
```
|
||||
|
||||
## With TypeScript
|
||||
|
||||
For type resolution with aliases, you may need to configure TypeScript:
|
||||
|
||||
```json
|
||||
// tsconfig.json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"lodash3": ["node_modules/lodash3"],
|
||||
"lodash4": ["node_modules/lodash4"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or use `@types` packages with aliases:
|
||||
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
"@types/lodash3": "npm:@types/lodash@3",
|
||||
"@types/lodash4": "npm:@types/lodash@4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Combined with Overrides
|
||||
|
||||
Force all transitive dependencies to use an alias:
|
||||
|
||||
```yaml
|
||||
# pnpm-workspace.yaml
|
||||
overrides:
|
||||
"underscore": "npm:lodash@^4.17.21"
|
||||
```
|
||||
|
||||
This replaces all `underscore` imports (including in dependencies) with lodash.
|
||||
|
||||
## Git and Local Aliases
|
||||
|
||||
Aliases work with any valid pnpm specifier:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"my-fork": "npm:user/repo#commit",
|
||||
"local-pkg": "file:../local-package"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Clear naming**: Use descriptive alias names that indicate purpose
|
||||
```json
|
||||
"lodash-legacy": "npm:lodash@3"
|
||||
"lodash-modern": "npm:lodash@4"
|
||||
```
|
||||
|
||||
2. **Document aliases**: Add comments or documentation explaining why aliases exist
|
||||
|
||||
3. **Prefer overrides for global replacement**: If you want to replace a package everywhere, use overrides instead of aliases
|
||||
|
||||
4. **Test thoroughly**: Aliased packages may have subtle differences in behavior
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/aliases
|
||||
-->
|
||||
159
skills/pnpm/references/features-catalogs.md
Normal file
159
skills/pnpm/references/features-catalogs.md
Normal file
@@ -0,0 +1,159 @@
|
||||
---
|
||||
name: pnpm-catalogs
|
||||
description: Centralized dependency version management for workspaces
|
||||
---
|
||||
|
||||
# pnpm Catalogs
|
||||
|
||||
Catalogs provide a centralized way to manage dependency versions across a workspace. Define versions once, use everywhere.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Define a catalog in `pnpm-workspace.yaml`:
|
||||
|
||||
```yaml
|
||||
packages:
|
||||
- 'packages/*'
|
||||
|
||||
catalog:
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
typescript: ~5.3.0
|
||||
vite: ^5.0.0
|
||||
```
|
||||
|
||||
Reference in `package.json` with `catalog:`:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "catalog:",
|
||||
"vite": "catalog:"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Named Catalogs
|
||||
|
||||
Create multiple catalogs for different scenarios:
|
||||
|
||||
```yaml
|
||||
packages:
|
||||
- 'packages/*'
|
||||
|
||||
# Default catalog
|
||||
catalog:
|
||||
lodash: ^4.17.21
|
||||
|
||||
# Named catalogs
|
||||
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
|
||||
```
|
||||
|
||||
Reference named catalogs:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "catalog:react18",
|
||||
"react-dom": "catalog:react18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitest": "catalog:testing"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Single source of truth**: Update version in one place
|
||||
2. **Consistency**: All packages use the same version
|
||||
3. **Easy upgrades**: Change version once, affects entire workspace
|
||||
4. **Type-safe**: TypeScript support in pnpm-workspace.yaml
|
||||
|
||||
## 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 |
|
||||
|
||||
## Publishing with Catalogs
|
||||
|
||||
When publishing, `catalog:` references are replaced with actual versions:
|
||||
|
||||
```json
|
||||
// Before publish (source)
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
// After publish (published package)
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Migration from Overrides
|
||||
|
||||
If you're using overrides for version consistency:
|
||||
|
||||
```yaml
|
||||
# Before (using overrides)
|
||||
overrides:
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
```
|
||||
|
||||
Migrate to catalogs for cleaner dependency management:
|
||||
|
||||
```yaml
|
||||
# After (using catalogs)
|
||||
catalog:
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
```
|
||||
|
||||
Then update package.json files to use `catalog:`.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use default catalog** for commonly shared dependencies
|
||||
2. **Use named catalogs** for version variants (e.g., different React versions)
|
||||
3. **Keep catalog minimal** - only include shared dependencies
|
||||
4. **Combine with workspace protocol** for internal packages
|
||||
|
||||
```yaml
|
||||
catalog:
|
||||
# External shared dependencies
|
||||
lodash: ^4.17.21
|
||||
zod: ^3.22.0
|
||||
|
||||
# Internal packages use workspace: protocol instead
|
||||
# "dependencies": { "@myorg/utils": "workspace:^" }
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/catalogs
|
||||
-->
|
||||
233
skills/pnpm/references/features-hooks.md
Normal file
233
skills/pnpm/references/features-hooks.md
Normal file
@@ -0,0 +1,233 @@
|
||||
---
|
||||
name: pnpm-hooks
|
||||
description: Customize package resolution and dependency behavior with pnpmfile hooks
|
||||
---
|
||||
|
||||
# pnpm Hooks
|
||||
|
||||
pnpm provides hooks via `.pnpmfile.cjs` to customize how packages are resolved and their metadata is processed.
|
||||
|
||||
## Setup
|
||||
|
||||
Create `.pnpmfile.cjs` at workspace root:
|
||||
|
||||
```js
|
||||
// .pnpmfile.cjs
|
||||
function readPackage(pkg, context) {
|
||||
// Modify package metadata
|
||||
return pkg
|
||||
}
|
||||
|
||||
function afterAllResolved(lockfile, context) {
|
||||
// Modify lockfile
|
||||
return lockfile
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage,
|
||||
afterAllResolved
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## readPackage Hook
|
||||
|
||||
Called for every package before resolution. Use to modify dependencies, add missing peer deps, or fix broken packages.
|
||||
|
||||
### Add Missing Peer Dependency
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
if (pkg.name === 'some-broken-package') {
|
||||
pkg.peerDependencies = {
|
||||
...pkg.peerDependencies,
|
||||
react: '*'
|
||||
}
|
||||
context.log(`Added react peer dep to ${pkg.name}`)
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
### Override Dependency Version
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Fix all lodash versions
|
||||
if (pkg.dependencies?.lodash) {
|
||||
pkg.dependencies.lodash = '^4.17.21'
|
||||
}
|
||||
if (pkg.devDependencies?.lodash) {
|
||||
pkg.devDependencies.lodash = '^4.17.21'
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
### Remove Unwanted Dependency
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Remove optional dependency that causes issues
|
||||
if (pkg.optionalDependencies?.fsevents) {
|
||||
delete pkg.optionalDependencies.fsevents
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
### Replace Package
|
||||
|
||||
```js
|
||||
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']
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
### Fix Broken Package
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Fix incorrect exports field
|
||||
if (pkg.name === 'broken-esm-package') {
|
||||
pkg.exports = {
|
||||
'.': {
|
||||
import: './dist/index.mjs',
|
||||
require: './dist/index.cjs'
|
||||
}
|
||||
}
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
## afterAllResolved Hook
|
||||
|
||||
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`)
|
||||
|
||||
// Modify lockfile if needed
|
||||
return lockfile
|
||||
}
|
||||
```
|
||||
|
||||
## Context Object
|
||||
|
||||
The `context` object provides utilities:
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Log messages
|
||||
context.log('Processing package...')
|
||||
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
## Use with TypeScript
|
||||
|
||||
For type hints, use JSDoc:
|
||||
|
||||
```js
|
||||
// .pnpmfile.cjs
|
||||
|
||||
/**
|
||||
* @param {import('type-fest').PackageJson} pkg
|
||||
* @param {{ log: (msg: string) => void }} context
|
||||
* @returns {import('type-fest').PackageJson}
|
||||
*/
|
||||
function readPackage(pkg, context) {
|
||||
return pkg
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Conditional by Package Name
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
switch (pkg.name) {
|
||||
case 'package-a':
|
||||
pkg.dependencies.foo = '^2.0.0'
|
||||
break
|
||||
case 'package-b':
|
||||
delete pkg.optionalDependencies.bar
|
||||
break
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
### Apply to All Packages
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Remove all optional fsevents
|
||||
if (pkg.optionalDependencies) {
|
||||
delete pkg.optionalDependencies.fsevents
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Resolution
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
if (process.env.DEBUG_PNPM) {
|
||||
context.log(`${pkg.name}@${pkg.version}`)
|
||||
context.log(` deps: ${Object.keys(pkg.dependencies || {}).join(', ')}`)
|
||||
}
|
||||
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 |
|
||||
|
||||
**Prefer overrides** for simple version fixes. **Use hooks** when you need:
|
||||
- Conditional logic
|
||||
- Non-version modifications (exports, peer deps)
|
||||
- Logging/debugging
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook not running
|
||||
|
||||
1. Ensure file is named `.pnpmfile.cjs` (not `.js`)
|
||||
2. Check file is at workspace root
|
||||
3. Run `pnpm install` to trigger hooks
|
||||
|
||||
### Debug hooks
|
||||
|
||||
```bash
|
||||
# See hook logs
|
||||
pnpm install --reporter=append-only
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/pnpmfile
|
||||
-->
|
||||
184
skills/pnpm/references/features-overrides.md
Normal file
184
skills/pnpm/references/features-overrides.md
Normal file
@@ -0,0 +1,184 @@
|
||||
---
|
||||
name: pnpm-overrides
|
||||
description: Force specific versions of dependencies including transitive dependencies
|
||||
---
|
||||
|
||||
# pnpm Overrides
|
||||
|
||||
Overrides let you force specific versions of packages, including transitive dependencies. Useful for fixing security vulnerabilities or compatibility issues.
|
||||
|
||||
## Basic Syntax
|
||||
|
||||
Define overrides in `pnpm-workspace.yaml` (recommended) or `package.json`:
|
||||
|
||||
### In pnpm-workspace.yaml (Recommended)
|
||||
|
||||
```yaml
|
||||
packages:
|
||||
- 'packages/*'
|
||||
|
||||
overrides:
|
||||
# Override all versions of a package
|
||||
lodash: ^4.17.21
|
||||
|
||||
# Override specific version range
|
||||
"foo@^1.0.0": ^1.2.3
|
||||
|
||||
# Override nested dependency
|
||||
"express>cookie": ^0.6.0
|
||||
|
||||
# Override to different package
|
||||
"underscore": "npm:lodash@^4.17.21"
|
||||
```
|
||||
|
||||
### In package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"lodash": "^4.17.21",
|
||||
"foo@^1.0.0": "^1.2.3",
|
||||
"bar@^2.0.0>qux": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
```
|
||||
Only override foo when the requested version matches ^1.0.0.
|
||||
|
||||
### Override nested dependency
|
||||
```yaml
|
||||
overrides:
|
||||
"express>cookie": ^0.6.0
|
||||
"foo@1.x>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": "-"
|
||||
```
|
||||
The `-` removes the package entirely.
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### Security Fix
|
||||
|
||||
Force patched version of vulnerable package:
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
# Fix CVE in transitive dependency
|
||||
"minimist": "^1.2.6"
|
||||
"json5": "^2.2.3"
|
||||
```
|
||||
|
||||
### Deduplicate Dependencies
|
||||
|
||||
Force single version when multiple are installed:
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"react": "^18.2.0"
|
||||
"react-dom": "^18.2.0"
|
||||
```
|
||||
|
||||
### Fix Peer Dependency Issues
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"@types/react": "^18.2.0"
|
||||
```
|
||||
|
||||
### Replace Deprecated Package
|
||||
|
||||
```yaml
|
||||
overrides:
|
||||
"request": "npm:@cypress/request@^3.0.0"
|
||||
```
|
||||
|
||||
## Hooks Alternative
|
||||
|
||||
For more complex scenarios, use `.pnpmfile.cjs`:
|
||||
|
||||
```js
|
||||
// .pnpmfile.cjs
|
||||
function readPackage(pkg, context) {
|
||||
// Override dependency version
|
||||
if (pkg.dependencies?.lodash) {
|
||||
pkg.dependencies.lodash = '^4.17.21'
|
||||
}
|
||||
|
||||
// Add missing peer dependency
|
||||
if (pkg.name === 'some-package') {
|
||||
pkg.peerDependencies = {
|
||||
...pkg.peerDependencies,
|
||||
react: '*'
|
||||
}
|
||||
}
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
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 |
|
||||
|
||||
## Debugging
|
||||
|
||||
Check which version is resolved:
|
||||
|
||||
```bash
|
||||
# See resolved versions
|
||||
pnpm why lodash
|
||||
|
||||
# List all versions
|
||||
pnpm list lodash --depth=Infinity
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/package_json#pnpmoverrides
|
||||
- https://pnpm.io/pnpmfile
|
||||
-->
|
||||
201
skills/pnpm/references/features-patches.md
Normal file
201
skills/pnpm/references/features-patches.md
Normal file
@@ -0,0 +1,201 @@
|
||||
---
|
||||
name: pnpm-patches
|
||||
description: Patch third-party packages directly with customized fixes
|
||||
---
|
||||
|
||||
# pnpm Patches
|
||||
|
||||
pnpm's patching feature lets you modify third-party packages directly. Useful for applying fixes before upstream releases or customizing package behavior.
|
||||
|
||||
## Creating a Patch
|
||||
|
||||
### Step 1: Initialize Patch
|
||||
|
||||
```bash
|
||||
pnpm patch <pkg>@<version>
|
||||
|
||||
# Example
|
||||
pnpm patch express@4.18.2
|
||||
```
|
||||
|
||||
This creates a temporary directory with the package source and outputs the path:
|
||||
|
||||
```
|
||||
You can now edit the following folder: /tmp/abc123...
|
||||
```
|
||||
|
||||
### Step 2: Edit Files
|
||||
|
||||
Navigate to the temporary directory and make your changes:
|
||||
|
||||
```bash
|
||||
cd /tmp/abc123...
|
||||
# Edit files as needed
|
||||
```
|
||||
|
||||
### Step 3: Commit Patch
|
||||
|
||||
```bash
|
||||
pnpm patch-commit <path-from-step-1>
|
||||
|
||||
# Example
|
||||
pnpm patch-commit /tmp/abc123...
|
||||
```
|
||||
|
||||
This creates a `.patch` file in `patches/` and updates `package.json`:
|
||||
|
||||
```
|
||||
patches/
|
||||
└── express@4.18.2.patch
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"express@4.18.2": "patches/express@4.18.2.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Patch File Format
|
||||
|
||||
Patches use standard unified diff format:
|
||||
|
||||
```diff
|
||||
diff --git a/lib/router/index.js b/lib/router/index.js
|
||||
index abc123..def456 100644
|
||||
--- a/lib/router/index.js
|
||||
+++ b/lib/router/index.js
|
||||
@@ -100,6 +100,7 @@ function createRouter() {
|
||||
// Original code
|
||||
- const timeout = 30000;
|
||||
+ const timeout = 60000; // Extended timeout
|
||||
return router;
|
||||
}
|
||||
```
|
||||
|
||||
## Managing Patches
|
||||
|
||||
### List Patched Packages
|
||||
|
||||
```bash
|
||||
pnpm list --depth=0
|
||||
# Shows (patched) marker for patched packages
|
||||
```
|
||||
|
||||
### Update a Patch
|
||||
|
||||
```bash
|
||||
# Edit existing patch
|
||||
pnpm patch express@4.18.2
|
||||
|
||||
# After editing
|
||||
pnpm patch-commit <path>
|
||||
```
|
||||
|
||||
### Remove a Patch
|
||||
|
||||
```bash
|
||||
pnpm patch-remove <pkg>@<version>
|
||||
|
||||
# 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`
|
||||
|
||||
## Patch Configuration
|
||||
|
||||
### Custom Patches Directory
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"express@4.18.2": "custom-patches/my-express-fix.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Multiple Packages
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"express@4.18.2": "patches/express@4.18.2.patch",
|
||||
"lodash@4.17.21": "patches/lodash@4.17.21.patch",
|
||||
"@types/node@20.10.0": "patches/@types__node@20.10.0.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Workspaces
|
||||
|
||||
Patches are shared across the workspace. Define in the root `package.json`:
|
||||
|
||||
```json
|
||||
// Root package.json
|
||||
{
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"express@4.18.2": "patches/express@4.18.2.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All workspace packages using `express@4.18.2` will have the patch applied.
|
||||
|
||||
## Best Practices
|
||||
|
||||
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
|
||||
Fixes timeout issue. PR pending: https://github.com/expressjs/express/pull/1234
|
||||
```
|
||||
|
||||
3. **Minimize patches**: Keep patches small and focused. Large patches are hard to maintain.
|
||||
|
||||
4. **Track upstream**: Note upstream issues/PRs so you can remove patches when fixed.
|
||||
|
||||
5. **Test patches**: Ensure patched code works correctly in your use case.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Patch fails to apply
|
||||
|
||||
```
|
||||
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
|
||||
# Reapply changes
|
||||
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
|
||||
- https://pnpm.io/package_json#pnpmpatcheddependencies
|
||||
-->
|
||||
250
skills/pnpm/references/features-peer-deps.md
Normal file
250
skills/pnpm/references/features-peer-deps.md
Normal file
@@ -0,0 +1,250 @@
|
||||
---
|
||||
name: pnpm-peer-dependencies
|
||||
description: Handling peer dependencies with auto-install and resolution rules
|
||||
---
|
||||
|
||||
# pnpm Peer Dependencies
|
||||
|
||||
pnpm has strict peer dependency handling by default. It provides configuration options to control how peer dependencies are resolved and reported.
|
||||
|
||||
## Auto-Install Peer Dependencies
|
||||
|
||||
By default, pnpm automatically installs peer dependencies:
|
||||
|
||||
```ini
|
||||
# .npmrc (default is true since pnpm v8)
|
||||
auto-install-peers=true
|
||||
```
|
||||
|
||||
When enabled, pnpm automatically adds missing peer dependencies based on the best matching version.
|
||||
|
||||
## Strict Peer Dependencies
|
||||
|
||||
Control whether peer dependency issues cause errors:
|
||||
|
||||
```ini
|
||||
# Fail on peer dependency issues (default: false)
|
||||
strict-peer-dependencies=true
|
||||
```
|
||||
|
||||
When strict, pnpm will fail if:
|
||||
- Peer dependency is missing
|
||||
- Installed version doesn't match required range
|
||||
|
||||
## Peer Dependency Rules
|
||||
|
||||
Configure peer dependency behavior in `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": ["@babel/*", "eslint"],
|
||||
"allowedVersions": {
|
||||
"react": "17 || 18"
|
||||
},
|
||||
"allowAny": ["@types/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ignoreMissing
|
||||
|
||||
Suppress warnings for missing peer dependencies:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"@babel/*",
|
||||
"eslint",
|
||||
"webpack"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use patterns:
|
||||
- `"react"` - exact package name
|
||||
- `"@babel/*"` - all packages in scope
|
||||
- `"*"` - all packages (not recommended)
|
||||
|
||||
### allowedVersions
|
||||
|
||||
Allow specific versions that would otherwise cause warnings:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"allowedVersions": {
|
||||
"react": "17 || 18",
|
||||
"webpack": "4 || 5",
|
||||
"@types/react": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### allowAny
|
||||
|
||||
Allow any version for specified peer dependencies:
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"allowAny": ["@types/*", "eslint"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Adding Peer Dependencies via Hooks
|
||||
|
||||
Use `.pnpmfile.cjs` to add missing peer dependencies:
|
||||
|
||||
```js
|
||||
// .pnpmfile.cjs
|
||||
function readPackage(pkg, context) {
|
||||
// Add missing peer dependency
|
||||
if (pkg.name === 'problematic-package') {
|
||||
pkg.peerDependencies = {
|
||||
...pkg.peerDependencies,
|
||||
react: '*'
|
||||
}
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Peer Dependencies in Workspaces
|
||||
|
||||
Workspace packages can satisfy peer dependencies:
|
||||
|
||||
```json
|
||||
// packages/app/package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"@myorg/components": "workspace:^"
|
||||
}
|
||||
}
|
||||
|
||||
// packages/components/package.json
|
||||
{
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.0 || ^18.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The workspace `app` provides `react` which satisfies `components`' peer dependency.
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Monorepo with Shared React
|
||||
|
||||
```yaml
|
||||
# pnpm-workspace.yaml
|
||||
catalog:
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
```
|
||||
|
||||
```json
|
||||
// packages/ui/package.json
|
||||
{
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
// apps/web/package.json
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "catalog:",
|
||||
"react-dom": "catalog:",
|
||||
"@myorg/ui": "workspace:^"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Suppress ESLint Plugin Warnings
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"eslint",
|
||||
"@typescript-eslint/parser"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Allow Multiple Major Versions
|
||||
|
||||
```json
|
||||
{
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"allowedVersions": {
|
||||
"webpack": "4 || 5",
|
||||
"postcss": "7 || 8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Debugging Peer Dependencies
|
||||
|
||||
```bash
|
||||
# See why a package is installed
|
||||
pnpm why <package>
|
||||
|
||||
# List all peer dependency warnings
|
||||
pnpm install --reporter=append-only 2>&1 | grep -i peer
|
||||
|
||||
# Check dependency tree
|
||||
pnpm list --depth=Infinity
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Enable auto-install-peers** for convenience (default in pnpm v8+)
|
||||
|
||||
2. **Use peerDependencyRules** instead of ignoring all warnings
|
||||
|
||||
3. **Document suppressed warnings** explaining why they're safe
|
||||
|
||||
4. **Keep peer deps ranges wide** in libraries:
|
||||
```json
|
||||
{
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.0 || ^18.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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