Webpack: 深入理解图像加载原理与最佳实践

news2024/11/22 11:03:38

概述

图形图像资源是当代 Web 应用的最常用、实惠的内容、装饰元素之一,但在 Webpack 出现之前对图像资源的处理复杂度特别高,需要借助一系列工具(甚至 Photoshop)完成压缩、雪碧图、hash、部署等操作。

而在 Webpack 中,图像以及其它多媒体资源都被提升为一等公民 —— 能够像引用普通 JavaScript 模块一样通过 import/require 语句导入资源模块,这种开发模式允许我们将图像相关的处理合入统一的心智模型中,提升开发效率。

本文将集中介绍 Webpack 体系下处理图像资源的常见方法,包括:

  • 如何使用适当的 Loader 处理图像资源;
  • 如何借助 Loader 或插件实现图像优化,包括压缩、雪碧图、响应式图片。

在 Webpack 4 中导入图像

原生 Webpack 4 只能处理标准 JavaScript 模块,因此需要借助 Loader —— 例如 file-loaderurl-loaderraw-loader 等完成图像加载操作,实践中我们通常需要按资源类型选择适当加载器,简单介绍:

  • file-loader:将图像引用转换为 url 语句并生成相应图片文件,例如使用如下配置:

    // webpack.config.js
    module.exports = {
      // ...
      module: {
        rules: [{
          test: /\.(png|jpg)$/,
          use: ['file-loader']
        }],
      },
    };
    

经过 file-loader 处理后,原始图片会被重命名并复制到产物文件夹,同时在代码中插入图片 URL 地址,形如:

请添加图片描述

  • url-loader:有两种表现,对于小于阈值 limit 的图像直接转化为 base64 编码;大于阈值的图像则调用 file-loader 进行加载,例如如下配置:

    module.exports = {
      // ...
      module: {
        rules: [{
          test: /\.(png|jpg)$/,
          use: [{
            loader: 'url-loader',
            options: {
              limit: 1024
            }
          }]
        }],
      },
    };
    

经过 url-loader 处理后,小于 limit 参数即 1024B 的图片会被转译为 Base64 编码,如:
请添加图片描述

对于超过 limit 值的图片则直接调用 file-loader 完成加载。

url-loader 同样适用于大多数图片格式,且能将许多细小的图片直接内嵌进产物中,减少页面运行时需要发出的网络请求数,在 HTTP 1.1 及之前版本中能带来正向的性能收益。

  • raw-loader:不做任何转译,只是简单将文件内容复制到产物中,适用于 SVG 场景,例如如下配置:

    // webpack.config.js
    module.exports = {
      // ...
      module: {
        rules: [
          {
            test: /\.svg$/i,
            use: ['raw-loader'],
          },
        ],
      },
    };
    

经过 raw-loader 处理后,SVG 资源会被直接复制成字符串形式:
请添加图片描述

提示:除 raw-loader 外,我们还可以使用如下 Loader 加载 SVG 资源:

  • svg-inline-loader:能够自动删除 SVG 图片中与显式无关的各种原信息,达到压缩效果;
  • svg-url-loader:以 DataURL 方式导入 SVG 图片,相比于 Base64 更节省空间;
  • react-svg-loader:导入 SVG 图片并自动转化为 React 组件形态,效果类似 @svgr/webpack;
  • vue-svg-loader:导入 SVG 图片并自动转化为 Vue 组件形态。

在 Webpack 5 中导入图像

上述 file-loaderurl-loaderraw-loader 都并不局限于处理图片,它们还可以被用于加载任意类型的多媒体或文本文件,使用频率极高,几乎已经成为标配组件!所以 Webpack5 直接内置了这些能力,开箱即可使用。

用法上,原本需要安装、导入 Loader,Webpack5 之后只需要通过 module.rules.type 属性指定资源类型即可,对比来看:

  • file-loader 对标到 type = "asset/resource"'
// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [{
      test: /\.(png|jpg)$/,
-     use: ['file-loader']
+     type: 'asset/resource'
    }],
  },
};

