Webpack 5 核心机制详解与打包性能优化实践

在这里插入图片描述

作者简介:水煮白菜王,一个web开发工程师
文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧和知识归纳总结✍。
感谢支持

目录

    • Webpack 5 相较于 Webpack 4 的主要改进
    • 安装
    • 生命周期
      • Compiler Hooks
      • use hooks
    • webpack中的loader(转换器)
      • 工作原理
      • 常用loader
      • 自定义loader
    • webpack中的plugins(插件)
      • 工作原理
      • 自定义plugins
    • 打包过程
      • 加速webpack打包速度和减小打包体积的优化
      • webpack配置
      • webpack配置拆分
        • webpack.config.common.js文件公共环境配置
        • webpack.config.dev.js文件开发环境配置 npx webpack -c ./webpack.config.dev.js
        • webpack.config.prod.js文件生产环境配置 npx webpack -c ./webpack.config.prod.js
        • webpack.config.js 运行:webpack -c ./webpack.config.js --env development
      • 封装webpack自定义插件
    • 如果你觉得这篇文章对你有帮助,请点赞 、收藏 并关注我!

Webpack 5 相较于 Webpack 4 的主要改进

  1. 性能改进:webpack5在构建速度和打包体积方面进行了一些优化。它引入了持久缓存,可以减少构建时间。
    此外,webpack5还引入了更好的树摇(tree shaking)算法,可以更好地优化打包体积。
  2. 模块联邦(Module Federation)新增特性:这是webpack5中最重要的新功能之一。模块联邦允许不同的应用程序共享模块,从而实现更好的代码复用和拆分。这对于构建大型的微服务架构非常有用。
new ModuleFederationPlugin({
  name: 'myApp',
  filename: 'remoteEntry.js',
  remotes: {},
  exposes: {
    './Button': './src/Button',
  },
  shared: { react: { singleton: true } },
});
  1. 支持WebAssembly:webpack5对WebAssembly提供了更好的支持。它可以直接导入和导出WebAssembly模块,并且可以通过配置进行优化。
  2. 缓存策略增强:webpack5引入了更好的缓存策略,可以更好地利用浏览器缓存。这可以减少用户在更新应用程序时需要下载的文件数量。
  3. Tree Shaking 改进:webpack5引入了更好的Tree Shaking算法,可以更好地识别和删除未使用的代码。这可以进一步减少打包体积。
  4. 改进的持久缓存:webpack5引入了更好的持久缓存策略,可以更好地利用缓存。这可以减少构建时间。
特性 Webpack 5 改进
性能改进 Webpack 5 在构建速度和打包体积方面进行了优化。引入了持久缓存机制,显著减少重复构建时间。
模块联邦(Module Federation) 引入模块联邦功能,允许不同应用之间共享模块,提升代码复用能力,适用于微服务架构和微前端项目。
WebAssembly 支持增强 原生支持 WebAssembly 模块的导入与导出,无需额外 loader,支持异步加载、Tree Shaking 和 Code Splitting。
缓存策略增强 引入更智能的浏览器缓存策略(如 deterministic ID 算法),提升长期缓存利用率,减少用户更新时的资源下载量。
Tree Shaking 改进 使用更高级的 Tree Shaking 算法,支持导出级(export-level)和嵌套级的未使用代码识别与删除,进一步减小打包体积。
持久缓存改进 引入基于文件系统的持久化缓存(cache: { type: 'filesystem' }),大幅提升开发阶段的增量构建速度。

其中最显著的变化是 webpack5 引入了持久化缓存机制,使得构建速度大幅提升。此外,webpack5 改进了长期缓存策略,支持更好的 Tree Shaking 和代码分割功能

安装

npm init -y     // 初始化package.json
npm install webpack webpack-cli --save-dev

npx webpack --watch     // 监听文件修改
npx webpack-dev-server  // 以server的方式启动项目,不会打包物理文件,而是输出到内存

生命周期

Compiler Hooks

beforeRun:在webpack开始运行之前调用,执行全局初始化逻辑,例如异步加载配置、插件依赖项等。

