面向 Windows 开发环境的一套可复用方案:用 fnm 管理
Node,多版本隔离;用 Corepack 管理包管理器;将项目升级到 Yarn4,并按需启用 PnP

0. 设计目标

  • 可控安装路径(避免系统盘污染)
  • 多 Node 版本快速切换
  • 包管理器版本随项目锁定(可复现)
  • 减少 node_modules 带来的体积与 I/O 开销(可选 PnP)

1. fnm 安装与路径规划

1.1 安装(自定义路径,假设我们自定义安装路径为:D:\fnm)

winget install Schniz.fnm --location D:\fnm

1.2 PowerShell 注入

注意,只在 powershell 中有用,在 cmd 中无效

打开Microsoft.PowerShell_profile.ps1并进行配置

notepad $profile

修改内容并保存

$env:FNM_DIR="D:\fnm"
fnm env --use-on-cd | Out-String | Invoke-Expression
顺序必须:先设置 FNM_DIR,再执行 fnm env

1.3 Node 安装与验证

fnm install 21
fnm list
node -v

2. Corepack 与 Yarn 版本认知纠偏

2.1 常见误区

  • corepack enable ≠ 使用最新 Yarn
  • ❌ Yarn 并不随 Node 自动升级到最新大版本

2.2 正确姿势

corepack enable
yarn set version stable
Corepack 默认指向 Yarn v1(Classic)最新小版本,需要手动切换到现代版本(v3/v4)。

3. 为什么要升级到 Yarn 3/4

3.1 关键改进

  • Plug'n'Play(PnP)依赖解析
  • 更严格的依赖边界(杜绝"幽灵依赖")
  • 更高效的 I/O 与磁盘占用
  • 更清晰的错误信息

3.2 与传统 node_modules 对比(实测案例)

模式体积
node_modules~294MB
PnP + .yarn~40MB + <1MB

4. 新项目初始化(推荐)

yarn init -2

效果:

  • 自动生成 .yarn/
  • 生成 .pnp.cjs
  • node_modules

5. 旧项目升级路径

yarn set version stable
yarn install

默认行为:

# .yarnrc.yml
nodeLinker: node-modules
出于兼容性考虑,旧项目不会默认启用 PnP。

6. 启用 PnP(可选进阶)

nodeLinker: pnp

然后:

yarn install

结果:

  • 删除 node_modules
  • 生成:

    • .pnp.cjs
    • .pnp.loader.mjs
    • .yarn/

7. 使用习惯变化(重要)

7.1 替代 global

yarn dlx create-vite

7.2 替代 node_modules/.bin

yarn run build

7.3 运行 Node

yarn node main.js

8. Git 忽略策略

.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

9. 兼容性与限制

不建议启用 PnP 的场景:

  • React Native
  • Flow
  • 某些依赖路径写死的老项目

10. 部署环境注意事项

Cloudflare Pages

  • 默认:

    • Node 18+
    • Yarn 3+

如果检测到:

Yarn v1 config detected

说明项目仍在使用 Classic,需要升级。


11. 实战建议(工程化)

推荐组合

组件 方案
-------------- ----------------------------
Node 管理 fnm
包管理器管理 Corepack
包管理器 Yarn 4
依赖模式 node_modules → PnP(渐进)

进阶策略

  • 项目内锁定 Yarn 版本(.yarn/releases
  • 使用 .node-version 固定 Node
  • CI 中启用 corepack

12. 总结

这套组合的本质是:

把"环境不确定性"收敛到项目内部
  • fnm:控制 Node
  • Corepack:控制 Yarn
  • Yarn:控制依赖解析方式

最终实现:

  • 可复现
  • 可迁移
  • 高性能

13. 延伸阅读方向

  • pnpm vs Yarn PnP 架构差异
  • Node ESM Loader 机制(.pnp.loader.mjs)
  • Monorepo(Yarn Workspaces)