提示:默认情况下,asset/resource 生成的文件会以 [hash][ext][query] 方式重命名,可以通过 output.assetModuleFilename 属性控制。

  • url-loader 对标到 type = "asset"type = "asset/inline"

    module.exports = {
      // ...
      module: {
        rules: [{
          test: /\.(png|jpg)$/,
    -     use: [{
    -       loader: 'url-loader',
    -       options: {
    -         limit: 1024
    -       }
    -     }]
    +     type: "asset",
    +     parser: {
    +        dataUrlCondition: {
    +          maxSize: 1024 // 1kb
    +        }
    +     }
        }],
      },
    };
    

其中,module.rules.parser.dataUrlCondition 用于限定文件大小阈值,对标 url-loaderlimit 属性。

  • raw-loader 对标到 type = "asset/source"

    module.exports = {
      // ...
      module: {
        rules: [
          {
            test: /\.svg$/i,
    -       use: ['raw-loader']
    +       type: "asset/source"
          },
        ],
      },
    };
    

补充一下,引入 module.rules.type 并不只是为了取代 Loader 那么简单,更重要的目的是在 JavaScript Module 之外增加对其它资源 —— Asset Module 的原生支持,让 Webpack 有机会介入这些多媒体资源的解析、生成过程,从而有机会实现更标准、高效的资源处理模型。

目前 module.rules.type 已经支持 JSON、WebAssemsbly、二进制、文本等资源类型,相信在下一个 Webpack 版本中,必然会基于 Asset Module 实现更丰富的资源处理能力。

图像优化:压缩

前面介绍的 Loader 与 Asset Modules 都只是解决了图像资源加载 —— 也就是让 Webpack 能够理解、处理图像资源,现实中我们还需要为 Web 页面中的图片做各种优化,提升页面性能,常见的优化方法包括:

  • 图像压缩:减少网络上需要传输的流量;
  • 雪碧图:减少 HTTP 请求次数;
  • 响应式图片:根据客户端设备情况下发适当分辨率的图片,有助于减少网络流量;
  • CDN:减少客户端到服务器之间的物理链路长度,提升传输效率;
  • 等等。

这其中有不少可以在开发、构建阶段借助 Webpack 搭建自动优化工作流,例如:图像压缩。

在 Webpack 生态中有不少优秀的图像压缩组件,包括:image-webpack-loader、imagemin-webpack-plugin、image-minimizer-webpack-plugin 等,以我的使用经验来看,image-webpack-loader 组件功能齐全且用法简单,更推荐使用。基本用法首先安装依赖:

yarn add -D image-webpack-loader

之后配置 Loader:

module.exports = {
  // ...
  module: {
    rules: [{
      test: /\.(gif|png|jpe?g|svg)$/i,
      // type 属性适用于 Webpack5,旧版本可使用 file-loader
      type: "asset/resource",
      use: [{
        loader: 'image-webpack-loader',
        options: {
          // jpeg 压缩配置
          mozjpeg: {
            quality: 80
          },
        }
      }]
    }],
  },
};

image-webpack-loader 底层依赖于 imagemin 及一系列的图像优化工具:

  • mozjpeg:用于压缩 JPG(JPEG) 图片;
  • optipng:用于压缩 PNG 图片;
  • pngquant:同样用于压缩 PNG 图片;
  • svgo:用于压缩 SVG 图片;
  • gifsicle:用于压缩 Gif 图;
  • webp:用于将 JPG/PNG 图压缩并转化为 WebP 图片格式。

基本上已经覆盖 Web 页面常用的图片格式,具体用法可点击上述链接查阅,此处不再赘述。最后补充一点,图像压缩是一种非常耗时的操作,建议只在生产环境下开启:

module.exports = {
  // ...
  module: {
    rules: [{
      // ...
      use: [{
        loader: 'image-webpack-loader',
        options: {
+         disable: process.env.NODE_ENV === 'development'
          // ...
        }
      }]
    }],
  },
};

图像优化:雪碧图

在 HTTP 2 之前,HTTP 请求-响应是一种性能低下的通讯模型,即使是为了请求一个非常少的数据,也可能需要完整经历:建立 TCP 连接 => 发送 HTTP 请求 => 服务端处理 => 返回响应数据整个过程,加之 HTTP 协议的队首阻塞、浏览器并发请求数限制等原因,迫使我们必须尽量减少 HTTP 请求数以提升网络通讯效率。

