Deep Dive into npm, Yarn, and pnpm Dependency Management
This article explains how npm, Yarn, and pnpm manage JavaScript dependencies, detailing installation processes, flat vs nested node_modules structures, lock files, and the hard-link mechanism that improves speed and saves disk space.
Frontend developers daily encounter xxx install commands; package managers are essential tools for managing library dependencies in projects.
The article first explains how npm installs dependencies: sending npm install , querying the registry for the tarball URL, downloading the package to ~/.npm , and extracting it into the project's node_modules directory.
It then contrasts npm2 and npm3 behaviors. npm2 creates a nested node_modules structure where each package's dependencies are installed under its own folder, leading to duplication and deep trees (the "nesting hell"). npm3 attempts to flatten the tree by hoisting dependencies to the top level when possible, which reduces duplication but introduces uncertainty about which version gets hoisted, ghost dependencies (packages accessible without being declared in package.json ), and doppelganger dependencies (multiple copies of the same package when hoisting cannot avoid duplication).
Yarn improves installation speed by performing tasks in parallel rather than the serial approach of early npm. Its most important feature is the yarn.lock file, which locks exact versions of all resolved dependencies, ensuring deterministic installs across environments. The lock file records versions but relies on package.json for the dependency graph.
pnpm takes a different approach using a global store and link mechanisms. Each package version is stored once in a global content-addressable store. During pnpm install , hard links ( hard link ) from the store to a virtual node_modules/.pnpm folder provide the actual files, while symbolic links ( symbolic link ) inside that folder express the dependency relationships. This yields near‑zero extra disk space usage and fast installs because files are not copied. Advantages include elimination of ghost and doppelganger dependencies, while disadvantages involve potential side‑effects from shared hard links (e.g., post‑install scripts affecting all projects) and incompatibility with environments that do not support symbolic links (such as Electron).
For migration from npm or Yarn to pnpm, the author recommends deleting node_modules , running pnpm i , and then iteratively adding missing packages discovered via pnpm dev until the project runs without errors. This process helps uncover ghost dependencies that were previously accessible only through hoisting.
The article concludes by referencing tools like @sugarat/ghost for detecting undeclared dependencies and suggests using faster alternatives such as SWC for scanning large codebases.
ByteFE
Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.