run:在webpack开始运行时调用,可以在此做一些全局处理 ,一些初始化操作。

beforeCompile:在webpack开始编译之前调用,修改编译参数、注入额外上下文。

compile:在webpack开始编译时调用,初始化与本次编译相关的状态。

make:在webpack开始构建编译器时调用,启动模块解析、构建等操作,可在此阶段添加自定义入口点或资源。

afterCompile:在webpack完成编译之后调用,获取完整的模块依赖图,进行最终分析或优化。

emit:在webpack生成最终的资源之前调用,添加、修改或删除最终输出的资源(如生成额外文件)。

afterEmit:在webpack生成最终的资源之后调用,做一些清理工作或触发后续流程。

done:在webpack完成构建之后调用,清理临时资源、输出构建信息、发送通知。

Hook 名称 触发时机 使用场景
beforeRun 在 Compiler 开始运行前触发(如执行 webpack() 可用于初始化插件或设置运行时配置
run 在 Compiler 开始运行时触发(异步) 类似入口点,可以在此做一些全局处理 ,一些初始化操作
beforeCompile 在编译开始前触发 准备编译所需的数据或资源
compile 在编译开始时触发 初始化编译过程,执行一些初始化操作,例如创建 Compilation 实例
thisCompilation 在 Compilation 创建之前触发 用于监听后续的 Compilation 生命周期
compilation 在 Compilation 被创建后触发 插件可在此接入 Compilation 生命周期
make 在模块解析开始时触发 可以添加/修改模块依赖关系
afterCompile 在编译完成后触发 对编译结果做最后调整或校验
emit 在生成最终输出资源之前触发 可以修改输出内容,如添加额外文件
afterEmit 在输出资源之后触发 清理 emit 阶段使用的临时数据
done 整个构建流程完成之后触发 执行清理工作或输出构建耗时信息
failed 构建失败时触发 处理异常、记录错误日志

use hooks

module.exports = {
  // ...
  plugins: [
    {
      apply: (compiler) => {
        compiler.hooks.beforeRun.tap('MyPlugin', () => {
          console.log('Before run');
        });

        compiler.hooks.done.tap('MyPlugin', () => {
          console.log('Build done');
        });
      }
    }
  ]
};

//在这个示例中,我们定义了一个自定义插件,并利用beforeRun和done两个生命周期钩子函数。在这些钩子函数中,我们可以实现自定义行为,如输出日志信息。

webpack中的loader(转换器)

工作原理

webpack loader 在 webpack 构建过程中的生命周期中的工作主要分为以下几个阶段:

  • 解析阶段:webpack 会根据配置文件中的入口文件,递归解析所有的依赖模块。在这个阶段,webpack 会根据文件的后缀名来确定使用哪个 loader 来处理该文件。

  • 编译阶段:在这个阶段,webpack 会将解析后的模块转换成 AST(抽象语法树),并且根据配置文件中的规则,将模块中的代码进行转换和处理。
    这个阶段是 loader 的主要工作阶段,loader 可以对模块进行各种处理,例如转换代码、添加额外的功能等。

  • 生成阶段:在这个阶段,webpack 会根据处理后的模块生成最终的输出文件。输出文件的格式和路径可以通过配置文件进行配置。

在这些阶段中,loader 主要在编译阶段发挥作用。loader 可以通过导出一个函数来定义自己的处理逻辑,这个函数接收一个参数,即待处理的模块的源代码,然后返回处理后的代码。

开始编译阶段
获取模块源代码
创建抽象语法树AST
是否有匹配的loader?
调用loader处理函数
直接使用原始代码
loader处理转换
返回处理后的代码
更新AST
分析模块依赖
递归处理依赖模块
生成最终代码
结束编译阶段

常用loader

以下是一些常用的webpack loader:

Loader 描述
babel-loader 用于将ES6+的JavaScript代码转换为ES5代码,以便在旧版本浏览器中运行。
css-loader 用于解析CSS文件,并处理其中的import和url()等语法。
style-loader 将解析后的CSS代码以