我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!
需求
由于 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
确实不报如上错误,但却出现另一个错误:
查找原因
大概率是配制不对,换了好几个方案,有用 urlLoaderExcludes: [/.svg$/]
,也有用 config.module.rule('svg').uses.clear()
但都不起作用。
陷入深思好久。。。。。。
灵光一现,有没可能是跟 umi
的版本有关,那 umi
的不同版本对应的 webpack-chain
配制是不是也是不同的,这时赶紧查看了下源码,果然发现,在该项目里的所用的 webpack-chain
是 6.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
处理。
这时就想到了 include
与 exclude
将要采用 @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'))
}
这下真正的大功告成。
总结
- 遇到难题,不要慌
- 不要网上瞎找解决方案,而要先分析下出错的关键点,比如 3.
这个错,可以明显看出来是无法将
base64
作为标签(组件) 使用,那就要问下这一整串base64
哪来的,为什么会转成了base64
,可以想到是由于url-loader
里配制了limit
会有该效果,同时也说明了umi
里的默认webpack
配制并没有被删除。那么就要看下默认的webpack
配制到底是啥,就想到看源代码,这样一串下来就找到了默认image
规则 - 比起瞎找解决方案,甚至问别人,更多的是要学会看源码,因为网上别人遇到的大多跟你自己的项目不是同一个版本,只有看了自己项目里的具体配制,才能对症下药。