Vite插件自动编译svg图标为字体

发布时间:2024年01月24日

前言

今天来点儿6的.本文或许需要花费点时间才能理解.
目前是草稿阶段,比较凌乱,许多部分没有详细说明,日后有空更新补充.

本文主要提供解决思路,请按需调整.

很多时候我们在开发阶段是不能确定使用哪些图标的,它会随着开发不停的新增或调整.
所以我一般会从iconfont直接下载svg图标保存起来.

注意本段为废话可以跳过
一开始我是直接将svg代码直接插入dom中,但总觉得这么干会浪费内存影响效率之类的…后来我就好奇平时常见的图标字库是怎么构建的…

查着查着就发现了svgtofont这件神器.
它可以自动寻找某个目录下的svg文件,随后一键生成.less .css .ttf .woff这一堆你要的文件,岂不美哉…
关于它的用法及原理本文不着重介绍,小伙伴可以自行查询,一抓一大把…

开始

本文目的主要解决两大痛点

  1. 使用vite自动更新构建svg图标库到项目中
  2. 还是使用vite自动更新构建svg图标库到项目中

解决

我写了一个vite.plugin.svgtofont.ts插件,以实现自动重编译.
它目前在我的UI库中工作的很好,很大程度提高了我编写该库的效率.

根目录下创建一个文件 vite.plugin.svgtofont.ts

//vite.plugin.svgtofont.ts
import { PluginOption } from "vite";
import path from 'path'
import chokidar from 'chokidar';
import svgtofont from 'svgtofont';
import fs from 'fs';

/* 注意 svg文件名不能存在空格 */
const plugin: PluginOption = {
    name: 'svgtofont',
    configureServer(server) {
        // 监视 SVG 目录
        const fontName = "mpui-icon"
        const src = path.resolve(__dirname, 'svg');
        const dist = path.resolve(__dirname, 'src/Components/Icon/font');
        const watcher = chokidar.watch(src, { ignoreInitial: true });
        console.log(`[vite.plugin.svgtofont]开始监视SVG目录文件变化:${src}`);

        const rebuild = async () => {
            // 当 SVG 文件变化时,使用 svgtofont 重新编译字体
            await svgtofont({
                fontName, src, dist,
                css: {
                    fontSize: "1em",
                },
                // 其他 svgtofont 配置项...
            });

            //生成TS引用文件
            console.log(`[vite.plugin.svgtofont]SVG图标重编译->生成TS引用文件...`);
            const cssFilePath = path.resolve(dist, `${fontName}.css`);
            const cssContent = fs.readFileSync(cssFilePath, 'utf-8');
            // console.log("=>cssContent:", cssContent);

            // 使用正则表达式匹配所有的图标名称
            const iconNames = cssContent.match(/\.mpui-icon-(\w+):before/g) || [];
            // 生成 TypeScript 文件的内容
            let tsContent = `import "./${fontName}.less"\nexport type IconName =\n`;
            iconNames.forEach((iconName, index) => {
                iconName = iconName.replace(`.${fontName}-`, '').replace(':before', '');
                tsContent += `  | '${iconName}'\n`;
            });
            //console.log("=>tsContent:", tsContent);
            fs.writeFileSync(path.resolve(dist, `${fontName}.ts`), tsContent);


            console.log(`[vite.plugin.svgtofont]SVG图标->重编译完成,重加载页面...`);

            // 通知 Vite 重新加载页面
            server.ws.send({ type: 'full-reload', });
            console.log(`[vite.plugin.svgtofont]SVG图标->重载完成!`);

        }
        watcher.on("ready", async () => {
            console.log(`[vite.plugin.svgtofont]SVG图标重编译->初始化...`);
            await rebuild();
        });
        watcher.on('add', async (path) => {
            console.log(`[vite.plugin.svgtofont]SVG图标重编译-新增文件:${path}`);
            await rebuild();
        });
        watcher.on('unlink', async (path) => {
            console.log(`[vite.plugin.svgtofont]SVG图标重编译-移除文件:${path}`);
            await rebuild();
        });
    }
}


export default plugin

使用

修改vite配置文件,新增我们刚才写的插件.

//vite.config.ts
import svgtofont from "./vite.plugin.svgtofont"
import { defineConfig } from "vite"
export default defineConfig({

   ...
    plugins: [
        svgtofont,
    ],
    optimizeDeps: {
        /* 设置不被Vite打包的包 */
        exclude: ["fs", "path", "chokidar", "svgtofont"],
    }
}) 

然后你需要制作一个Icon类负责实例化元素
这里使用到了CustomElements 没用过的话可以去补课一下

import { IconName } from '你插件上配置的输出路径';

export class Icon extends HTMLElement{
constructor(name: IconName ) {
  super()
  this.classList.add( `mpui-icon-${nameOrSVG}`)
  
  }
}

export defalut Icon 
if(!customElements.get("mpui-icon"))customElements.define("mpui-icon",Icon)

然后用起来就很简单了

import Icon from "./Icon"
document.body.appendChild(new Icon("MiragePulse"))

随后你会在dom中看到一个名为mpui-icon的元素
神奇吧.你可以在上面提到的Icon.ts结尾部分更改它叫啥
在这里插入图片描述

这个元素被渲染出来以后是这样的
在这里插入图片描述
这是我用Illustrator画的一个小图标,转存为了SVG文件生成的.
(Illustrator生成的SVG大多数情况不能直接使用,还需要进一步压缩处理,下次更新说明)

文章来源:https://blog.csdn.net/cbaili/article/details/135810597
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。