彻底拆解Webpack源码:深入理解webpack的打包原理
2024-01-04 10:04:11
当我们使用webpack去打包,最终都会产出一个或者多个可被浏览器直接加载执行的JavaScript文件,而这个过程往往会经历模块的解析、转换、合并以及优化等一系列流程。
接下来,我们就以webpack@5.72.1版本为例,一探webpack源码中模块化打包是如何实现的。
1. 源码文件结构解析
webpack源码位于webpack
目录下,总共包含537个文件和38个目录,其中最核心的文件是webpack.js
,它是webpack的核心入口文件。
webpack/
├── bin/
│ ├── webpack.js
│ └── webpack-cli.js
├── config/
│ └── webpack.config.js
├── node_modules/
├── package.json
├── README.md
├── scripts/
├── test/
├── types/
├── version.js
└── webpack.js
2. Webpack构建流程概述
webpack的构建流程可以概括为以下几个步骤:
- 初始化编译器 :在这一步中,webpack会创建一个compiler对象,compiler对象负责整个webpack的构建过程。
- 解析入口文件 :webpack会从入口文件开始,解析其依赖的模块,并构建一个模块依赖图。
- 应用规则 :webpack会根据配置的规则,对模块应用相应的处理,如转换、压缩等。
- 优化代码 :webpack会对代码进行优化,如代码压缩、代码分割等。
- 生成输出文件 :webpack会将处理后的代码生成输出文件,如JavaScript文件、CSS文件等。
3. 深入剖析Webpack源码
3.1 初始化编译器
// webpack.js
const Compiler = require('./Compiler');
const webpackOptions = configureWebpack(options);
const compiler = new Compiler(webpackOptions.context);
在webpack.js
文件中,首先会创建一个Compiler对象,Compiler对象负责整个webpack的构建过程。
3.2 解析入口文件
// Compiler.js
this.hooks.compilation.tap('Compiler', compilation => {
this.parentCompilation = compilation;
this.compilation = compilation;
this.applyPlugins('make', compilation);
this.processAssets();
this.processModules();
});
在Compiler
对象的make
钩子中,webpack会调用processModules
方法来解析入口文件。processModules
方法会从入口文件开始,解析其依赖的模块,并构建一个模块依赖图。
3.3 应用规则
// Compiler.js
this.hooks.thisCompilation.tap('Compiler', compilation => {
const handler = {
get(obj, prop) {
const { tap, callAsync } = compilation[prop];
return (...args) => {
return tap.call(compilation, ...args);
};
}
};
const plugins = this.plugins.slice();
const modules = this.modules.slice();
plugins.push(compilation.resolverFactory);
modules.push(compilation.dependencyTemplates);
modules.push(compilation.normalModuleFactory);
modules.push(compilation.contextModuleFactory);
const copiedCompilation = new Proxy(compilation, handler);
compilation.dependencyFactories = modules;
compilation.resolverFactory = plugins;
});
在Compiler
对象的thisCompilation
钩子中,webpack会将webpack的插件和模块添加到compilation对象中。compilation对象负责整个webpack的编译过程。
3.4 优化代码
// Compiler.js
this.hooks.compilation.tap('Compiler', compilation => {
compilation.hooks.afterOptimizeAssets.tapAsync('Compiler', (assets, callback) => {
this.applyPluginsAsync('after-optimize-assets', assets, callback);
});
});
在Compiler
对象的compilation
钩子中,webpack会调用afterOptimizeAssets
钩子来对代码进行优化。afterOptimizeAssets
钩子会调用webpack的插件来对代码进行优化,如代码压缩、代码分割等。
3.5 生成输出文件
// Compiler.js
this.hooks.compilation.tap('Compiler', compilation => {
compilation.hooks.afterEmit.tapAsync('Compiler', (compilation, callback) => {
this.emitAssets(compilation, callback);
});
});
在Compiler
对象的compilation
钩子中,webpack会调用afterEmit
钩子来生成输出文件。afterEmit
钩子会调用webpack的插件来生成输出文件,如JavaScript文件、CSS文件等。
4. 总结
以上就是webpack模块化打包的核心流程,希望对您有所帮助。