本文主要讨论基于webpack5+TypeScript的React项目(cra、craco底层本质都是使用webpack,所以同理)在2023年的今天是如何在项目中使用svg资源的。

首先,假定您已经完成基于webpack5+TypeScript的React项目的搭建工作(如果您不太清楚搭建的背景,可以参考这篇笔记:【个人笔记】2023年搭建基于webpack5与typescript的react项目 - 知乎 (zhihu.com))。

HTML中SVG经典用法

SVG:可缩放矢量图形 | MDN (mozilla.org)

要在一般的html中使用SVG,我们可以直接编写标签:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512" width="200" height="200">
<path d="M256 32C114.6 32 0 125.1 0 240c0 47.6 19.9 91.2 52.9 126.3C38 405.7 7 439.1 6.5 439.5c-6.6 7-8.4 17.2-4.6 26S14.4 480 24 480c61.5 0 110-25.7 139.1-46.3C192 442.8 223.2 448 256 448c141.4 0 256-93.1 256-208S397.4 32 256 32zm0 368c-26.7 0-53.1-4.1-78.4-12.1l-22.7-7.2-19.5 13.8c-14.3 10.1-33.9 21.4-57.5 29 7.3-12.1 14.4-25.7 19.9-40.2l10.6-28.1-20.6-21.8C69.7 314.1 48 282.2 48 240c0-88.2 93.3-160 208-160s208 71.8 208 160-93.3 160-208 160z"/>
</svg>
</div>
</body>
</html>

React编写SVG组件

在React中,React的jsx标签与HTML中的标签几乎是一一对应的,我们可以通过编写jsx来描述组件。所以不难想到,我们可以使用svg以及与其关联的jsx标签(譬如<path>、<g>等)来手写一个React的SVG组件:

export const IconComment = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
width="200"
height="200">
<path
d="M256 32C114.6 32 0 125.1 0 240c0 47.6 19.9 91.2 52.9 126.3C38 405.7 7 439.1 6.5 439.5c-6.6 7-8.4 17.2-4.6 26S14.4 480 24 480c61.5 0 110-25.7 139.1-46.3C192 442.8 223.2 448 256 448c141.4 0 256-93.1 256-208S397.4 32 256 32zm0 368c-26.7 0-53.1-4.1-78.4-12.1l-22.7-7.2-19.5 13.8c-14.3 10.1-33.9 21.4-57.5 29 7.3-12.1 14.4-25.7 19.9-40.2l10.6-28.1-20.6-21.8C69.7 314.1 48 282.2 48 240c0-88.2 93.3-160 208-160s208 71.8 208 160-93.3 160-208 160z"/>
</svg>
);
}

这个IconComment就是一个普通的React组件,编写完成后我们就可以在需要使用的地方引入了:

效果如下:

SVG文件在React中的使用方式

组件模式使用

上面我们讲到了如何编写一个svg组件,但一般来说,我们都会让设计出svg资源,然后存放在项目某个目录下并进行使用。我们当然可以把设计出的svg的内容复制到我们的项目中,以组件的方式来使用:

但是每次都需要拷贝一个又一个的组件当然是一件很麻烦的事情,在webpack中我们使用svg资源的时候,其实更希望如同图片资源一样以模块的形式引入(import或者是require)并使用,就像下面一样:

如果要达到上面的目的,我们首先需要弄清楚一件事情,那就是咱们"import"的"IconAbc"到底是个什么?通过上面的代码反推,我们很容易回答,IconAbc肯定需要是一个React组件(函数组件或类组件)。

了解webpack的同学都知道,webpack可以通过loader,来处理一个资源在导入的时候会变成什么。但现在在webpack配置中,我们先不添加任何关于svg模块的处理loader,不出意外肯定会报错:

ERROR in ./src/icon-comment.svg 1:0

Module parse failed: Unexpected token (1:0)

You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

译文:您可能需要适当的加载程序(loader)来处理此文件类型,目前没有配置加载程序来处理此文件。请参阅 https://webpack.js.org/concepts#loaders

问题我们已经很清楚了webpack无法找到处理svg模块的loader,那么现在的解决方案是什么呢?我们可以使用svgr提供的配合webpack的loader(Webpack - SVGR (react-svgr.com))就可以完成这个任务。

首先安装必要的依赖:yarn add -D @svgr/webpack;

然后,配置webpack处理svg文件:

module.exports = {
... ...
module: {
rules: [
{
test: /\.tsx?/,
use: [
'babel-loader'
],
exclude: /node_moudles/
},
... ...
+ {
+ test: /\.svg$/,
+ use: ['@svgr/webpack']
+ }
]
},
... ...
}