例如,我们可以将许多细小的图片合并成一张大图 —— 从而将复数次请求合并为一次请求,之后配合 CSS 的 background-position 控制图片的可视区域,这种技术被称作“雪碧图”。在 Webpack 中,我们可以使用 webpack-spritesmith 插件自动实现雪碧图效果,首先安装依赖:

yarn add -D webpack-spritesmith

之后添加配置:

module.exports = {
  // ...
  resolve: {
    modules: ["node_modules", "assets"]
  },
  plugins: [
    new SpritesmithPlugin({
      // 需要
      src: {
        cwd: path.resolve(__dirname, 'src/icons'),
        glob: '*.png'
      },
      target: {
        image: path.resolve(__dirname, 'src/assets/sprite.png'),
        css: path.resolve(__dirname, 'src/assets/sprite.less')
      }
    })
  ]
};

关键在于,webpack-spritesmith 插件会将 src.cwd 目录内所有匹配 src.glob 规则的图片合并成一张大图并保存到 target.image 指定的文件路径,同时生成兼容 SASS/LESS/Stylus 预处理器的 mixins 代码,例如对于下面文件结构:

load-img
├─ src
│  ├─ icons
│  │  ├─ grunt.png
│  │  ├─ gulp-js.png
│  │  └─ webpack.png
│  └─ index.js
├─ webpack.config.js
└─ package.json

按照上述配置运行后会生成如下产物:

src/assets/sprite.pngsrc/assets/sprite.less
img/* ... */ .sprite(@sprite) { .sprite-image(@sprite); .sprite-position(@sprite); .sprite-width(@sprite); .sprite-height(@sprite); } /* ... */

之后,我们就可以使用 sprite.less 提供的 .sprite mixin 添加背景图:

@import (less) "./assets/sprite.less";

#main {
    // 参数为原始图片文件名
    .sprite(@webpack);
}

提示:雪碧图曾经是一种使用广泛的性能优化技术,但 HTTP2 实现 TCP 多路复用之后,雪碧图的优化效果已经微乎其微 —— 甚至是反优化,可以预见随 HTTP2 普及率的提升,未来雪碧图的必要性会越来越低,因此建议读者们了解作用与基本原理即可,不必深究。

图像优化:响应式图片

移动互联网时代,我们需要面对的客户端设备越来越多样复杂,分辨率从 PC 到平板电脑再到移动终端跨度极大:

image.png

这会带来一个问题:同一张图片(主要是位图)在不同设备中,如果显示尺寸大于原始尺寸,最终效果会有明显颗粒感;而如果显示尺寸小于原始尺寸,又会造成带宽浪费。理想的解决方案是为不同设备提供不同的分辨率、不同尺寸的图片 —— 也就是所谓的响应式图片。

Webpack 中有不少能够自动生成响应式图片的组件,例如: resize-image-loader、html-loader-srcset、responsive-loader 等,以 responsive-loader 为例,首先安装依赖:

yarn add -D responsive-loader sharp

之后,修改配置:

module.exports = {
  // ...
  module: {
    rules: [{
      test: /\.(png|jpg)$/,
      oneOf: [{
        type: "javascript/auto",
        resourceQuery: /sizes?/,
        use: [{
          loader: "responsive-loader",
          options: {
            adapter: require("responsive-loader/sharp"),
          },
        }],
      }, {
        type: "asset/resource",
      }],
    }],
  }
};

注意,实践中我们通常没必要对项目里所有图片都施加响应式特性,因此这里使用 resourceQuery 过滤出带 size/sizes 参数的图片引用,使用方法:

// 引用图片,并设置响应式参数
import responsiveImage from './webpack.jpg?sizes[]=300,sizes[]=600,sizes[]=1024';

const Picture = function () {
  return (
    <img
      srcSet={responsiveImage.srcSet}
      src={responsiveImage.src}
      sizes="(min-width: 1024px) 1024px, 100vw"
      loading="lazy"
    />
  );
};

上例的引用参数 './webpack.jpg?sizes[]=300,sizes[]=600,sizes[]=1024'; 最终将生成宽度分别为 300、600、1024 三张图片,之后设置 img 标签的 srcset 属性即可实现图片响应式功能。

此外,我们还能简单地通过 size 参数精确控制不同条件下的图像尺寸:

