@syzlm/vite-plugin-svg-images
v0.3.2
Published
Convert SVG files to PNG and render them as Vue image components for WeChat Mini Programs.
Downloads
347
Readme
@syzlm/vite-plugin-svg-images
面向 Vue 3 / Vite 微信小程序项目的 SVG 图片插件。构建时将 SVG 栅格化为 PNG,运行时通过原生 image 组件渲染,避免微信小程序不支持直接渲染 SVG 的问题。
特性
- SVG 在构建阶段转换为 PNG,不向小程序产物注入 SVG
- 通过一个
SvgImage组件按名称使用图片 - 默认宽高均为
18rpx - 支持
class、style、size、color以及image的其他属性和事件 - PNG 以 Base64 内联,不依赖小程序本地 SVG 能力
size传数字时使用rpx,传字符串时支持px、rpx等单位- 图标名称、热更新和 TypeScript 联合类型提示
- 自动扫描 Vue 模板,仅将实际使用的 SVG 打包进产物
- PNG 按 SVG 内容哈希缓存,不覆盖源文件
安装
npm install @syzlm/vite-plugin-svg-images -D需要 Node.js 20+、Vite 5+ 和 Vue 3.3+。
如果项目是 uni-app 且仍使用 Vite 4.0,请安装兼容 Vite 4 的特殊版本:
npm install @syzlm/[email protected] -D该版本仅用于 Vite 4.x 项目,使用方式和导入路径保持不变;Vite 5+ 项目继续使用默认版本。
配置
// vite.config.ts
import { defineConfig } from "vite";
import uni from "@dcloudio/vite-plugin-uni";
import SvgImages from "@syzlm/vite-plugin-svg-images/vite";
export default defineConfig({
plugins: [
uni(),
SvgImages({
iconDir: "src/assets/svg",
// 动态 color 的全部可能值;模板静态颜色无需填写
colors: ["#1677ff", "#d0343a"],
}),
],
});HBuilderX 创建的 Vue3 项目使用同一配置,因为其编译器也是 Vite。uni() 来自
@dcloudio/vite-plugin-uni;完整示例见
examples/hbuilderx-mp-weixin。
默认扫描 src/assets/svg。嵌套目录会保留在名称中,例如 src/assets/svg/common/add.svg 的名称是 common/add。
iconDir 也可以直接指向阿里 Iconfont 的 symbol JS,或使用数组同时配置 SVG 目录和
iconfont.js:
SvgImages({
iconDir: ["src/assets/svg", "docs/iconfonts/iconfont.js"],
includeNames: ["common/add", "icon-shouye1"],
});插件会在构建阶段拆分 <symbol> 并转换为 PNG,图标名称保留 symbol 的完整 id。
Iconfont JS 中依赖浏览器 window、document 的注入代码不会进入小程序产物。
数组中的所有来源共用按需打包、颜色预生成和名称冲突检查。
插件默认在项目根目录生成 svg-image.d.ts,请确保 tsconfig.json 包含该文件:
{
"include": ["src", "svg-image.d.ts"]
}注册组件
小程序端不支持在 main.ts 全局注册 .vue 组件。uni-app 编译微信小程序时,位于
node_modules/.cache 的组件会被改写为惰性路径函数,注册后 resolveComponent 解析到
一个返回字符串的函数,页面渲染为空;同时全局组件不会进入任何页面的
usingComponents,微信端同样无法解析。
因此小程序项目请开启 easycom,插件会把组件输出到
src/components/svg-image/svg-image.vue,uni-app 的 easycom 机制会自动扫描模板中的
<SvgImage> / <svg-image> 标签并注入各页面的 usingComponents:
// vite.config.ts
SvgImages({
iconDir: "src/assets/svg",
easycom: true, // 输出 easycom 组件,替代 main.ts 全局注册
});开启 easycom 后,请移除 main.ts 中的全局注册代码,模板中直接使用即可:
// main.ts(easycom 模式下不要再 app.component 注册 SvgImage)
import { createSSRApp } from "vue";
import App from "./App.vue";
export function createApp() {
const app = createSSRApp(App);
return { app };
}H5、App 端和非 uni-app 的 Vite 项目不受此限制,可以继续在 main.ts 全局注册:
// main.ts
import { createSSRApp } from "vue";
import App from "./App.vue";
import SvgImage from "~virtual/svg-image";
export function createApp() {
const app = createSSRApp(App);
app.component(SvgImage.name!, SvgImage);
return { app };
}也可以在页面或组件中局部导入。easycom 模式下生成的组件建议加入 .gitignore
(src/components/svg-image/),它在每次构建时自动生成。
使用
<script setup lang="ts">
// @author gt
import SvgImage from "~virtual/svg-image";
</script>
<template>
<!-- 默认 18rpx × 18rpx -->
<SvgImage name="common/add" />
<!-- 数字自动转换为 rpx -->
<SvgImage name="common/add" :size="24" class="icon" />
<!-- 字符串保留小程序常用单位 -->
<SvgImage name="common/add" size="36rpx" style="opacity: 0.8" />
<!-- 静态颜色会在编译时自动转为对应的 PNG Base64 -->
<SvgImage name="common/add" :size="28" color="#D0343A" />
</template>color 会替换 SVG 中非 none 的 fill 和 stroke,适合单色图标。模板内的静态
十六进制、rgb()、rgba() 颜色会自动发现;如果颜色来自变量,请将所有可能值写入
colors,否则组件会回退到图标原色并输出警告:
SvgImages({
colors: ["#1677ff", "#d0343a"],
});按需打包
静态图标名称会被自动识别,未使用的 SVG 不会转换,也不会进入 dist:
<SvgImage name="common/add" />includeNames 的作用
includeNames 用于显式声明需要保留的图标。它主要解决动态 name 无法在构建阶段
确定具体值的问题,也可以强制保留模板中没有直接出现的图标。
插件会将模板中自动发现的静态名称与 includeNames 合并,然后只转换这些图标:
- 静态
name="common/add":自动发现,通常不需要写入includeNames。 - 动态
:name="activeIcon"且配置了includeNames:只额外保留配置中的候选图标。 - 动态
:name="activeIcon"且未配置includeNames:为避免运行时缺图,保留全部图标并输出警告。 - 模板中未直接使用但需要通过脚本、配置或后端数据展示的图标:应写入
includeNames。
名称必须与组件的 name 属性完全一致。SVG 文件使用相对于 SVG 目录的无扩展名路径,
Iconfont 图标使用 <symbol> 的完整 id:
SvgImages({
iconDir: ["src/assets/svg", "docs/iconfonts/iconfont.js"],
includeNames: [
"common/add", // src/assets/svg/common/add.svg
"common/close", // src/assets/svg/common/close.svg
"icon-shouye1", // <symbol id="icon-shouye1">
],
});<script setup lang="ts">
/** @author gt */
const activeIcon = "icon-shouye1";
</script>
<template>
<SvgImage :name="activeIcon" />
</template>includeNames 不会改变图标名称,也不会引入新的图标来源;它只从 iconDir 指定的
SVG 与 Iconfont JS 中选择需要保留的图标。
获取全部名称或名称类型:
import { svgNames, type SvgImageName } from "~virtual/svg-image";IDE 扩展或自动化脚本也可以直接调用转换 API:
import { convertSvgImages } from "@syzlm/vite-plugin-svg-images";
const entries = await convertSvgImages({
root: process.cwd(),
iconDir: "src/assets/svg",
});配置项
| 属性 | 类型 | 默认值 | 说明 |
| --------------- | ----------------------------- | -------------------------------------------- | ----------------------------------- |
| iconDir | string \| readonly string[] | src/assets/svg | SVG 与 Iconfont JS 来源,可混合配置 |
| cacheDir | string | node_modules/.cache/vite-plugin-svg-images | PNG 缓存目录 |
| componentName | string | SvgImage | 组件名称 |
| dts | string \| false | svg-image.d.ts | 类型声明路径;false 表示不生成 |
| colors | readonly string[] | [] | 为动态 color 预生成的候选颜色 |
| includeNames | readonly string[] | [] | 显式保留动态或模板外使用的图标名称 |
| easycom | boolean | false | 输出 easycom 组件,供小程序端使用 |
注意事项
- SVG 会变成位图,不能在小程序运行时直接修改其像素颜色。
color切换的是编译期预生成的 PNG,不在小程序运行时解析或栅格化 SVG。- 为避免高 DPI 屏幕模糊,插件按 192 DPI 转换,再由
size缩放显示。 - 多个 SVG 目录中不能出现相同图标名称;冲突时构建会给出具体文件路径。