完成配置以后,重新经过webpack编译打包,运行后会看到控制台的输出:

  • 效果1:我们通过console.log输出的IconComment是一个React组件纯函数。
  • 效果2:代码中我们使用<IconComment/>在屏幕上展示出来了。

PS:上图中import报错暂时可以不用关心,是IDE类型检查的语法提示,webpack打包是没有问题的,想要深入了解,可以参考:【长文详解】TypeScript与Babel、webpack的关系以及IDE对TS的类型检查 - 知乎 (zhihu.com)

回顾整个过程,我们可以用下面的图来描述这个过程:

资源模式使用

当然,我们有的时候并不想按照React组件的使用。例如,svg同样可以作为一些元素的背景,这个时候我们需要把svg是为类似于图片一样的资源,就像下面的方式:

如果svg的loader配置保持不变,还是@svgr/webpack,我们会看到没有起效果,并且,查看对应生成css样式文件,我们可以看到对应的url('./icon-comment.svg')被编译为了url(8ed4ed501566520a5cd0.svg):

这个8ed4ed501566520a5cd0.svg是什么呢?可能看起来还有点懵,我们尝试打包编译项目,看一下编译后的产物就知道了:

通过上图的结果可知,很明显svg在这种场景下依然被@svgr/webpack这个loader处理为了React组件,又因为咱们是在less/css中引用这个svg,loader内部将这种场景回退到了文件资源存放了。

现在,我们希望webpack在处理这种场景的时候,还是以普通资源的方式进行;同时,在React代码中依然能够将svg资源以组件的形式被引入。好在webpack支持这样的配置:

module.exports = {
... ...
module: {
rules: [
... ...
{
// 引用的资源如果是 '${svg-path}/icon-comment.svg?abc'
test: /\.svg$/,
resourceQuery: /abc/,
// 以webpack的资源形式加载(普通资源文件、base64等)
type: 'asset',
},
{
// 除了上面的匹配规则,我们都按照React组件来使用
test: /\.svg$/,
resourceQuery: {not: [/abc/]},
use: ['@svgr/webpack']
}
]
},
... ...
}

webpack5中的 type: "assets" 是什么?可以看这篇文章:

资源模块 | webpack 中文文档 (docschina.org)

在上述配置中,我们都将匹配svg资源的引用,不同的是,如果这个引用路径带上url query,则使用webpack5的asset资源模块来处理;否则,调用@svgr/webpack来将其转换为React组件。

完成上述的配置以后,我们适当的修改代码,如下所示:

关于关键代码的解释:

  1. index.tsx第三行和第四行我们均引入了./icon-comment.svg模块,不同的是第四行的引入路径我们还添加了与webpac配置中保持一致的url query = "abc"。同时,在下面我们分别打印了IconComment和IconCommentUrl。
  2. 在index.module.less中,.app样式中,我们添加的背景也使用./icon-comment.svg,也添加了url query = "abc"。

代码运行以后,我们首先从UI上能够看到效果:

其次,从控制台也能看到对应的IconComment就是React函数组件;IconComment是svg资源的base64 DataUrl:

demo地址

本文相关demo已提交至webpack5-react-demo的svg_use_case分支,供读者参考:

w4ngzhen/webpack5-react-demo at svg_use_case (github.com)

