采用 @svgr/webpack 支持 svg 作为组件引入

1 篇文章 0 订阅
1 篇文章 0 订阅

需求

由于 antd 默认的 Icon 图标很有限,所以决定采用自定义 SVG 图标方式来拓展。
Antd Icon

开始实战

在这里插入图片描述

按文档介绍的,我先安装了 @svgr/webpack,但由于是采用的 umi 搭建的脚手架,所以需要采用 webpack-chain 来自定义 webpack 配置:

  chainWebpack(config) {
    config.module.rules.delete('svg')
    config.module
      .rule('svg')
      .test(/\.svg$/)
      .use('svgr')
      .loader('@svgr/webpack')
  },
import HistorySvg from '@/asset/icon/history.svg'
<Icon component={HistorySvg} />

如上方式在用最新 umi 脚手架搭建的 demo 项目是可以正常显示图标的。

出现问题

但在该项目,却报如下错误:
在这里插入图片描述
网上搜了下,大多是说版本不一致,想到自己的 umi 版本较低,所以就将 @svgr/webpack 版本降到 5.5.0
确实不报如上错误,但却出现另一个错误:
DOMException: Failed to execute 'createElement' on 'Document': The tag name provided

查找原因

大概率是配制不对,换了好几个方案,有用 urlLoaderExcludes: [/.svg$/] ,也有用 config.module.rule('svg').uses.clear() 但都不起作用。
陷入深思好久。。。。。。
灵光一现,有没可能是跟 umi的版本有关,那 umi 的不同版本对应的 webpack-chain 配制是不是也是不同的,这时赶紧查看了下源码,果然发现,在该项目里的所用的 webpack-chain6.0 版本的,并且发现默认的 webpack 配制是:
在这里插入图片描述

如上处理 svg 文件的 loader 所对应的规则名并不叫 svg,而是叫 image,所以不管用 delete 还是 clear 实际上都没有将该规则删除,而当 svg 文件大小小于 1000kb 时,就会被转换为 base64。就出现了如上的错误。

对症下药

找到了原因,就开始对症下药了。

  chainWebpack(config) {
    config.module.rules.delete('image')
    config.module
      .rule('svg')
      .test(/\.svg$/)
      .use('svgr')
      .loader('@svgr/webpack')
  }

这样 svg 是可以作为组件使用了,但原先的那些 png 等图片格式就异常了。
所以不能直接删除 image 规则,而是要替换该规则。

test 里去掉 svg 匹配

  config.module
  .rule('image')
  .test(/\.(png|jpe?g|gif)$/) // 去掉 svg
  .use('url-loader')
    .loader('url-loader')
    .options({
      limit: 10000,
      name: '[name].[hash:7].[ext]'
    })
 config.module
  .rule('svg')
  .test(/\.svg$/)
  .use('svgr')
  .loader('@svgr/webpack')

这样图片与新加入的 svg 文件可以正常显示了。
但考虑到项目目前里已经有了 svg 文件,并且之前是作为 img src 使用,所以不能一刀切将所有的 svg 文件都用 @svgr/webpack 处理。
这时就想到了 includeexclude
将要采用 @svgr/webpack 解析的放在 src/asset/icon 目录下

chainWebpack(config) {
    // 将要使用 svgr/webpack 解析的 svg 文件放置在 src/asset/icon 底下
    // 被解析的 svg 文件,可以作为 React 组件导入
    config.module
      .rule('image')
      .exclude.add(resolve('src/asset/icon')) // 不包含 src/asset/icon 的采用默认的 image 规则 
      .end()
    config.module
      .rule('svg')
      .test(/\.svg$/)
      .include.add(resolve('src/asset/icon')) // 在 src/asset/icon 下的采用新建的规则
      .end()
      .use('@svgr/webpack')
      .loader(resolve('@svgr/webpack'))
  }

这下真正的大功告成。

总结

  1. 遇到难题,不要慌
  2. 不要网上瞎找解决方案,而要先分析下出错的关键点,比如 3. DOMException: Failed to execute 'createElement' on 'Document': The tag name provided
    这个错,可以明显看出来是无法将 base64 作为标签(组件) 使用,那就要问下这一整串 base64 哪来的,为什么会转成了 base64,可以想到是由于 url-loader 里配制了 limit 会有该效果,同时也说明了 umi 里的默认 webpack 配制并没有被删除。那么就要看下默认的 webpack 配制到底是啥,就想到看源代码,这样一串下来就找到了默认 image 规则
  3. 比起瞎找解决方案,甚至问别人,更多的是要学会看源码,因为网上别人遇到的大多跟你自己的项目不是同一个版本,只有看了自己项目里的具体配制,才能对症下药。
  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值