01|这篇真正要讲的,不是“JavaScript 社区为什么爱造轮子”,而是 npm 为什么会把“拆得更细”推成一种看起来很合理的生态直觉

今天很多人回头吐槽 npm 生态,最常见的一类抱怨就是:

  • 一个项目依赖太多
  • 一个很小的功能也要装包
  • 依赖树深得吓人
  • node_modules 看起来像失控森林

于是很容易顺着得出一个结论:

JavaScript 社区是不是天生就特别喜欢把东西拆碎。

这话当然不是完全没道理。

可如果只停在“社区风气”这一层,还是会把历史写浅。

因为 npm 世界里的小包文化之所以会疯长,

不是因为突然有一批人集体迷恋一行代码一个包。

更深的原因是:

npm 把“把一个小功能独立发出来、让别人顺手装上”这件事做得太便宜了。

而一旦复用成本被压得足够低,

整个生态就会很容易出现一种新直觉:

  • 能拆,就拆
  • 能复用,就复用
  • 能发成独立包,就别留在大项目里
  • 能依赖现成模块,就别自己重写

这套直觉一开始看起来并不疯狂。

恰恰相反,

它在当时甚至显得很先进、很现代、很工程化。

所以第二篇真正要问的,不是:

“为什么 npm 生态后来有那么多小包?”

而是:

为什么在 npm 世界里,把东西拆得更细,最早会被很多人自然理解成一种进步。


02|因为 npm 先完成了一件特别关键的事:它把“共享模块”从一件麻烦事,变成了一件默认小动作

上一篇讲的是 npm 为什么能迅速长成中央仓库。

那一篇的重点在入口。

这一篇要往前推一步,去看入口一旦形成之后,会发生什么。

最关键的变化就是:

共享模块的摩擦突然变得非常低。

在很多生态里,你当然也能复用代码。

可复用如果要经过很多步骤,

大家就还是会本能地偏向:

  • 自己写一份
  • 直接拷进项目
  • 在大仓库里顺手放着

因为“单独抽出来再发出去”太麻烦。

npm 把这件事改了。

有了 package.json,有了版本,有了依赖声明,有了 publish,有了 install

一个原本只服务自己项目的小功能,

突然就很容易被做成:

一个独立可流通的软件单位。

这会带来一个很重要的心理变化。

那就是开发者不再只把“抽公共逻辑”理解成:

项目内部整理代码。

他开始把它理解成:

我可以把这段逻辑正式做成一个包。

这一步特别关键。

因为只要“正式做成一个包”的门槛足够低,

模块拆分就不再只是代码风格问题。

它会慢慢变成:

  • 发布习惯
  • 复用习惯
  • 生态协作习惯

而这正是小包文化会爆炸的前提。


03|为什么“拆得更细”在当时会显得如此有道理?因为它刚好同时满足了工程美学和开放生态美学

这一步要再往里看一层。

因为一个习惯如果后来能长成文化,

通常不是因为它只有坏处。

恰恰相反,

它往往是在早期看起来很像正确答案。

小包文化就是这样。

它最早吸引人的地方其实非常多:

  • 单一职责看起来更清楚
  • 包做得小,测试和维护似乎更容易
  • API 边界更窄,复用看起来更直接
  • 不同项目之间可以像搭积木一样组合能力

这套想法其实很顺。

因为它同时踩中了两套很强的美学。

第一套是工程美学:

一个模块最好只做一件事。

第二套是开放生态美学:

既然这件事别人也可能会用,那就把它独立出来共享给所有人。

你会发现,这两套美学在 npm 世界里几乎天然互相强化。

模块越小,

看起来越像“职责纯粹”。

越职责纯粹,

越容易被包装成一个独立包。

越能独立成包,

就越容易被别的项目拿去复用。

所以这时候,小包文化并不只是一种技术偏好。

它看起来更像一种道德上也站得住脚的好习惯:

我不是在无谓拆碎代码,我是在给生态贡献更可复用的积木。

这就是它最早最有感染力的地方。


04|更麻烦的是,npm 还让“依赖别人写的小东西”变得几乎没有心理负担

如果只是“发包容易”,小包文化还不一定会疯长到那个程度。

真正把这件事推快的,是另一面:

装包也太容易了。

这点很重要。

因为一个生态里再多小模块,

只要使用成本高,

它们就很难形成真正的繁殖效应。

可 npm 世界给出的是另一种现实:

  • 想用就 install
  • 依赖会写进 package.json
  • 版本范围可以声明
  • 下一次别人拉项目,直接一起装下来

