# webpack
# 运行流程
- 校验配置文件:读取命令行传入或者
webpack.config.js
文件,初始化本次构建的配置参数 - 生成
Compiler
对象:实例配置文件中的插件 - 确定入口:进入
entryOption
阶段,读取配置的Entries
,遍历所有的入口文件 - 编译模块:递归依赖使用
loader
对文件进行编译,再将编译好的文件生成AST,所有模块和依赖分析完成之后,执行compilation
的seal
对每个chunk进行整理、优化、封装__webpack_require__
- 输出资源
emit
:编译及转化都已经完成,包含了最终输出的资源。已经可以在compilation.assets
上拿到所需数据,包括即将输出的资源、代码块chunk等信息 - 输出完成
# webpack 插件
# 基本结构
plugins
是可以使用自身原型方法 apply
来实例化的对象。 apply
只会在初始化插件时执行一次。apply
传入 webpack compiler
的引用,来获取编译器回调。
class myPlugin{
// 在构造函数中获取用户给该插件传入的配置
constructor(options){
}
// Webpack 会调用 myPlugin 实例的 apply 方法给插件实例传入 compiler 对象
apply(compiler) {
// 在emit阶段插入钩子函数,用于特定时机处理额外的逻辑;
compiler.hooks.emit.tap('myPlugin', (compilation) => {
// 在功能流程完成后可以调用 webpack 提供的回调函数;
});
// 如果事件是异步的,会带两个参数,第二个参数为回调函数,在插件处理完任务时需要调用回调函数通知webpack,才会进入下一个处理流程。
compiler.plugin('emit',function(compilation, callback) {
// 支持处理逻辑
// 处理完毕后执行 callback 以通知 Webpack
// 如果不执行 callback,运行流程将会一直卡在这不往下执行
callback();
});
}
}
module.exports = HelloPlugin;
# 工作原理
- 读取配置时执行初始化实例
new myPlugin(options)
- 初始化
compiler
对象后调用[plugin].apply(compiler)
传入compiler
对象 - 插件实例获取到
compiler
对象后,就可以通过compiler.plugin(事件名称,回调函数)
监听到webpack
广播出来的事件,并且可以通过compiler
对象操作webpack
# 如何实现动态加载
webpack
本身是静态模板打包工具,它不会关心运行时到底发生了什么。
使用 import()
方法可以实现按需加载资源,在代码中所有使用 import([路径])
的模块都被抽离成一个单独的chunk。在客户端执行到这行代码的时候,会自动请求加载这个资源。路径被编译之后会处理成 webpack
命令执行目录的相对路径
# 打包优化
- 代码拆分:将应用程序拆分为多个小块,按需加载,减小初始加载的文件大小,提高页面加载速度。
- 延迟加载:按需加载某些模块或代码块,减少初始加载的文件大小,提高页面响应速度。
- 压缩和混淆代码:使用压缩工具对代码进行压缩和混淆,减小文件大小,提高加载速度。
- 优化文件大小:使用加载器和插件对不同类型的文件进行优化处理,如压缩CSS、压缩图片等。
- 缓存和长效缓存:生成带有哈希值的文件名,利用浏览器缓存机制,减少请求次数,提高再次访问时的加载速度。
- Tree Shaking:消除未使用的代码,减小文件大小,提高运行时的性能。
- 并行构建和缓存:使用多线程构建和缓存策略,加快构建速度,提高开发效率。
- 优化webpack配置:合理配置选项和插件,如设置合适的模式、调整模块解析规则等。
# webpack require是如何查找依赖的
- 解析路径:webpack会根据配置文件中的resolve属性来解析模块的路径,resolve属性包含了一系列的解析规则,例如指定了模块的根目录、模块的别名等。webpack会根据这些规则来解析模块的路径。
- 查找文件:一旦webpack解析了模块的路径,会尝试在指定的路径下查找相应的文件。
- 解析依赖:在查找文件的过程中,如果webpack发现文件中存在其他的依赖关系(例如通过import或者require引入其他模块),它会继续递归地解析这些依赖关系,直到找到所有的依赖为止。 🚧