svg和png转base64插件
# 图例

# 插件功能
- 生产环境下,将小于 8KB 的 svg 和 png 图标转成 base64 编码,减少 http 请求,加快图标的展示速度。
# 实现思路
判断
process.env.NODE_ENV !== 'production'
,非生产环境不执行这个插件的功能,本地开发的时候继续使用源文件引用的方式展示图标避免不必要的文件处理,不需要频繁修改和保存 scc 和 scss 文件,从而提示开发效率
便于调试,base64 无法找到文件对于的位置,没法调试
打包过程中,
process.env.NODE_ENV === 'production'
,这个时候执行插件的代码逻辑写一个正则 urlRegex ,匹配 scss 和 css 文件里面使用 url() 引入的 png 和 svg 文件
然后将匹配到的这些图标的完整路径获取到,读取图标文件的大小和内容
超过 8 KB 的图标不进行处理,仍然使用源文件的 url 模式导入
不超过 8 KB 的图标将其内容转成 base64 格式编码,然后替换 scss 或 css 文件内的
url(xxx.svg|png)
部分需要注意的是这个步骤需要在 load 钩子函数中完成,因为 transform 钩子函数里的 css 和 scss 文件已经被预处理过了,资源路径已经被预处理并替换为
__VITE_PUBLIC_ASSET__
这样的占位符,导致无法在 transform 钩子中匹配到原始的 svg 或 png 路径
# 实现代码
点击 展开/收起 jsx 代码
import fs from 'fs';
import path from 'path';
export default function svgToBase64Plugin(maxSize = 8 * 1024) {
return {
name: 'vite-plugin-svg-base64',
load(id) {
if (process.env.NODE_ENV !== 'production') {
return null;
}
// 处理 CSS 和 SCSS 文件
if (id.endsWith('.css') || id.endsWith('.scss')) {
const src = fs.readFileSync(id, 'utf-8');
const urlRegex = /url\(['"]?([^'")]+\.(svg|png))['"]?\)/g;
let match;
let newSrc = src;
while ((match = urlRegex.exec(src)) !== null) {
const filePath = match[1];
const fileExt = match[2];
if (filePath.startsWith('/svgs/') || filePath.startsWith('/')) {
const fullPath = path.resolve('public', filePath.slice(1));
if (fs.existsSync(fullPath)) {
const stats = fs.statSync(fullPath);
const fileSizeInBytes = stats.size;
if (fileSizeInBytes <= maxSize) {
const fileContent = fs.readFileSync(fullPath);
const base64 = Buffer.from(fileContent).toString('base64');
const mimeType =
fileExt === 'svg' ? 'image/svg+xml' : 'image/png';
const dataUrl = `data:${mimeType};base64,${base64}`;
newSrc = newSrc.replace(filePath, dataUrl);
}
}
}
}
return newSrc;
}
return null;
},
};
}