Understanding Webpack 5 Compilation Process and Tapable Plugin System
This article explains the internal compilation mechanism of webpack 5.11.0, covering Tapable’s event system, the Compiler and Compilation lifecycle, module creation, parsing, resolving, rule compilation, generators, and tree‑shaking, with practical code examples illustrating how plugins and hooks operate.
The Dali Front‑end Infrastructure team investigated webpack’s compilation speed and decided to dissect the [email protected] source to reveal its compilation principles.
Understanding Tapable
Webpack’s core is built on Tapable, a flexible event‑emitter that registers callbacks (hooks) which can be executed synchronously, asynchronously in series, or in parallel. It supports execution modes such as basic, waterfall, bail, and loop, allowing plugins to intervene at many stages.
class Person {
constructor(name) {
this.name = name;
this.hooks = {
eat: new SyncHook(),
};
}
eat() {
this.hooks.eat.call();
}
}
const zhangsan = new Person('zhangsan');
zhangsan.hooks.eat.tap('FitnessPlugin', () => console.log('自觉点!!!'));
zhangsan.eat(); // triggers the hook and logs "自觉点!!!"With Tapable understood, you can write a FitnessPlugin that reacts when a Person eats.
Compiler Instantiation
The Compiler object is created from the merged webpack.config.js and CLI arguments. Its main responsibilities are:
Choose watchRun or run based on the watch flag.
Create a new Compilation instance.
Delegate the actual build work to the Compilation .
Emit the final assets.
During its run, the Compiler fires many lifecycle hooks (e.g., compile , make , emit ) that plugins can tap into.
Compilation Lifecycle
A Compilation represents a single build pass: loading entry modules, resolving dependencies, parsing ASTs, creating chunks, and emitting assets. Key stages include:
module creation – NormalModuleFactory creates module objects, resolves dependencies, and parses source code.
parsing – the appropriate Parser (e.g., JavascriptParser ) walks the AST and triggers Tapable hooks for each syntax node.
generation – Generator objects (e.g., JavascriptGenerator ) transform the processed AST back into JavaScript code, replacing require with __webpack_require__ and injecting runtime helpers.
NormalModuleFactory
The factory performs three core actions:
create – instantiate a NormalModule after resolution.
resolve – use enhanced‑resolve to locate the module file, applying alias, extensions, and condition fields.
parse – obtain a parser based on file type (e.g., JavascriptParser for .js/.ts ) and generate an AST.
Example of a rule compiled by RuleSetCompiler :
{
conditions: [
{ property: 'resource', fn: v => /\.tsx?$/.test(v) }
],
effects: [
{ type: 'type', value: 'javascript/auto' },
{ type: 'use', value: { loader: 'ts-loader', options: { transpileOnly: true } } }
]
}Parsers
Webpack ships with several built‑in parsers:
JavascriptParser – handles javascript/auto , javascript/esm , and javascript/dynamic source types.
JsonParser – parses JSON files.
WebAssemblyParser – parses WebAssembly modules.
AssetParser – deals with asset modules (inline, resource, source).
For JavaScript, javascript/auto first tries to parse as an ES module and falls back to a script if that fails.
Generators
Generators mirror parsers. The JavascriptGenerator rewrites import/require statements, injects __webpack_require__ , and attaches runtime helpers needed for module execution.
Tree Shaking
Tree shaking removes unused exports. In development mode, webpack adds comments like /* unused harmony export square */ but does not drop the code. In production, plugins such as HarmonyExportDependencyPlugin and FlagDependencyUsagePlugin mark unused exports, and a minifier (e.g., Terser) eliminates the dead code.
Conclusion
Webpack’s architecture is highly modular: Tapable provides the hook system, the Compiler orchestrates the build, the Compilation manages modules, and parsers/generators transform source code. Understanding these components empowers developers to write custom plugins, optimise builds, and grasp advanced features like tree shaking.
ByteDance Dali Intelligent Technology Team
Technical practice sharing from the ByteDance Dali Intelligent Technology 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.