.foo {
    background: url("./webpack.jpg?size=1024");
}

@media (max-width: 480px) {
    .foo {
        background: url("./webpack.jpg?size=300");
    }
}

提示:除本文提及的基本功能外,responsive-loader 还提供了许多用于控制产物、压缩比等特性的配置项,有需要的同学可到 官网 展开阅读。

总结

在 Webpack 5 之前,我们需要使用 file-loaderurl-loader 等 Loader 加载图片或其它多媒体资源文件,这些加载器各有侧重点,需要根据实际场景择优选用;而 Webpack 5 之后引入了 Asset Module 模型,自此我们只需要设置适当的 module.rules.type 配置即可,不需要为多媒体资源专门引入 Loader。

在加载之外,我们还可以借助 Webpack 生态一系列组件低成本实现图像压缩、雪碧图、响应式图片等优化措施

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1878306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端Web开发HTML5+CSS3+移动web视频教程 Day3 CSS 第1天

P29 - P43 从此开始进入 CSS 的学习。前面都是 HTML 的学习。 CSS 的作用&#xff1a;美化。 HTML 只是规定了网页内容有哪些&#xff0c;在网页中显示的位置默认是从上到下显示&#xff0c;还带有默认效果&#xff0c;比如超链接有颜色有下划线&#xff0c;无序列表有小圆点…

【算法训练记录——Day37】

Day37——贪心Ⅴ 1.leetcode_56合并区间 1.leetcode_56合并区间 思路&#xff1a;排序&#xff0c;如果重叠&#xff0c;更新right 为max(right, curVal), 不重叠就加入res,需要单独考虑最后一次&#xff0c;因为每次都是在下一次遍历开始时判断是否加入res&#xff0c;因此 当…

平衡二叉搜索树/AVL树

VAL树的特性 左右子树高度差的绝对值不超过1。&#xff08;即左右子树高度差取值为-1&#xff0c;0&#xff0c;1&#xff09;且左右子树均为VAL树右子树的值大于左子树的值 在搜索二叉树中我们提及了搜索二叉树的退化问题。 当有序&#xff08;升序或降序&#xff09;地插入…

人工智能类SCI,1区TOP,3个月可录!

今天给大家推荐一本人工智能类SCIE领域的SCI&#xff0c;此期刊为我处目前合作的重点期刊&#xff01;影响因子7.0-8.0之间&#xff0c;JCR1区&#xff0c;中科院2/1区&#xff08;TOP&#xff09;&#xff0c;最重要的是审稿周期较短&#xff0c;对急投的学者较为友好&#xf…

MATLAB-振动问题:两自由度耦合系统自由振动

一、基本理论 二、MATLAB实现 以下是两自由度耦合系统自由振动质量块振动过程动画显示的MATLAB程序。 clear; clc; close allx0 1; D1 40; D12 8; D2 D1; m1 1; omega0 sqrt(D1/m1); k1 D12 / D1; k2 D12 / D2; k sqrt(k1 * k2); omegazh omega0 * sqrt(1 k); omeg…

SpringBoot使用Spark的DataFrame API

什么是Spark&#xff1f; Apache Spark是一个开源的分布式计算系统&#xff0c;它提供了一个快速和通用的集群计算平台。Spark 能够处理大规模数据&#xff0c;支持多种编程语言&#xff0c;如Scala、Java和Python&#xff0c;并且具有多种高级功能&#xff0c;包括SQL查询、机…

基于51单片机的密码锁Proteus仿真

文章目录 一、密码锁1.题目要求2.思路3.仿真图3.1 未仿真时3.2 初始界面3.3 输入密码界面3.4 开锁成功界面3.5 修改密码界面3.6 输入密码错误界面 4.仿真程序4.1 矩阵按键4.2 液晶显示16024.3 存储模块2402 二、总结 一、密码锁 1.题目要求 以51单片机为核心&#xff0c;设计…

【原创实现 设计模式】Spring+策略+模版+工厂模式去掉if-else,实现开闭原则,优雅扩展

1 定义与优点 1.1 定义 策略模式&#xff08;Strategy Pattern&#xff09;属于对象的⾏为模式。他主要是用于针对同一个抽象行为&#xff0c;在程序运行时根据客户端不同的参数或者上下文&#xff0c;动态的选择不同的具体实现方式&#xff0c;即类的行为可以在运行时更改。…

