📦 Browserify
一句话定性
一、它是什么 & 出现的时代
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 看到了这个巨大的落差。
二、为什么会出现(解决上一代什么痛点)
浏览器没有模块系统
- 全局变量污染:所有
<script>共享同一个全局作用域,命名冲突是日常。- 依赖顺序靠手排:
<script>标签的先后顺序决定加载顺序,排错就报错。- 无法复用 npm 生态:后端有几十万个 npm 包,前端却用不了——因为它们用
require(),而浏览器不认。- 任务流工具不解决这个问题: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 流式管道用,契合当时的工具习惯。
四、带来的新问题 / 副作用
思想超前,但能力有限
- 只懂 CommonJS,只懂 JS:它处理的是 JS 模块,CSS/图片这类资源不在它的世界里。
- 没有 code splitting:全打成一个大 bundle,无法按需加载。
- 没有 HMR:改代码要整体重新打包刷新。
- 配置和扩展能力弱:transform 机制远不如后来的 loader/plugin 灵活。
- 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