Node 官方后来对 npm 的介绍甚至会把这种感觉说得很直接:

registry 里有海量包,

几乎什么都有。

这会让开发者逐步形成一种本能:

遇到一个很具体的小问题,先看看有没有现成小包。

而一旦这个本能形成,

生态就会自动往“更细颗粒、更高复用”那边滑。

因为需求会反向塑造供给。

使用者愿意装非常细的小包,

作者就更愿意发非常细的小包。

作者越愿意发,

使用者就越觉得“这类小问题应该先搜包”。

于是一个自我强化的循环就长出来了。

这时候,拆细不再只是作者单方面的偏好。

它变成了供需两端一起推高的文化惯性。


05|所以 npm 最早推广的,不只是复用本身,而是一种特别激进的复用观:连很小的能力也值得独立流通

这是第二篇最关键的一层。

很多生态当然也讲复用。

可 npm 世界的独特之处在于:

它把复用推进得非常细。

不是只有“大库”“大框架”“大工具”值得共享。

而是连这种东西也可以被独立出来:

  • 一个字符串处理函数
  • 一个对象判断函数
  • 一个颜色转换函数
  • 一个命令行参数小工具

换句话说,npm 世界慢慢形成的是一种特别激进的复用观:

只要某段逻辑有可能在别处再出现一次,它就值得被做成包。

这套观念如果只从结果看,当然很容易被嘲笑。

可如果放回当时的历史位置,它其实非常顺。

因为 npmNode 一起给了这种观念足够强的现实支撑:

  • 包可以轻易发布
  • 包可以轻易安装
  • 包可以声明依赖关系
  • 包可以被更多包继续依赖

一旦这些条件都成立,

“连很小的东西也值得独立流通”就不再只是口号。

它会变成一个真的能跑起来的生态模式。

而这正是后来那些著名微型模块层出不穷的根本原因。


06|可问题也就从这里开始:当拆分越来越容易,生态很容易悄悄把“能拆”误当成“该拆”

这一步,就是第二篇要开始转折的地方。

因为小包文化最早的问题,不在于它完全错误。

问题在于:

它太容易从“这在某些情况下有益”滑向“这几乎总是更先进”。

这就是很多技术文化常见的命运。

一个原本很有价值的原则,

一旦进入大规模扩散阶段,

就容易被过度普适化。

在 npm 世界里,

这种过度普适化很容易表现成:

  • 只要能独立,就最好独立
  • 只要足够小,就好像更优雅
  • 只要能复用,就比留在本地更高级

这时,“单一职责”会悄悄变形。

它不再只是帮助你控制复杂度。

它开始变成一种文化压力:

你好像不把东西拆出去,就显得不够模块化。

而一旦文化压力形成,

技术系统就会被推向更极端的方向。

这也是为什么 npm 生态后来的问题,并不只是“包太多”。

而是:

生态慢慢养成了一种把细粒度拆分本身当作价值信号的习惯。

这就很危险了。

因为“能拆”是一种能力。

“该拆到什么程度”则是另一种判断。

而 npm 世界最早恰恰特别擅长前者,却没有来得及建立后一者的共同节制。


07|Isaac 自己后来的回看其实已经很说明问题:npm 未必真能阻止重复造轮子,它只是让造轮子和复用轮子都变得更高效

这点特别值得记住。

因为它能帮助我们避免把历史讲成简单的是非题。

Isaac Z. Schlueter 后来在采访里讲得很坦白:

他不能问心无愧地说 npm 真正阻止了重复造轮子,

因为 npm 上本来就有很多很多轮子。

他的希望是:

让重新造轮子这件事更容易、更高效,也让你别老是重复做同样已经做过的脏活。

这段话很重要。

因为它说明 npm 从一开始追求的,

未必是“让世界只剩一个最标准的实现”。

它更像是在说:

让模块流通得更快,让尝试不同实现也足够便宜。

这套哲学当然非常开放。

可它的副作用也很明显:

同一类问题会长出很多近似模块。

包的总量会非常夸张。

开发者会越来越习惯依赖别人写的小块逻辑。

而一旦这种习惯形成,

整个生态的依赖密度就会越来越高。

换句话说,

npm 小包文化并不是简单的“大家都不想自己写”。

它更像一种特别开放、特别高流速的生态后果:

写一个小包很便宜,用一个小包也很便宜,于是整个世界自然会越长越碎。


08|为什么小包文化不是歪风,而是 npm 机制最顺手的结果

把前面几层叠一起看,第二篇最重要的判断可以压成一句:

小包文化不是偶然长歪的,它一开始就是 npm 把复用成本压到极低之后最自然的文化结果。

