webpack如何打包图片

330 阅读2分钟

前言

在项目开发中我们一般通过两种方式来使用图片

import LufeiImg from "./assets/image/lufei.jpg";
import "./assets/css/style.css";
​
// 引入图片的两种方式
// 方式一:以src元素的形式
const imgEl = document.createElement("img");
imgEl.src = LufeiImg;  // 设置src属性
document.body.append(imgEl);
​
// 方式二:以背景图片的形式
const bgDiv = document.createElement("div");
bgDiv.className = " bg-image";
document.body.append(bgDiv);

这个时候用webpack打包会报错,如图所示:

1679301986649.png

在解决如果打包图片的问题之前,我们先来了解一下webpack的资源模块

资源模块(asset module)

定义:资源模块是一种模块类型,它允许使用资源文件(图片,图标等)而无需使用配置额外的loader。

在webpack 5 之前,通常使用:

  • raw-loader 将文件导入字符串
  • url-loader 将文件作为data URL 内联到 bundle中
  • file-loader 将文件发送到输出目录

资源模块类型(asset module type),通过添加4种新的模块类型,来替换所有这些loader:

  • asset/resource 发送一个单独的文件并导出URL。

    • 之前通过使用file-loader实现
  • asset/inline 导出资源的源代码。

    • 之前通过使用raw-loader实现
  • asset/source 导出资源的源代码。

    • 之前通过使用 raw-loader 实现
  • asset 在导出一个 data URL 和发送一个单独的文件之间自由选择。

    • 之前通过使用 url-loader,并且配置资源体积限制实现
使用
resource资源
// webpack.config.js
    // ........
    module: {
        rules: [
          // .......
          {
            test: /.(png|jpe?g|svg|gif)$/,
            // 1.打包两张图片, 并且这两张图片有自己的地址, 将地址设置到img/bgi中
            // 缺点: 很多张图片加载会有很多次网络请求
            type: "asset/resource",
          },
        ],
     },
    // ........

输出结果:

1679305852149.png

inline资源
// webpack.config.js
    // ........
    module: {
        rules: [
          // .......
          {
            test: /.(png|jpe?g|svg|gif)$/,
            // 2.将图片进行base64的编码, 并且直接编码后的源码放到打包的js文件中
            // 缺点: 造成js文件非常大, 下载js文件本身消耗时间非常长, 造成js代码的下载和解析/执行时间过长
            type: "asset/inline"
          },
        ],
     },
    // ........

输出结果:

1679306190630.png

通用资源类型(asset)
// webpack.config.js
// ........
     module: {
        rules: [
          // .......
          {
            test: /.(png|jpe?g|svg|gif)$/,
            // 对于小于8kb的图片, 视为inline类型,可以进行base64编码
            // 对于大于8kb的图片, 单独的图片打包, 形成url地址, 单独的请求这个url图片
            type: "asset"
          },
        ],
     },
// ........

输出结果:

1679306338579.png

我们看到这里打包后的图片的名称有点杂乱,那么我们该如何自定义文件名称呢?

自定义文件名称
  1. 方式一:在output中添加assetModuleFilename属性;

1679307222198.png

1679307240358.png

  1. 方式二: 在rule中,添加一个generator属性,并且这是filename;

1679307284504.png

这里我们介绍几个常用的的placeholder:

  • [ext]  处理文件的扩展名 
  • [name]  处理文件的名称 
  • [contenthash]  使用MD4的散列函数处理,生成一个128位的hash值 

前面我们提到通用资源类型,会按默认条件,自动根据文件的大小,按resource和inline之间进行选择处理。

可以通过在配置的rule层级中,设置Rule.parser.dataUrlCondition.maxSize选项来修改此条件:

// webpack.config.js
// ........
     module: {
        rules: [
          // .......
          {
            test: /.(png|jpe?g|svg|gif)$/,
            // 对于小于8kb的图片, 视为inline类型,可以进行base64编码
            // 对于大于8kb的图片, 单独的图片打包, 形成url地址, 单独的请求这个url图片
            type: "asset",
            generator: {
                filename: "[name]_[contenthash:6][ext]"
            },
            parser: {
               dataUrlCondition: {
                   maxSize: 32 * 1024  // 32kb
               }
            }
          },
        ],
     },
// ........      

输出结果:

图片2以base64编码形式打包进bundle文件了

1679307897650.png

1679307985740.png

以上全部,谢谢