C++:静态断言内存对齐

静态断言 C中的断言assert (1)直接参考&#xff1a;https://www.cnblogs.com/lvchaoshun/p/7816288.html (2)C的assert是运行时检测发现错误&#xff0c;而不是编译时 (3)C在编译时错误用#error来输出C静态断言 (1)C引入static_assert(表达式, “提示字符串”)来实现编译时的静…

[数据集][目标检测]婴儿状态睡觉哭泣检测数据集VOC+YOLO格式7109张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;7109 标注数量(xml文件个数)&#xff1a;7109 标注数量(txt文件个数)&#xff1a;7109 标注…

【MySQL基础篇】SQL指令:DQL及DCL

1、DQL DQL - 介绍 DQL英文全称是Data Query Language(数据查询语言)&#xff0c;数据查询语言&#xff0c;用来查询数据表中的记录。&#xff08;在MySQL中应用是最为广泛的&#xff09; 查询关键字&#xff1a;SELECT DQL - 语法 SELECT 字段列表 FROM 表名列表 WHER…

代码随想录算法训练营第四十七天| 188.买卖股票的最佳时机IV ,309.最佳买卖股票时机含冷冻期 ,714.买卖股票的最佳时机含手续费

188. 买卖股票的最佳时机 IV - 力扣&#xff08;LeetCode&#xff09; class Solution {public int maxProfit(int k, int[] prices) {int[][] dp new int[prices.length][2*k];for(int i0;i<2*k;i){if(i%2 0){dp[0][i] -prices[0];}else{dp[0][i] 0;} }for(int i1;i…

LeetCode题练习与总结:环形链表Ⅱ--142

一、题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测…

C语言 | Leetcode C语言题解之第206题反转链表

题目&#xff1a; 题解&#xff1a; struct ListNode* reverseList(struct ListNode* head) {if (head NULL || head->next NULL) {return head;}struct ListNode* newHead reverseList(head->next);head->next->next head;head->next NULL;return newHea…

Camera Raw:增强

Camera Raw 中的增强 Enhance命令基于 AI 技术提升图像的质量&#xff0c;可用于降噪、生成清晰的细节以及提高图像的分辨率。 ◆ ◆ ◆ 主要用途 1、高 ISO 图像降噪 勾选“去杂色” Denoise&#xff0c;可轻松消除使用高 ISO 设置或在低光环境下拍摄的照片中的噪点。 可以对…

Nettyの粘包、半包问题框架解决方案自定义协议

1、Netty框架是如何解决粘包、半包问题 关于粘包&#xff0c;半包问题&#xff0c;在前面几篇中都有提及&#xff0c;我们简单的复习一下。 粘包指的是客户端发出的多条消息&#xff0c;被服务端当做一条进行接收。半包指的是客户端发出一条完整的消息&#xff0c;在传输的过程…

鸿蒙项目实战-月木学途:1.编写首页,包括搜索栏、轮播图、宫格

效果展示 搜索栏制作 相关知识回顾 输入框组件TextInput 单行输入框类型.type(InputType.Normal)//基本输入框.type(InputType.Password)//密码.type(InputType.Email)//邮箱.type(InputType.Number)//数字.type(InputType.PhoneNumber)//电话号.type(InputType.Normal).type…

boston房价预测--机器学习Boston数据分析

1.采用散点图绘制相关性。 #分析波士顿房价数据集的数据相关性 import numpy as np import pandas as pd import matplotlib.pyplot as plt #载入数据集 data_url "http://lib.stat.cmu.edu/datasets/boston" raw_df pd.read_csv(data_url, sep"\s", …

Java数据结构6-栈与队列

1. 栈(Stack) 1.1 概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则 压栈…

第11章 规划过程组(11.5创建WBS)

第11章 规划过程组&#xff08;一&#xff09;11.5创建WBS&#xff0c;在第三版教材第380~383页&#xff1b; 文字图片音频方式 视频22 第一个知识点&#xff1a;主要输入 1、项目管理计划 范围管理计划 定义了如何根据项目范围说明书创建WBS2、项目文件 项目范围说明…