1. svg-sprite-loader 介绍及原理
svg-sprite-loader
是一个 Webpack 加载器(loader),它的主要目的是处理 SVG(可缩放矢量图形)文件,并将它们合并成一个或多个 SVG 精灵图(Sprite)。这个过程简化了SVG图标的管理和使用,提升了网页性能。
原理
- 匹配svg,合成一个包含多个
<symbol>
原素的SVG文件(原来的SVG替换成了<symbol>
)。 - 通过
<use>
使用<symbol>
(eg.<use xlink:href="#icon-id"></use>
)。
优点
- 通过ID来控制图标,十分Nice
- 减少HTTP请求
- 动态引用和样式控制
- SVG配置过程自动化
缺点
- 兼容性差(Internet Explorer 9 +)
- 无法处理 多色、渐变色 SVG图标 改色
2. svg-sprite-loader 使用
安装
npm install --save-dev svg-sprite-loader
Webpack配置
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
use: [
{
loader: 'svg-sprite-loader',
options: {
extract: true,
spriteFilename: 'svg-sprite.[hash].svg',
},
},
],
},
],
},
};
Vue组件
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="iconName"/>
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
iconName () {
return `#za-icon-${this.iconClass}`
},
svgClass () {
if (this.className) {
return `za-svg-icon za-icon-${this.iconClass} ` + this.className
} else {
return `za-svg-icon za-icon-${this.iconClass}`
}
}
}
}
</script>
<style lang="scss">
.za-svg-icon {
width: 20px;
height: 20px;
vertical-align: middle;
fill: currentColor;
overflow: hidden;
}
</style>
自动导入 index.js
import Vue from 'vue'
import SvgIcon from '@/components/k-element/svg-icon/index.vue'
// 全局注册组件
Vue.component('svg-icon', SvgIcon)
// 定义一个加载目录的函数
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('@/assets/icons', false, /\.svg$/)
// 加载目录下的所有 svg 文件
requireAll(req)
3. 踩坑
在集成开源项目时,开源项目中也使用了svg-sprite-loader
,如何解决webpack配置冲突 ?
原项目中的loader配置如下(weboack.config.js):
const webpackCommonConfig = {
// ...
module: {
rules: [
// ...
{
test: /\.svg$/,
loader: "svg-sprite-loader",
include: [resolve("src/assets/icons")],
options: {
symbolId: "icon-[name]",
},
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset", // asset 资源类型可以根据指定的图片大小来判断是否需要将图片转化为 base64
parser: {
dataUrlCondition: {
maxSize: 60 * 1024, // 限制于 60kb
},
},
generator: {
filename: "static/img/[name][ext]",
},
exclude: resolve("src/assets/icons")
},
],
},
};
开源项目配置如下(vue.config.js):
module.exports = {
chainWebpack: (config) => {
config.module
.rule("svg")
.exclude.add(resolve("packages"))
// .add(resolve('xxxx'))
// .add(resolve('xxxx'))
// .add(resolve('xxxx'))
.end();
config.module
.rule("icons")
.test(/\.svg$/)
.include.add(resolve("packages"))
// .add(resolve('xxxx'))
// .add(resolve('xxxx'))
// .add(resolve('xxxx'))
.end()
.use("svg-sprite-loader")
.loader("svg-sprite-loader")
.options({
symbolId: "icon-[name]",
})
.end();
},
};
合并思路
- 将packages等需要解析的SVG目录从Webpack5 自带的资源解析loader中排除(exclude)
- 在
svg-sprite-loader
中添加packages等需要解析的SVG目录(include) - 在自动导入SVG的
index.js
中添加packages等需要加载的SVG目录
最终代码如下:
weboack.config.js:
const webpackCommonConfig = {
// ...
module: {
rules: [
// ...
{
test: /\.svg$/,
loader: "svg-sprite-loader",
include: [resolve("src/assets/icons"), resolve("packages")],
options: {
symbolId: "icon-[name]",
},
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset", // asset 资源类型可以根据指定的图片大小来判断是否需要将图片转化为 base64
parser: {
dataUrlCondition: {
maxSize: 60 * 1024, // 限制于 60kb
},
},
generator: {
filename: "static/img/[name][ext]",
},
exclude: [resolve("src/assets/icons"), resolve("packages")]
},
],
},
};
index.js
import Vue from 'vue'
import SvgIcon from '@/components/k-element/svg-icon/index.vue'
// 全局注册组件
Vue.component('svg-icon', SvgIcon)
// 定义一个加载目录的函数
const requireAll = requireContext => requireContext.keys().map(requireContext)
const req1 = require.context('@/assets/icons', false, /\.svg$/)
const req2 = require.context('@/packages', false, /\.svg$/)
// 加载目录下的所有 svg 文件
requireAll(req1)
requireAll(req2)
END
撒花 ✿✿ヽ(°▽°)ノ✿