这句话里有几层意思。

第一,小包文化不是先由某个极端案例带起来的。

它是中央仓库、package.jsonpublish / install 路径和版本机制共同作用的长期结果。

第二,它最早并不是负面文化。

它看起来同时符合工程美学和开放生态美学,所以特别容易被社区主动拥抱。

第三,真正的问题不是“模块化”本身。

而是生态后来慢慢把“复用很便宜”误滑成了“拆得更细总是更好”。

第四,这种文化一旦形成,

深依赖、脆弱性扩散和治理压力其实就已经在后面排队了。

所以理解 npm 的第二步,不该只记住:

“后来出现了很多一行代码的包。”

更该记住的是:

那些极端案例之所以可能出现,是因为整个生态在更早的时候,就已经被训练成把细粒度复用理解成一种几乎天然正确的方向。


09|小包文化是 npm 把复用做便宜之后的自然结果

npm 江湖 的第二篇,最值得记住的,不是“JavaScript 社区喜欢小题大做”这种轻浮判断。

更值得记住的是:

当 npm 把共享、安装、声明依赖和继续组合这几件事做得足够便宜之后,JavaScript 世界就自然长出了一种特别激进的复用文化,而小包文化正是这种文化最顺手、也最危险的表现。

也正因此,

后来大家看到 left-pad 那种案例时,

才会突然意识到一个此前没那么多人认真面对的事实:

原来一个看起来微不足道的小模块,真的可能挂在成千上万项目的关键路径上。

这也就是第三篇要接上的地方。

因为第三篇真正要讲的,不只是一次事故。

而是:

为什么整个行业要等到 left-pad 出事,才第一次被迫承认“小包复用的美学”背后,其实一直埋着一整套此前被低估的脆弱性。


编者注(事实核对):文中关于 npm 如何降低模块共享与安装门槛的描述,主要依据 npm Docs 中关于 package.jsondependencies / devDependenciesnpm installnpm publish 的说明,其中明确写到发布包最重要的字段是 nameversion,依赖关系可直接写入 package.json,而 npm install 会按其中的版本范围自动下载并安装依赖。关于 npm 的规模和“几乎什么都有”的使用直觉,主要依据 Node.js 官方文档 An introduction to the npm package manager,其中明确称 npm 是 Node 的 standard package manager,并提到 registry 已拥有数百万包,是 “the biggest single language code repository on Earth”。关于 Isaac Z. Schlueter 对 npm 生态中“重复造轮子”问题的回看,主要依据 Increment 采访中“npm really prevents ever reinventing the wheel”那段回答,他明确承认 npm 上仍有大量重叠模块,但强调希望让重新造轮子与复用已有轮子都变得更高效。正文将这些线索综合概括为“小包文化是 npm 把复用成本压得极低之后最自然的文化结果”,属于对工具摩擦、生态激励和社区审美共同作用的综合判断。


关键人物速览

  • Isaac Z. Schlueternpm 的发起者。理解为什么 npm 生态会把“模块流通”做得如此低摩擦,绕不开他。
  • Laurie Voss:npm 早期核心推动者之一。理解 npm 如何把 registry 文化和社区叙事一起推大,绕不开他。
  • Sindre Sorhus:小而专注模块文化最有代表性的实践者之一。理解“小包并不天然等于坏设计”这条辩护线在社区里为什么长期成立,绕不开他。

参考与延伸阅读

  1. An introduction to the npm package manager | Node.js Docs
    https://nodejs.org/learn/getting-started/an-introduction-to-the-npm-package-manager

  2. npm | npm Docs
    https://docs.npmjs.com/cli/v8/commands/npm

  3. package.json | npm Docs
    https://docs.npmjs.com/cli/v11/configuring-npm/package-json/

  4. Specifying dependencies and devDependencies in a package.json file | npm Docs
    https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file/

  5. Packages and modules | npm Docs
    https://docs.npmjs.com/packages-and-modules/

  6. Interview with Isaac Z. Schlueter, CEO of npm - Increment
    https://increment.com/development/interview-with-isaac-z-schlueter-ceo-of-npm/

  7. npm About
    https://www.npmjs.com/about

  8. About npm | npm Docs
    https://docs.npmjs.com/about-npm

  9. What are your thoughts on the left-pad npm case?
    https://github.com/sindresorhus/ama/issues/367


下篇预告:left-pad 为什么会成为行业惊魂夜,因为它第一次逼整个行业承认,一个看起来几乎微不足道的小包,真的可能挂在整个生态的关键路径上。