本节摘要:Yarn 不是"另一个 npm",它出现的那一刻,包管理的评价标准被重新定义了。本节勘验 Yarn 发布时的三份证物——锁文件、并行下载管线、工作区——说明每项创新分别击中 Npm 的哪个痛点、改变了行业哪条默认期望。本节的关键结论:Yarn 最深的遗产不是工具市占率,而是把"安装必须可复现、必须快、必须能管多包仓库"从加分项变成了及格线。
设想一个反例场景:团队里两位工程师,同一个项目、同一份 package.json,各自全新安装。结果一位构建通过,另一位报错。排查半天,发现唯一的差异是安装日期——中间某个远端包发了新版,版本范围声明允许它悄悄溜进来。在锁文件普及之前,这类事故不是新闻,是日常。本节的主角 Yarn,就是从这个日常里长出来的。
2016 年,一家大型社交平台联合几家公司发布了 Yarn。发布团队并不掩饰动机:他们内部规模巨大的代码库早已被安装不确定性、缓慢速度与磁盘冗余折磨多年,决定自己造一台机器。拆开这台机器,核心部件有三件。
证物一:yarn.lock。 安装完成时,Yarn 把解析结果——每个包的精确版本、下载地址、完整性哈希——写成一份锁文件提交进版本库。此后任何人在任何时间安装,都直接照单执行,不再重新求解。愿望清单(package.json)与执行结果(锁文件)从此分离:前者表达"我想要什么范围",后者记录"实际拿到了什么"。
# yarn.lock 片段:每条记录三要素——精确版本、解析地址、完整性哈希 lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57...
这三行结构就是第三章的主角,这里先记一个直觉:锁文件的本质是把"求解题"变成"抄写题"——求解可以每次不同,抄写永远一致。
证物二:并行下载与离线缓存。 当年的 Npm 串行下载包,网络往返一个接一个排队。Yarn 把下载管线并行化,同时把每个下载过的包存入本地缓存;下次遇到同版本包,直接从缓存取,不再碰网络。快,而且稳定——网络差的环境里优势更明显。
证物三:工作区(Workspaces)。 一个仓库里放多个包、互相引用、统一安装——Monorepo 的这套需求,当年要么靠软链接手工维护,要么靠发布到私有仓库绕路解决。Yarn 把工作区做成一等公民:在顶层声明一组子包,安装器自动把它们互相链接,本地引用如同引用远端包一样自然。

把三份证物放回 1.1 节的标尺上量,会发现 Yarn 精准命中了全部三组矛盾:锁文件治"一致与漂移",并行加缓存治"效率与规模",工作区治的则是规模问题的组织形态——大团队如何拆分协作边界。一次发布同时回应三组矛盾,这才是"范式转移"的分量:它不是把某处做得更好,而是把"什么叫合格的包管理器"重新写了。
Npm 的回应在上一节已经勘验过:五代锁文件、并行安装、缓存重构、七代内置工作区,三四年内全部补齐。竞争的结果耐人寻味——两家工具在机制层高度趋同,用户侧反而获得了最大的自由度:选哪个都不再是重大风险决策,因为底线已经被共同抬高了。
趋同不等于无差别。两者真正的分野留在两处:一是 Yarn 在二代(常称 Berry)押上的免安装实验路线,激进地想连 node_modules 都取消掉,第五章 5.2 专门勘验;二是命令语义的细节差异——比如安装命令对清单的修改时机、锁文件格式,这些差异正是第七章迁移实务要逐条对账的内容。
行话听再多,不如跑一次对照。在同一项目目录分别实验"有锁文件"与"无锁文件"的安装:
# 实验A:标准安装(锁文件在场) $ rm -rf node_modules $ yarn install --frozen-lockfile # 输出关键行:Done in 9.42s —— 全程照单执行,无求解过程 # 实验B:删除锁文件再装(回到范式前时代) $ rm -rf node_modules yarn.lock $ yarn install # 输出关键行:info Lockfile is missing —— 进入求解模式 # 每个范围声明重新求最新版本,安装结果取决于此刻的远端状态
实验 A 与 B 的差异就是范式差的体感版本:A 是抄写,B 是重考。值得注意的是实验 B 的隐蔽风险——它大概率也能成功,只是装出来的版本组合已经悄悄变了。能跑和该跑是两回事,这正是锁文件存在的理由。
勘验现场之外,几个被反复问到的问题值得提前裁决。其一:Yarn 一代与二代怎么选? 一代是稳妥的当代选择,语义与主流完全兼容;二代(Berry)是形态实验的前沿,带来免安装与严格性的同时也带来适配成本。给团队的建议按 5.2 节的三问走,再加一条:新项目可以试用二代,存量项目切二代的迁移成本要单独立项评估,不要搭车。
其二:零安装把缓存提交进仓库,到底好不好? 好处是新成员克隆即用、真正离线、依赖历史随代码审查可见——评审者能在评审里直接看到依赖变更的完整内容。代价是仓库体积膨胀、二进制依赖让代码仓库变重、合并冲突面进一步扩大。适用判断很简单:依赖树小而稳定的库类项目收益明显,依赖庞大且频繁变动的应用类项目慎用。
其三:一个仓库能同时用 Npm 和 Yarn 吗? 短期可以但不该长期。清单文件两家都能读,可各自安装会生成各自的锁文件,两个事实源并存的恶果在 7.2 节有完整案例——那里给出的最高禁令(两把锁并存即事故)在这里先立此存照:团队工具必须统一,切换要走正式迁移流程而非各装各的。
第一章到此收束:三组矛盾、两个主角、一条被抬高的行业底线。第二章开始下钻机制——先勘验那台"把范围变成精确版本"的解析引擎,幽灵依赖的成因也会在那里现出原形。