Skip to content

Webpack 原理与实战

Webpack 核心概念

Webpack 是一个现代 JavaScript 应用程序的静态模块打包器。当 Webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

核心概念

  • Entry(入口):指示 Webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。
  • Output(输出):告诉 Webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件。
  • Loader:让 Webpack 能够去处理那些非 JavaScript 文件(Webpack 自身只理解 JavaScript)。
  • Plugin:用于执行范围更广的任务,包括:打包优化、资源管理和注入环境变量。
  • Mode(模式):通过选择 developmentproductionnone 之中的一个,来设置 mode 参数,你可以启用 Webpack 内置在相应环境下的优化。

Webpack 构建流程

  1. 初始化参数:从配置文件和 Shell 语句中读取并合并参数
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译
  3. 确定入口:根据配置中的 entry 找出所有的入口文件
  4. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
  5. 完成模块编译:在经过第 4 步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
  6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表
  7. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

Loader 原理

Loader 本质上是一个函数,接受源文件作为参数,返回转换的结果。

js
module.exports = function (source) {
  // source 是源文件内容
  // 对 source 进行处理
  return modifiedSource
}

多个 Loader 串行执行,顺序为从右到左(或从下到上)。

Plugin 原理

Plugin 是 Webpack 的支柱功能。Webpack 自身也是构建于你在 Webpack 配置中用到的相同的插件系统之上。

Plugin 可以访问 Webpack 提供的各种 API,通过监听生命周期事件来执行自定义逻辑。

Webpack 优化策略

构建性能优化

  • 使用 include/exclude 减少 Loader 搜索范围
  • 使用 cache-loader 或 Webpack 5 内置的持久化缓存
  • 使用 thread-loaderparallel-webpack 进行多进程打包
  • 合理使用 DllPluginDllReferencePlugin

产物优化

  • Tree Shaking:消除 dead code
  • Code Splitting:代码分割,按需加载
  • 压缩代码:TerserPlugin、CssMinimizerPlugin
  • 提取公共代码:SplitChunksPlugin

Webpack 5 新特性

  • 持久化缓存:默认开启,大幅提升二次构建速度
  • Module Federation:模块联邦,实现跨应用共享模块
  • Tree Shaking 增强:支持嵌套模块和 CommonJS 的部分 Tree Shaking
  • Asset Modules:内置资源模块,替代 file-loader、url-loader、raw-loader

面试高频问题

1. Webpack 的热更新原理是什么?

Webpack HMR 的核心流程:

  1. Webpack Compile:编译阶段,生成 hash 值并创建更新清单
  2. HMR Runtime:浏览器端运行时,通过 WebSocket 与服务器建立连接
  3. 文件更新:文件变更后,Webpack 重新编译,推送更新通知
  4. 模块替换:浏览器端接收到更新,下载更新模块并替换旧模块

2. Loader 和 Plugin 的区别?

  • Loader:文件加载器,用于对模块的源代码进行转换。它是一个转换器,将 A 文件进行编译形成 B 文件。
  • Plugin:插件,用于扩展 Webpack 的功能。它是在 Webpack 生命周期中的特定时刻执行特定的任务。

3. 如何提高 Webpack 的构建速度?

  • 升级 Webpack 版本(Webpack 5 持久化缓存)
  • 多进程/多实例构建
  • 缩小 Loader 作用范围
  • 合理使用 resolve 配置
  • 使用 DllPlugin 预编译资源
  • 开启缓存