Files
blog-press/docs/Web-Front/Others/Package.md
2025-12-15 23:25:25 +08:00

3.8 KiB
Raw Blame History

npm

2010年随Node.js发布的npm首次为JavaScript引入了标准的包管理系统。其核心创新是package.json文件,通过语义化版本规范定义了依赖声明标准。这一设计解决了手动管理依赖时的版本混乱问题,为模块化开发提供了基础设施。

第一阶段:嵌套依赖架构

早期版本采用树状嵌套的依赖结构。每个包将其依赖安装在自身的node_modules目录中形成深层嵌套。这种设计保证了依赖隔离但导致了几个严重问题

  • 路径深度问题依赖树深度可达十几层触发Windows 260字符路径限制
  • 空间极度浪费:相同包在不同层级重复安装,项目体积指数级膨胀
  • 安装性能低下大量递归操作导致I/O效率极低

第二阶段:扁平化依赖重构

2015年发布的npm v3引入扁平化依赖安装策略。该方案将可共享的依赖提升到顶层node_modules,减少嵌套深度。
  主要解决方案为:

  • 依赖提升算法:将兼容版本的依赖包提升至顶层
  • 冲突处理:版本冲突时,低版本保持嵌套结构
  • 确定性牺牲:提升顺序影响最终结构

  但同时也引入了新问题:

  • 幻影依赖:未声明但被提升的包意外可用
  • 依赖不确定性相同package.json产生不同目录结构
  • 模块解析复杂化Node.js模块解析算法与扁平结构不匹配

yarn

2016年发布的Yarn针对npm核心痛点提出了系统性解决方案:

  • 确定性版本锁定yarn.lock文件记录精确版本和依赖树
  • 并行下载优化:多线程并发下载提升网络利用率
  • 离线缓存机制:全局缓存支持离线安装
  • 完整性校验checksum验证确保包完整性

Yarn的成功迫使npm进行重大改进。npm v5版本借鉴了Yarn的核心设计增加了package-lock.json和缓存优化形成了技术竞争的良性循环。

pnpm

2017年发布的pnpm从存储层面重新设计了包管理模型。其核心是基于内容寻址的全局存储与符号链接架构
  实现原理:

  • 内容可寻址存储:包按内容哈希存储,全局唯一
  • 硬链接复用:相同包文件在所有项目间共享
  • 符号链接树通过软链接构建符合Node.js解析规则的依赖树
  • 严格依赖隔离:每个包只能访问其声明的依赖

npm/yarn的node_modules目录

项目A: node_modules/lodash@4.17.21
项目B: node_modules/lodash@4.17.21 # 重复存储
项目C: node_modules/lodash@4.17.21 # 重复存储

pnpm的node_modules目录

全局存储: .pnpm-store/lodash@4.17.21
项目A: 硬链接 → 全局存储
项目B: 硬链接 → 全局存储
项目C: 硬链接 → 全局存储

npm/Yarn采用扁平化结构包可访问非声明依赖pnpm采用符号链接嵌套结构包仅可访问声明依赖。
pnpm的符号链接架构在Monorepo场景中表现优异。跨包依赖通过本地文件系统链接实现避免了重复安装。Workspaces功能通过优化符号链接策略确保开发环境与生产环境一致性。

简单使用

# 通过 npm 安装
npm install -g pnpm

# 检查版本
pnpm --version

# 安装所有依赖(根据 package.json
pnpm install

# 安装生产依赖
pnpm add <package-name>

# 安装开发依赖
pnpm add -D <package-name>

# 移除依赖
pnpm remove <package-name>

# 查看所有配置
pnpm config list

# 设置存储路径
pnpm config set store-dir ~/.pnpm-store

# 使用淘宝镜像
pnpm config set registry https://registry.npmmirror.com/

::: tip npm确立了基本范式Yarn解决了确定性问题pnpm重构了存储模型 :::