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

概述

图形图像资源是当代 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-loadertype: "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 (<imgsrcSet={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.mzph.cn/bicheng/37868.shtml

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

相关文章

基于MongoDB的电影影评分析

项目源码及资料 项目介绍 1、从豆瓣网爬取Top10的电影数据 爬取网址: https://movie.douban.com/top250 1.1 爬取Top10的影视信息 mv_data [] i 0 for x in soup.select(.item):i 1mv_name re.search(>([^<])<, str(x.select(.info > .hd > a > .tit…

【动态规划】2306. 公司命名

本文涉及知识点 动态规划汇总 LeetCode 2306. 公司命名 给你一个字符串数组 ideas 表示在公司命名过程中使用的名字列表。公司命名流程如下&#xff1a; 从 ideas 中选择 2 个 不同 名字&#xff0c;称为 ideaA 和 ideaB 。 交换 ideaA 和 ideaB 的首字母。 如果得到的两个新…

Python 面试【★★★★★】

欢迎莅临我的博客 &#x1f49d;&#x1f49d;&#x1f49d;&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

大数据可视化实验(七):Python数据可视化

目录 一、实验目的... 1 二、实验环境... 1 三、实验内容... 1 1&#xff09;绘制带颜色的柱状图。.. 1 2&#xff09;绘制堆叠柱状图。.. 3 3&#xff09;绘制数学函数曲线图。.. 4 4&#xff09;使用seaborn绘制组合图形。... 5 5&#xff09;使用Boken绘制多个三角形…

63.ThreadLocal原理

JDK8中ThreadLocal的设计 每个Thread维护一个ThreadLocalMap,这个map的key是ThreadLocal实例本身,value才是真正要存储的值Object。 Thread -> ThreadLocalMap -> <ThreadLocal实例对象, 变量副本> jdk早期设计 ThreadLocal -> ThreadLocalMap -> <T…

vmware安装debian11

安装vmware16 下载镜像 https://repo.huaweicloud.com/debian-cd/ https://repo.huaweicloud.com/debian-cd/11.7.0/amd64/iso-dvd/ 安装 安装完成之后重启&#xff0c;输入账号密码进入&#xff0c;安装ssh服务器即可使用

ManicTime(屏幕时间统计工具) 专业版值得购买吗

ManicTime 是 Windows 平台上&#xff0c;一款支持跟踪、标记用户在每个软件上所花时间的工具&#xff0c;它能自动归类生成时间使用报表&#xff0c;帮助用户分析及改善工作效率。 ManicTime 不仅会在后台记录、统计所有窗口的使用时间&#xff0c;还能自动截图存档到本地&a…

设计模式 - 原型模式,就该这样学!

目录 开始 为什么要引入原型模式 原型模式概述 原型模式代码实现&#xff08;浅拷贝&#xff09; 浅拷贝和深拷贝的区别 原型模式代码实现&#xff08;深拷贝&#xff09; 方式一&#xff1a;直接 copy 方式二&#xff1a;序列化和反序列化&#xff08;推荐&#xff09…

LeetCode 1527, 54,114

目录 1527. 患某种疾病的患者题目链接表要求知识点思路代码 54. 螺旋矩阵题目链接标签思路代码 114. 二叉树展开为链表题目链接标签前序遍历思路代码 前驱思路代码 1527. 患某种疾病的患者 题目链接 1527. 患某种疾病的患者 表 表Patients的字段为patient_id、patient_name…

C++ | Leetcode C++题解之第205题同构字符串

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isIsomorphic(string s, string t) {unordered_map<char, char> s2t;unordered_map<char, char> t2s;int len s.length();for (int i 0; i < len; i) {char x s[i], y t[i];if ((s2t.coun…

Webpack: 7 款常用的性能分析工具

概述 Webpack 最大的优势在于它的功能非常强大、全面&#xff0c;加之繁荣活跃的组件生态&#xff0c;已经足够应对几乎所有 Web 构建需求&#xff0c;包括&#xff1a;SPA、MPA、SSR、桌面应用、Node 程序、WebAssemsbly、PWA、微前端等等&#xff0c;所以即使在近几年工程化…

Python | Leetcode Python题解之第205题同构字符串

题目&#xff1a; 题解&#xff1a; class Solution:def isIsomorphic(self, s: str, t: str) -> bool:dicts Counter(s)dictt Counter(t) if list(dicts.values()) ! list(dictt.values()):return Falsefor i in range(len(s)):inds list(dicts.keys()).index(s…

C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏

前言 今天大姚给大家分享一款由C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏&#xff1a;SeeSharpSnake。 项目特点 该仓库中的项目文件和脚本可以用多种不同的配置构建相同的游戏&#xff0c;每个配置生成的输出大小也不同。 项目源码运行 F5 运行 SeeSharpSnake项目&…

E4A视频APP源码电视盒子Coolpoint酷点电视4.5版后端苹果cms

电视盒子酷点TV版4.5影视APP源码后端对接苹果CMS&#xff0c;此版带会员功能,对接的是 如意验证1.71版苹果cms后端APP 电视TV4.5版,会员功能带注册邀请,绑定邮箱,邮箱找回密码,修改新密码,卡密充值,签到,积分兑换会员&#xff1b; 自带10个解析线路,有电视直播功能,首页滚动公…

Java教程之IO模式精讲,NIO+BIO

第一章 BIO、NIO、AIO介绍 背景 在java的软件设计开发中&#xff0c;通信架构是不可避免的&#xff0c;我们在进行不同系统或者不同进程之间的数据交互&#xff0c;或 者在高并发下的通信场景下都需要用到网络通信相关的技术&#xff0c;对于一些经验丰富的程序员来说&#x…

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

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

十六进制计数器

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请用Verilog设计十六进制递增计数器电路&#xff0c;每个时钟周期递增1。 电路的接口如下图所示。Q[3:0]中&#xff0c;Q[3]是高位。 接口电路图如下&#xff1a; 输入描述&#xff1a; input …

操作系统期末复习考题三(不挂科系列)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文☀️☀️☀️三、总结&#x1f353;&#x1f353;&#x1f353; 一、前言&#x1f680;&#x1f680;&am…

java基于ssm+jsp 房屋租赁系统

1 管理员登录 管理员输入个人的用户名、密码登录系统&#xff0c;这时候系统的数据库就会在进行查找相关的信息&#xff0c;如果我们输入的用户名、密码不正确&#xff0c;数据库就会提示出错误的信息提示&#xff0c;同时会提示管理员重新输入自己的用户名、密码&#xff0c;…

了解WPF控件:OpenFileDialog常用属性与用法(十六)

掌握WPF控件&#xff1a;熟练OpenFileDialog常用属性&#xff08;十六&#xff09; OpenFileDialog控件在WPF中用于需要用户指定文件路径&#xff0c;为用户提供了一个直观且易用的界面来浏览和选择本地文件系统中的文件。例如&#xff0c;当用户需要打开一个已存在的文本文件…