📦 Browserify

一句话定性

它做了一件石破天惊的事:Node.jsrequire() 跑在浏览器里。第一次让前端能像后端一样用 CommonJS 模块组织代码,直接复用 npm 上的海量包。它是模块打包思想的开创者,也是 Webpack 的精神前驱。


一、它是什么 & 出现的时代

Browserify(2011,作者 substack)是第一个真正流行的 JS 模块打包器(bundler)

它的口号是:“browser-side require() — the node.js way”。在它出现之前,浏览器里没有任何模块系统;Browserify 把 Node.js 的 CommonJS 规范(require / module.exports)整套搬到了浏览器。

时代背景:Node.js(2009)和 npm 已经在后端建立了繁荣的模块生态,而前端还停留在 <script> 标签 + 全局变量。Browserify 看到了这个巨大的落差。


二、为什么会出现(解决上一代什么痛点)

浏览器没有模块系统

  1. 全局变量污染:所有 <script> 共享同一个全局作用域,命名冲突是日常。
  2. 依赖顺序靠手排:<script> 标签的先后顺序决定加载顺序,排错就报错。
  3. 无法复用 npm 生态:后端有几十万个 npm 包,前端却用不了——因为它们用 require(),而浏览器不认。
  4. 任务流工具不解决这个问题:Gulp 能合并文件,但它们不理解 require() 的依赖关系。

核心洞察:为什么前端不能复用后端那套已经验证过的模块系统? 这是典型的第一性原理思考——既然 CommonJS 在 Node 里跑得好好的,把它带到浏览器就行了。


三、核心机制 & 为什么流行

Browserify 做的事,本质是静态分析 + 打包:

入口 main.js
   │  扫描 require('./a')、require('lodash')
   ▼
构建依赖图(dependency graph)
   │  递归解析每个模块的 require
   ▼
把所有模块包进一个 bundle.js
   │  用一个小型 require 运行时(模块注册表 + 工厂函数)模拟 CommonJS
   ▼
浏览器只需 <script src="bundle.js">

它在打包产物里塞了一个极简的模块加载运行时:每个模块被包成一个函数,require(id) 就是从模块注册表里查表、执行、缓存 exports。

为什么流行:

  • 第一次让前端能 npm install lodash 然后直接 require('lodash') 用——打通了前后端的模块生态
  • 配合 transform(如 babelify)能在打包时做转译。
  • 配合 Gulp 流式管道用,契合当时的工具习惯。

四、带来的新问题 / 副作用

思想超前,但能力有限

  1. 只懂 CommonJS,只懂 JS:它处理的是 JS 模块,CSS/图片这类资源不在它的世界里。
  2. 没有 code splitting:全打成一个大 bundle,无法按需加载。
  3. 没有 HMR:改代码要整体重新打包刷新。
  4. 配置和扩展能力弱:transform 机制远不如后来的 loader/plugin 灵活。
  5. CommonJS 是动态的:require() 可以写在任何地方、可以是变量,导致无法做 tree-shaking(静态分析不出哪些代码没用到)。

五、为什么会衰落 / 现状

Webpack 把 Browserify 的核心思想——“构建依赖图 + 打成一个 bundle”——推广到了所有资源类型。Webpack 说:不只是 JS,CSS、图片、字体、一切皆模块;不只是 CommonJS,AMD、ES Module 都支持;还有 code splitting、HMR、loader/plugin 生态。

一句话:Browserify 证明了”打包”这条路是对的,Webpack 把这条路修成了高速公路。 当 Webpack 的能力全面超越后,Browserify 就完成了历史使命,逐渐退场。如今(2026)基本只作为历史标本存在。


六、对后续技术的影响(因果链)

Node.js + npm 在后端建立模块生态
        │
        ▼
Browserify:"把 require() 带到浏览器"
        │  ① 证明"依赖图 + 打包"范式可行
        │  ② 打通前后端模块生态(前端能用 npm 包了)
        │  ③ 但只懂 CommonJS、只懂 JS、无 code splitting
        │
        ▼
[[Webpack]] 继承并大幅扩展:
        ├──► 一切皆模块(CSS/图片也是模块)
        ├──► loader / plugin 生态
        ├──► code splitting + HMR
        └──► 多模块格式(CJS/AMD/ESM)
        │
        ▼
打包器统治十年(详见 [[为什么Webpack统治了十年]])
        │
        ▼
后来 [[ES-Modules]] 原生化 ──► [[Vite]] 重新思考"还要不要打包"

CommonJS 与 tree-shaking 的伏笔

Browserify 依赖的 CommonJS 是动态的,无法静态分析,因此天生不支持 tree-shaking。这个限制后来由 ES-Modules静态结构解决,也成了 Rollup 推广 tree-shaking 的前提。


🔗 相关:前端工程化演进史 | Node.js | Webpack | Rollup | Grunt-Gulp-任务流时代 | ES-Modules