shamefully-hoist is a pnpm configuration option used to create a flat node_modules structure similar to npm/Yarn.
Default Behavior vs shamefully-hoist:
bash# Default pnpm structure (strict) node_modules/ ├── .pnpm/ │ └── lodash@4.17.21/ └── lodash -> .pnpm/lodash@4.17.21/node_modules/lodash # Can only access declared dependencies const lodash = require('lodash'); // ✅ Normal const debug = require('debug'); // ❌ Error (not declared)
bash# shamefully-hoist=true structure (flat) node_modules/ ├── .pnpm/ ├── lodash/ ├── debug/ # Hoisted up └── ... # Can access all dependencies const lodash = require('lodash'); // ✅ Normal const debug = require('debug'); // ✅ Accessible (phantom dependency)
Configuration Method:
ini# .npmrc shamefully-hoist=true # Or hoist only specific packages shamefully-hoist-pattern[]=webpack shamefully-hoist-pattern[]=*types*
Usage Scenarios:
- Legacy Project Migration
ini# Project depends on phantom dependencies, temporarily can't modify # .npmrc shamefully-hoist=true # Should disable after migration # shamefully-hoist=false
- Specific Tool Compatibility
ini# Some tools require flat structure # Such as certain webpack plugins, IDEs, etc. shamefully-hoist=true
- Mixed Usage
ini# Only hoist specific packages public-hoist-pattern[]=*eslint* public-hoist-pattern[]=*prettier* public-hoist-pattern[]=*types*
Configuration Comparison:
| Configuration | Effect | Recommendation |
|---|---|---|
shamefully-hoist | Fully flat | ⭐⭐ |
public-hoist-pattern | Partially flat | ⭐⭐⭐⭐⭐ |
hoist-pattern | Internal flat | ⭐⭐⭐⭐ |
public-hoist-pattern Recommended Configuration:
ini# .npmrc # Hoist type definition packages public-hoist-pattern[]=*types* # Hoist build tools public-hoist-pattern[]=*eslint* public-hoist-pattern[]=*prettier* public-hoist-pattern[]=*webpack* # Hoist test tools public-hoist-pattern[]=*jest* public-hoist-pattern[]=*vitest*
Why Not Recommend Full Flattening:
javascript// Problems with shamefully-hoist=true // 1. Phantom dependencies const someDep = require('some-dep'); // Actually not declared in package.json // May cause CI/CD failures // 2. Version conflicts // Different packages depend on different versions of same package // After flattening, only one version can exist // 3. Lose pnpm advantages // Reduced disk space savings # Less strict dependency management
Best Practices:
ini# Recommended configuration # .npmrc # Default no flattening shamefully-hoist=false # Only hoist necessary packages public-hoist-pattern[]=*eslint* public-hoist-pattern[]=*prettier* public-hoist-pattern[]=*types* # Strict mode strict-peer-dependencies=true
Migration Strategy:
bash# 1. First enable shamefully-hoist for migration # .npmrc shamefully-hoist=true # 2. Run project, check for issues pnpm install pnpm build pnpm test # 3. Gradually fix phantom dependencies # Find all undeclared dependencies pnpm ls --depth=10 # 4. Add to package.json pnpm add missing-dep # 5. Disable shamefully-hoist # .npmrc shamefully-hoist=false
Check Phantom Dependencies:
bash# Use depcheck to check cd project npx depcheck # Or use pnpm to check pnpm ls --depth=0
Summary:
shamefully-hoistis a migration transition solution- Should be disabled for long-term use to maintain pnpm's strictness
- Use
public-hoist-patterninstead of full flattening - Gradually fix phantom dependencies and return to standard mode