Rollup
Rollup是面向JavaScript的模块打包工具,由Rich Harris开发,可将多个小型模块文件编译合并为库或应用程序所需的较大产物[1]。它以标准化的ES模块为设计中心,而非CommonJS等早期模块方案,并通过静态分析剔除未被使用的代码,从而生成体积较小的输出[2]。这一特性使其长期被用于打包可发布的JavaScript库,构建工具Vite的生产构建也以它为基础[3]。
定义
Rollup是一个用于JavaScript的模块打包工具,作用是把分散的小块代码编译成更大、更复杂的整体,例如一个库或一个应用[1]。它不同于以CommonJS、AMD为中心的传统打包器,而是把ES模块的import与export语法当作构建依赖图的起点[2]。除打包外,它承担的另一项核心工作是静态分析并排除未被实际使用的代码[4]。
Rollup既可以作为命令行工具调用,也可以在其JavaScript API中通过编程方式使用,配置文件通常命名为rollup.config.js、rollup.config.mjs或rollup.config.cjs[5]。开发者可以指定一个或多个入口文件,并把对等依赖标记为外部依赖,从而按需产出多种模块格式的产物[5]。
原理
Rollup从配置的入口文件开始,先解析文件得到抽象语法树,再据此发现其中包含哪些import声明,然后定位、加载并解析被引用的模块,如此循环直到没有新的模块进入依赖图[6]。依赖图建立后,它会判断哪些导出真正被程序使用,只保留会影响程序可观察行为的代码[4]。
与传统打包器把每个模块包进函数、运行时再用require取出执行的方式不同,Rollup倾向于把多个模块的代码合并进同一作用域,这种做法常被称为作用域提升(scope hoisting),可减少包装带来的体积与启动开销[6]。基于这一机制,产物结构较为扁平,也更接近手写代码的形态[7]。
剔除未使用代码的过程称为摇树优化(tree shaking)。由于ES模块的导入导出关系在编译阶段即可静态确定,工具能够较可靠地识别未被引用的导出;相比之下,CommonJS的require是运行期调用,难以做到同等精度的分析[7]。Rollup的文档将这一能力描述为一次针对被导入ES模块的静态分析,并认为它比仅对打包结果做压缩更能有效去掉死代码[1]。
flowchart LR
A[入口文件] --> B[解析为AST]
B --> C[识别import声明]
C --> D[加载并解析依赖模块]
D --> C
D --> E[建立依赖图]
E --> F[标记被使用的导出]
F --> G[摇树优化/剔除未用代码]
G --> H[作用域提升与合并]
H --> I[按格式生成产物]
发展历程
Rollup由Rich Harris开发。他在从事Ractive项目时,发现代码库拆分得越细、构建产物反而越大,先写了名为Esperanto的打包器,后又因难以在其上实现摇树优化而放弃,转而重新开发了Rollup[6]。npm仓库记录显示,rollup 0.1.0于2015年5月14日发布,被描述为“下一代ES6模块打包器”;同年5月17日发布的0.2.0被视为首个可实际投入使用的版本[5]。
2015年12月21日,Harris撰文阐述Rollup的摇树优化思路,即只把打包产物真正需要的代码包含进来;webpack的相关指南也把摇树优化这一名称与概念在JavaScript社区的流行归功于Rollup[5]。此后项目按主要版本持续演进:1.0.0于2018年12月28日发布,2.0.0于2020年3月6日发布,3.0.0于2022年10月11日发布,4.0.0于2023年10月5日发布[5]。
在与CommonJS包并存的过渡期,Rollup还参与了npm包发布约定的形成:其维基页面记录了package.json中的module字段,用以指向可供Rollup、webpack等工具直接读取的ES模块源码,并与CommonJS工具使用的main字段相区别[5]。围绕核心包,Rollup组织维护着一批官方插件,覆盖Node包解析、CommonJS转换、JSON加载、TypeScript编译以及与其他资源类型的集成[5]。
应用
Rollup的主要用途是打包JavaScript库。库作者希望源码以模块形式组织,同时又要发布能被旧运行环境和各类包使用者消费的产物,Rollup的格式控制与摇树优化正好满足这一需求,因此在可复用库的构建中较为常见[5]。它一次构建即可输出ES模块、CommonJS、UMD、AMD、IIFE、SystemJS等多种格式,其中UMD与IIFE格式在打包时需要提供包名[1]。
在工具链层面,构建工具Vite在开发阶段借助原生ES模块,而在生产构建时调用Rollup生成优化后的产物[3]。Vite的插件接口也在很大程度上沿用并扩展了Rollup的插件规范,这使得Rollup的插件生态可以为其复用[7]。此外,Rollup支持通过插件导入已有的CommonJS模块,并可编译为UMD或CommonJS格式,再借助package.json中的字段指向编译后的版本[1]。
Rollup还支持代码分割,可配合动态导入与手动分包生成按需加载的多个chunk,并内置监听模式用于增量重建[4]。在配置上,external用于把某些模块排除出产物,output中的file、format、name等字段决定输出位置、格式与全局变量名[8]。
局限
Rollup原生以ES模块为输入,对CommonJS依赖的原生支持有限,通常需要node-resolve与commonjs等插件配合,配置复杂度随之上升,且部分边缘情况未必能被完全覆盖[9]。由于摇树优化依赖ES模块的静态语义,混合代码库中的CommonJS依赖难以被有效剔除[9]。
Rollup本身只是打包器,不内置开发服务器与热模块替换,开发阶段的体验需要Vite等上层工具补齐;多数场景下也需要显式配置,而非开箱即用[9]。有观点指出,其构建速度不及以Rust或Go实现的新一代工具,对大型项目而言构建耗时可能偏长[10]。
摇树优化本身也有边界。当导入路径无法静态确定,例如使用变量拼接的动态import,静态分析便无法判断需要哪些模块,相关代码可能被整体排除或无法剔除[11]。此外,带有副作用的模块需要显式声明,否则打包器会趋于保守而将多余代码一并保留[12]。
参见
参考资料
- Rollup [引用日期2026-10-29]
- Rollup - tree: bb25b06b675aee0a4a0c0a698fb2567952f863f6 [引用日期2026-10-29]
- Rollup | CenterConsulting [引用日期2026-10-29]
- Rollup: ES Module Bundler for JavaScript Libraries [引用日期2026-10-29]
- rollup [引用日期2026-10-29]
- survivejs.com 上的网页 [引用日期2026-10-29]
- Rollup(打包工具) [引用日期2026-10-29]
- 深度解析 Rollup 配置与 Vite 生产构建流程 [引用日期2026-10-29]
- Rollup vs Vite: Build Tool Comparison (2026) — Zaira Labs [引用日期2026-10-29]
- Rollup [引用日期2026-10-29]
- github.com 上的网页 [引用日期2026-10-29]
- Tree Shaking - Monkey Vision Kennisbank [引用日期2026-10-29]