一文详解如何在基于webpack5的react项目中使用svg的更多相关文章

  1. 一文详解Hexo+Github小白建站

    作者:玩世不恭的Coder时间:2020-03-08说明:本文为原创文章,未经允许不可转载,转载前请联系作者 一文详解Hexo+Github小白建站 前言 GitHub是一个面向开源及私有软件项目的托 ...

  2. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

  3. 一文详解 Linux 系统常用监控工一文详解 Linux 系统常用监控工具(top,htop,iotop,iftop)具(top,htop,iotop,iftop)

    一文详解 Linux 系统常用监控工具(top,htop,iotop,iftop)     概 述 本文主要记录一下 Linux 系统上一些常用的系统监控工具,非常好用.正所谓磨刀不误砍柴工,花点时间 ...

  4. 详解BOM用途分类及在汽车企业中的应用

    摘要:在整车企业中,信息系统的BOM是联系CAD.CAPP.PDM和ERP的纽带,按照用途划分产品要经过产品设计,工程设计.工艺制造设计.生产制造4个阶段,相应的在这4个过程中分别产生了名称十分相似但 ...

  5. 基于 React 封装的高德地图组件,帮助你轻松的接入地图到 React 项目中。

    react-amap 这是一个基于 React 封装的高德地图组件,帮助你轻松的接入地图到 React 项目中. 文档实例预览: Github Web | Gitee Web 特性 ️ 自动加载高德地 ...

  6. 一文详解 OpenGL ES 3.x 渲染管线

    OpenGL ES 构建的三维空间,其中的三维实体由许多的三角形拼接构成.如下图左侧所示的三维实体圆锥,其由许多三角形按照一定规律拼接构成.而组成圆锥的每一个三角形,其任意一个顶点由三维空间中 x.y ...

  7. 一文详解 WebSocket 网络协议

    WebSocket 协议运行在TCP协议之上,与Http协议同属于应用层网络数据传输协议.WebSocket相比于Http协议最大的特点是:允许服务端主动向客户端推送数据(从而解决Http 1.1协议 ...

  8. 1.3w字,一文详解死锁!

    死锁(Dead Lock)指的是两个或两个以上的运算单元(进程.线程或协程),都在等待对方停止执行,以取得系统资源,但是没有一方提前退出,就称为死锁. 1.死锁演示 死锁的形成分为两个方面,一个是使用 ...

  9. 一文详解Redis键过期策略

    摘要:Redis采用的过期策略:惰性删除+定期删除. 本文分享自华为云社区<Redis键过期策略详解>,作者:JavaEdge. 1 设置带过期时间的 key # 时间复杂度:O(1),最 ...

  10. 一文详解JackSon配置信息

    背景 1.1 问题 Spring Boot 在处理对象的序列化和反序列化时,默认使用框架自带的JackSon配置.使用框架默认的,通常会面临如下问题: Date返回日期格式(建议不使用Date,但老项 ...

随机推荐

  1. 「浙江理工大学ACM入队200题系列」问题 E: 零基础学C/C++78——求奇数的乘积

    本题是浙江理工大学ACM入队200题第八套中的E题 我们先来看一下这题的题面. 题面 输入 输入数据包含多个测试实例,每个测试实例占一行,每行的第一个数为n,表示本组数据一共有n个,接着是n个整数,你 ...

  2. Oracle生成awr报告操作步骤介绍

    AWR全称Automatic Workload Repository,自动负载信息库,是Oracle 10g版本后推出的一种性能收集和分析工具,提供了一个时间段内整个系统的报表数据.通过AWR报告,可 ...

  3. perl chmod

    chmod函数改变一列文件的权限.列表的第一个元素必须是数字模式.chmod函数返回成功改变了的文件的数目.如: $cnt = chmod 0755, 'file1', 'file2';  其中最前面 ...

  4. SPPS完整版下载安装教程【博主亲测】

    SPSS全称Statistical Product and Service Solutions,是一款优秀的数据分析软件,旨在为用户提供专业的统计产品与服务解决方案.SPSS面向行业应用人员所设,被广 ...

  5. Go语言核心36讲27

    在前面的文章中,我们一起学习了Go程序测试的基础知识和基本测试手法.这主要包括了Go程序测试的基本规则和主要流程.testing.T类型和testing.B类型的常用方法.go test命令的基本使用 ...

  6. 决策树(二):后剪枝,连续值处理,数据加载器:DataLoader和模型评估

    在上一篇文章中,我们实现了树的构造,在下面的内容中,我们将中心放在以下几个方面 1.剪枝 2.连续值处理 3.数据加载器:DataLoader 4.模型评估 一,后剪枝 • 为什么剪枝  –" ...

  7. 第2-4-1章 规则引擎Drools介绍-业务规则管理系统-组件化-中台

    目录 规则引擎 Drools 1. 问题引出 2. 规则引擎概述 2.1 什么是规则引擎 2.2 使用规则引擎的优势 2.3 规则引擎应用场景 2.4 Drools介绍 规则引擎 Drools 全套代 ...

  8. tp6 requset获取参数的方式

    第一种:获取全部参数的值 request()->param() 1 第二种:获取排除某些字段的值,即获取其他值 request()->except(['serverToken','logi ...

  9. 关于CSDN发布博客接口的研究

    前言 其实我之前就有一个想法,实现用 python 代码来发布博客, 因为我个人做了一个发布到 github 博客软件(其实就是实现 git 命令集成,还有markdown的渲染的软件), 如果我弄明 ...

  10. SSH(六)hibernate持久层模板于事务管理

    持久层只要完成数据对数据库增删改查的操作,我们常说的hibernate区别于mybatis是在于他的全自动,而hibernate的全自动则主要体现于 他的模板,一些简单的数据操作我们就不用再去手写sq ...