【总结】从4个方面重新梳理webpack

我们始终被外在的东西所折磨,但只要活在当下,专注此时此刻做的每一件事情,把它做到极致,则就是那滴蜜糖。抓住这一点,我们就不再焦虑。

背景

本文内容来自于小册webpack5核心原理与应用实现, 总结一下对自己有帮助的点,这本小册总体写的不错,比较大的收获有:

  1. 对webpack的配置文件的理解
  2. js、css、图片 常用loader配置以及比较
  3. webpack优化方案
  4. webpack原理(后续单独总结)

写文章不易,写了几天,辛苦大家多多支持和指正~

一、重新理解webpack配置项

由于webpack的配置项众多,之前在脑海里都是一个一个的点,根本没有串起来,而且也记不住,但是换一种理解方法的话,就容易理解了。如果我们按照webpack的构建流程可以将配置项划分为两类来理解:

  1. 流程类:主要是干预打包编译规则,直接影响打包结果。
  2. 工具类:打包流程外,提供工程化的配置项。

1. 流程类

根据webpack编译流程来看构建项,这样的话就明白为什么会有这个配置项了。所以先来回顾下webpack的构建流程:

webpack编译流程

  • 输入:webpack从文件系统的读取入口
  • 模块递归处理:读取分析entry模块,调用Loader转译Module内容,并转换为AST,找到模块依赖,递归处理依赖,直到所有模块都处理完毕。
  • 后处理:所有模块处理完成后,根据Entry配置将模块封装进不同的Chunk对象,经过模块合并、注入运行时、产物优化,将模块按照chunk合并成最终产物,写入文件系统。

按照以上流程划分配置项有:

总结起来:

  1. webpack首先根据输入配置entry找到项目入口文件
  2. 按照模块配置相关的内容(module/resolve/externals)配置的规则处理模块,包括对各种类型文件利用loader转换为js类型、依赖分析等。
  3. 最后根据后处理相关的配置(optimization/target)合并模块资源、注入运行时依赖、优化产物等。

比较重要的点:

  1. resolve:告诉webpack怎么去找模块,这一步是webpack常用的优化点(考点),
    • 可以通过设置resolve的extensions缩小文件后缀的遍历路径,
    • 或者resolve的modules设置import的路径,一般设置为当前目录下的node_modules
  2. module:可以理解为loader配置,js、css、img等的loader配置
  3. optimization:splitChunk的分包配置等在这里,属于chunk生成阶段使用的。

2. 工具类配置

用于解决某一工程类问题,可以划分为以下三类:

  1. 开发效率类:watch、devtool、devServer
  2. 性能优化类:cache、performance
  3. 日志类:stats、infrastructureLogging

二、 js、css、img常用loader梳理

这块的话js比较熟悉,css插件不少,有时候记不住,需要梳理下,还有img的,也容易迷糊😓。

注意:loader执行顺序从右到左。

1. js loader

js的loader最常用就是babel-loader,ts的话是ts-loader或者,还有一般会加eslint插件,eslint插件一般会加扩展包。不多说了,直接脑图总结:

配置示例

js 复制代码
const path = require('path')
const ESLintPlugin = require('eslint-webpack-plugin')

module.exports = {
  entry: './src/index.ts',
  mode: 'development',
  devtool: false,
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: {
          loader: 'babel-loader',
          options: { presets: ['@babel/preset-typescript'] }
        }
      }
    ]
  },
  plugins: [new ESLintPlugin({ extensions: ['.js', '.ts'] })]
}

2. css

webpack不能处理css,所以需要借助css-loader插件将它转换为js格式使它可以处理。然后再通过style-loader或者mini-css-extract-plugin插入到页面中。

  • css-loader:将css翻译为module.exports = "${css}"的js代码
  • 插入页面,以下二选一:
    • style-loader创建一个style标签插入
    • mini-css-extract-plugin抽离成单独的css文件,通过link标签的方式插入到页面中

除去以上基础的,还有css预处理器以及post-css:

  • less-loader、sass-loader,预处理器定义了一套css之上的超集,如Ts与js的关系。
  • post-css:增强原生css的能力,没有定义一门新的语言,而是将css解析为ast结构,并传入postcss插件做处理,具体功能都由插件实现,就像babel和js。

脑图总结:

这里要注意的就是loader的顺序,实际处理顺序是从右到左,所以css的执行的流程:

less-loader=> post-css=> css-loader => style-loader,

style-loader一定要在最后面css-loader后面,因为被解析为js后才能插入页面。

示例demo如下:

js 复制代码
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          "style-loader", 
          {
            loader: "css-loader",            
            options: {
              importLoaders: 1
            }
          }, 
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                // 添加 autoprefixer 插件
                plugins: [require("autoprefixer")],
              },
            },
          },
          "less-loader"
        ],
      },
    ],
  }
};

3. 图片处理

这一块webpack4和5有区别了,因为相关的loader,webpack5基本内置了处理流程,等同于将img、文本等也升级为webpack的一等公民了。

图片分两部分,一部分是加载图片时使用的loader,一个是图片相关优化的loader。

图片加载相关
loader 作用 webpack5
file-loader 图片引用转换为url并生成相应图片 type = "asset/resource"'
url-loader 对于小于阈值 limit 的图像直接转化为 base64 编码,大于阈值用file-loader转换,看起来是file-loader升级版 type = "asset/inline"
raw-loader 不做任何转移,只是简单将文件内容复制到产物中,适用于svg type = "asset/source"

以上loader不仅可以处理图片,还可以加载任意类型的多媒体和文本文件。

