How Rollup Packs JavaScript: Inside the Build Process and AST Analysis
This article explains Rollup’s core principles, compares it with Webpack, introduces prerequisite concepts such as magic‑string, AST and scope chains, and walks through the complete build workflow—including parsing, dependency analysis, statement expansion, and final code generation—using concrete code examples and diagrams.
1. Rollup Overview
Official site: https://rollupjs.org/guide/en/
What is Rollup
Rollup is a modular bundler that merges JavaScript files without requiring manual ordering or worrying about variable name collisions. It essentially concatenates modules and handles scope conflicts internally.
Comparison with Webpack
Webpack is a powerful bundler that handles many asset types, but its output often contains redundant code, especially for pure JavaScript libraries. For library projects without additional static assets, Rollup produces smaller bundles with faster execution and better readability.
Rollup supports ES6 modules and tree‑shaking, but lacks Webpack features such as code‑splitting and hot module replacement, making it more suitable for library builds than full applications.
Simple Summary
Use Webpack for applications; use Rollup for libraries (React, Vue, Angular also support Rollup).
2. Prerequisite Knowledge
Before diving into Rollup’s build principle, understand the following concepts.
magic-string
magic-string is a utility library written by the Rollup author for convenient string manipulation.
<code>var MagicString = require('magic-string')
var magicString = new MagicString('export var name = "zhangsan"')
// string operations examples...
</code>AST
JavaScript parsing produces an Abstract Syntax Tree (AST) that represents code structure, enabling precise analysis and transformation.
<code>// main.js
import { a } from './a'
console.log(a)
</code>Example AST (truncated):
<code>{ "type":"Program", "body":[ ... ] }</code>AST Workflow
Parse → Transform → Generate.
acorn
acorn is a JavaScript parser that converts source code into an AST. See https://astexplorer.net/ for exploration.
Scope / Scope Chain
Scope defines variable visibility; the scope chain links the current execution context to its ancestors, ensuring ordered variable access.
3. How Rollup Works
Rollup receives an entry file (e.g., index.js), parses it with Acorn to obtain an AST, then recursively resolves all imported modules until no new modules appear.
Example entry
<code>import foo from './foo.js';
</code>Rollup loads, parses, and analyzes ./foo.js, repeating the process for nested imports. Each file becomes a module with its own AST.
During analysis, Rollup examines each AST node to determine whether it references a variable defined locally or in an external module, building a dependency graph.
Demo code
<code>// index.js
import { foo } from "./foo";
foo();
var city = 'hangzhou';
function test() { console.log('test'); }
console.log(test());
</code> <code>// foo.js
import { bar } from "./bar";
export function foo() { console.log('foo'); }
</code> <code>// bar.js
export function bar() { console.log('bar'); }
</code> <code>// rollup.config.js
export default {
input: './src/index.js',
output: {
file: './dist/bundle.js',
format: 'cjs',
name: 'bundleName'
}
};
</code>Running
npm run buildyields a bundle that contains only the necessary code, demonstrating scope hoisting and tree‑shaking.
Rollup Build Process Analysis
Source Structure
<code>bundle.js
external-module.js
module.js
rollup.js
ast/
analyse.js
Scope.js
walk.js
finalisers/
cjs.js
index.js
utils/
map-helpers.js
object.js
promise.js
replaceIdentifiers.js
</code>Build Steps
Instantiate a
Bundleand call
build.
Create a
Modulefor each file; parse its source with Acorn into an AST.
Collect import and export information, then analyse scopes to identify defined variables (
_defines) and external dependencies (
_dependsOn).
Expand statements by recursively including definitions of dependent variables, skipping import declarations.
Generate final code by concatenating the collected statements, removing
exportkeywords, and writing the result to the output file.
Key Functions
<code>function analyse(ast, magicString, module) { ... }</code>Builds a scope tree, marks variable definitions, and records external dependencies.
<code>expandAllStatements() { ... }</code>Recursively expands statements, ensuring each dependent definition appears once.
<code>generate() {
let magicString = new MagicString.Bundle();
this.statements.forEach(statement => {
const source = statement._source;
if (statement.type === 'ExportNamedDeclaration') {
source.remove(statement.start, statement.declaration.start);
}
magicString.addSource({ content: source, separator: '\n' });
});
return { code: magicString.toString() };
}
</code>Summary
Collect import/export variables.
Map dependencies and build a scope chain.
Gather all variable definitions.
Filter out import statements.
Remove unnecessary keywords.
During output, resolve imported variables recursively.
Generate final bundled code.
Conclusion
This walkthrough abstracts Rollup’s core mechanisms—parsing, dependency analysis, scope handling, and code generation—providing a foundation for deeper exploration of the actual source code.
References
https://zhuanlan.zhihu.com/p/372808332
https://github.com/xitu/gold-miner/blob/master/TODO/rollup-interview.md
https://blog.csdn.net/q411020382/article/details/108302906
WeDoctor Frontend Technology
Official WeDoctor Group frontend public account, sharing original tech articles, events, job postings, and occasional daily updates from our tech team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.