图片优化相关
优化方法 loader 说明
图像压缩 image-webpack-loader 组件 底层依赖于 imagemin 及一系列的图像优化工具
响应式图片 responsive-loader 生成不同尺寸的图片
雪碧图 webpack-spritesmith 插件 目前使用场景减少,iconfont和base64图片处理了小图标相关的功能

脑图总结

示例代码

js 复制代码
  module: {
    rules: [{
      test: /\.jsx?$/,
      exclude: /node_modules/,
      use: [{
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env'],
            ['@babel/preset-react']
          ]
        }
      }]
    }, {
      test: /\.less$/i,
      use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
    }, {
      test: /\.svg$/i,
      use: ['svg-url-loader']
    }, {
      test: /\.(png|jpg)$/,
      type: "asset/resource",
      use: [{
        loader: 'image-webpack-loader',

        options: {
          disable: true,
          mozjpeg: {
            quality: 10
          },
        }
      }]
    }],
  }

三、webpack优化方案

我们通常遇到性能分析问题,都要按照以下三个步骤来走:

  1. 度量
  2. 分析卡点
  3. 解决问题

性能度量工具

那有哪些性能度量工具呢?

以上这些工具可以用于webpack打包结果分析。

为什么会慢

为什么webpack在大型项目中性能不佳?

  • 一方面是js的单线程架构,无法并行执行,不像rust、go是支持多线程的,这也就是esbuild为啥优于webpack,因为语言层面就区别挺大。
  • 另一方面从webpack的流程看,它要完成大量的文件读写、代码转译等操作。

性能优化方法

关于性能优化,有没有觉得如果不实际操作,直接看那些优化方法,在面试的时候总是容易忘?为了让自己梳理清楚,可以将webpack的常用优化方法分为两个方向:

方面 目的 方法
优化构建速度 提升开发效率 1. 持久化缓存 2. 并行构建 3. 缩小编译范围 4. 使用最新版本的webpack5、node
优化运行时性能 提升网页运行时性能 1. 动态加载,减少首屏资源加载量 2. 代码压缩 3.tree-shaking、scope hoisting减少应用体积

一、构建速度优化

1. 持久化缓存

这个就是空间换时间的思路了。因为webpack5自带了持久化缓存的功能,所以可以从webpack5和4区分来看。

  • webpack5的持久化缓存能够把首次构建结果保存到文件系统,下次构建就可以跳过解析、连接、编译,直接用上次编译好的对象。

  • webpack4可以借助插件实现类似的功能。例如cache-loaderhard-source-webpack-plugin,这一点可以通过对vue-cli的内置的配置看出来,执行命令vue inspect > output.js或者npx vue-cli-service inspect > output.js来导出cli的默认配置,可以发现里面出现了2次cache-loader的影子。分别是在vue-loaderbabel-loader前面,看吧,原来我们一直在使用cache-loader。

脑图总结:

2. 并行构建

这一条是从单线程限制的方面优化,也是借助插件来实现。例如:

  • HappyPack:多进程方式运行资源加载(Loader)逻辑,webpack4可以使用;
  • Thread-loader:Webpack 官方出品,同样以多进程方式运行资源加载逻辑,推荐webpack5使用;
  • Parallel-Webpack:多进程方式运行多个 Webpack 构建实例;
  • TerserWebpackPlugin:支持多进程方式执行代码压缩、uglify 功能。
3. 缩小编译范围
  • 优化loader的执行范围
  • 模块解析,配置 resolve 控制资源搜索范围;
  • 针对 npm 包设置 module.noParse 跳过编译步骤;
4. 使用最新版本的webpack5、node

二、运行时性能优化

1. 动态加载,减少首屏资源加载量

SplitChunksPlugin 是 Webpack 4 之后内置实现的最新分包方案。常用分包方案

  • node_modules设置分组
  • 业务代码
    • 运行时代码单独抽离chunk
    • 设置common分组,通过minChunk设置使用多次的抽离为chunk
2. 代码压缩
  • terser-webpack-plugin:用于压缩 JS 代码的插件;
  • css-minimizer-webpack-plugin:用于压缩 CSS 代码的插件;
  • html-minifier-terser:用于压缩 HTML 代码的插件。

插件都支持 include/test/exclude 配置项,用于控制压缩功能的应用范围;也都支持 minify 配置项,用于切换压缩器,借助这个配置我们可以使用性能更佳的工具,如 ESBuild 执行压缩。

3. 利用tree-shaking、scope hoisting减少应用体积

四、webpack5新特性

既然是webpack5,就把webpack5的升级点简单总结下吧。

相关推荐
ywf12152 小时前
前端的dist包放到后端springboot项目下一起打包
前端·spring boot·后端
恋猫de小郭2 小时前
2026,Android Compose 终于支持 Hot Reload 了,但是收费
android·前端·flutter
hpoenixf8 小时前
2026 年前端面试问什么
前端·面试
还是大剑师兰特8 小时前
Vue3 中的 defineExpose 完全指南
前端·javascript·vue.js
泯泷8 小时前
阶段一:从 0 看懂 JSVMP 架构,先在脑子里搭出一台最小 JSVM
前端·javascript·架构
mengchanmian9 小时前
前端node常用配置
前端
华洛9 小时前
利好打工人,openclaw不是企业提效工具,而是个人助理
前端·javascript·产品经理
xkxnq9 小时前
第六阶段:Vue生态高级整合与优化(第93天)Element Plus进阶:自定义主题(变量覆盖)+ 全局配置与组件按需加载优化
前端·javascript·vue.js
A黄俊辉A10 小时前
vue css中 :global的使用
前端·javascript·vue.js
小码哥_常10 小时前
被EdgeToEdge适配折磨疯了,谁懂!
前端