把你的阿里巴巴图标库转成你自己的@ant-design/icons

news2025/1/17 0:17:22

背景

我们使用iconfont-阿里巴巴矢量图标库来管理自己的一套图标,并且基于它的js资源,封装了自己的icons图标组件。封装的方法是使用了antd提供的createFromIconfontCN方法
但随着图标库越来越大,JS资源文件也变得越来越大。在业务中,哪怕你只需要一个图标,却也要引入整个的JS资源。这使得我们必须考虑对他进行优化。

解决思路

我们参考@ant-design/icons的设计模式,计划将它的图标拆分成了一个一个组件,在业务中按需引入来达到减少资源浪费的目的。

我们阅读了@ant-design/icons的源码,发现他的图标对象其实都放在了一个叫做@ant-design/icons-svg的包里,里面放了每一个图标的属性。@ant-design/icons引用了这些图标并再次封装了一些属性和方法。
在这里插入图片描述
然而我们并不能这样做,我们没有深究他的这些图标对象是如何自动产生的。 我们只有在iconfont-阿里巴巴矢量图标库上下载的JS资源文件。

好在这个JS文件非常的有规律,他其实就是每一个svg图标的path路径。这使得我们可以简单的使用这个js文件来创建我们的图标组件,而不需要在独立创建一个包来存放图标的属性。

在这里插入图片描述

实现步骤

  1. 我们需要使用脚本读取这个js文件,输出一个数组,数组里面是每个svg图标的path
  2. 创建一个组件,用来接受svg的path内容
  3. 创建一个模版,循环数组的内容并生成相应的文件
  4. 脚本生成tree shake目录
  5. 执行脚本,生成对应文件

一、读取文件,输出数组

const fs = require('fs');

// 读取文件后整理成后的数据源
const fileContent = [];

function handleFormatData(content) {
  const symbolStr = content
    .split('<svg>')[1]
    .split('</svg>')[0]
    .replace(/<\/symbol>/g, '</symbol>\n');

  // 先根据 回车 拆成数组,每一项都包含了一个图标的信息
  const IconsStringArr = symbolStr.split('\n').filter(Boolean);

  const fileNameRegExp = /id="你的js的svg的id前缀-([^]*?)"/g;
  const viewBoxRegExp = /viewBox="([^]*?)"/g;
  const pathRegExp = /<path([^]*?)path>/g;
  IconsStringArr.forEach((element) => {
    const fileName = element.match(fileNameRegExp)[0].split('id="你的js的svg的id前缀-')[1].split('"')[0];
    const viewBox = element.match(viewBoxRegExp)[0].split('viewBox="')[1].split('"')[0];
    const path = element.match(pathRegExp).join('');
    fileContent.push({
      fileName: `P${fileName}`,
      viewBox: viewBox,
      svgPath: path,
    });
  });
}

fs.readFile('./iconfont.js', (err, data) => {
   // 将文件文本处理成想要的数据源
   handleFormatData(data.toString());
 });

二、组件

import React, { PropsWithChildren } from 'react';

export interface LeeIconProps {
  spanProps?: React.HTMLProps<HTMLSpanElement>;
  svgProps?: React.SVGProps<SVGSVGElement>;
}

const LeeIcon = (props: PropsWithChildren<LeeIconProps>) => {
  return (
    <span role="img" {...props.spanProps} >
      <svg width="1em" fill="currentColor" aria-hidden="true" {...props.svgProps}>
        {props.children}
      </svg>
    </span>
  );
};

export default LeeIcon;

三、模版、生产文件

const lodash = require('lodash');

function generateFile() {
  const render = lodash.template(
    `
/* eslint-disable react/self-closing-comp */
// GENERATE BY ../../scripts/generate.ts
// DON NOT EDIT IT MANUALLY

import LeeIcon, { LeeIconProps } from '../components/icon';

const  <%= fileName %> = (props: LeeIconProps) => (
  <LeeIcon
    {...props}
    svgProps={{
      viewBox: '<%= viewBox %>',
      ...props.svgProps,
    }}
  >
  <%= svgPath %>
  </LeeIcon>
);

export default <%= fileName %>;
  `.trim(),
  );

  console.log('generateFileLoading...');

  fileContent.forEach(({ fileName, viewBox, svgPath }) => {
    // 写入文件内容
    fs.writeFileSync(`../src/leeIcons/${fileName}.tsx`, render({ fileName, viewBox, svgPath }), () => {});
    console.log(`generateFile${fileName}Down`);
  });
}
// 生成文件
generateFile();

四、生产Tree Shake目录

function generateTreeShake() {
  console.log('generateTreeShakeLoading...');

  const render = lodash.template(
    `
export { default as <%= fileName %> } from './<%= fileName %>';`,
  );

  fs.writeFileSync(
    `../src/leeIcons/index.ts`,
    `
// GENERATE BY ../../scripts/generate.ts
// DON NOT EDIT IT MANUALLY
  `.trim(),
    () => {},
  );

  fileContent.forEach(({ fileName }) => {
    fs.appendFileSync(`../src/leeIcons/index.ts`, render({ fileName }), () => {});
  });

  console.log('generateTreeShakeSuccess');
}
// 生成摇树首页
generateTreeShake();

五、执行脚本

node ./generate.js

完整代码

/* eslint-disable @typescript-eslint/no-require-imports */
/*
 * @Author: atwLee
 * @Date: 2023-04-07 15:48:20
 * @LastEditors: atwLee
 * @LastEditTime: 2023-04-12 10:18:40
 * @Description:
 * @FilePath: /panui/packages/Icons/script/generate.js
 */
const fs = require('fs');
const lodash = require('lodash');
const rimraf = require('rimraf');

// 读取文件后整理成后的数据源
const fileContent = [];

function handleFormatData(content) {
  const symbolStr = content
    .split('<svg>')[1]
    .split('</svg>')[0]
    .replace(/<\/symbol>/g, '</symbol>\n');

  // 先根据 回车 拆成数组,每一项都包含了一个图标的信息
  const IconsStringArr = symbolStr.split('\n').filter(Boolean);

  const fileNameRegExp = /id="你的js的svg的id前缀-([^]*?)"/g;
  const viewBoxRegExp = /viewBox="([^]*?)"/g;
  const pathRegExp = /<path([^]*?)path>/g;
  IconsStringArr.forEach((element) => {
    const fileName = element.match(fileNameRegExp)[0].split('id="你的js的svg的id前缀-')[1].split('"')[0];
    const viewBox = element.match(viewBoxRegExp)[0].split('viewBox="')[1].split('"')[0];
    const path = element.match(pathRegExp).join('');
    fileContent.push({
      fileName: `P${fileName}`,
      viewBox: viewBox,
      svgPath: path,
    });
  });
}

function generateFile() {
  const render = lodash.template(
    `
/* eslint-disable react/self-closing-comp */
// GENERATE BY ../../scripts/generate.ts
// DON NOT EDIT IT MANUALLY

import LeeIcon, { LeeIconProps } from '../components/icon';

const  <%= fileName %> = (props: LeeIconProps) => (
  <LeeIcon
    {...props}
    svgProps={{
      viewBox: '<%= viewBox %>',
      ...props.svgProps,
    }}
  >
  <%= svgPath %>
  </LeeIcon>
);

export default <%= fileName %>;
  `.trim(),
  );

  console.log('generateFileLoading...');

  fileContent.forEach(({ fileName, viewBox, svgPath }) => {
    // 写入文件内容
    fs.writeFileSync(`../src/leeIcons/${fileName}.tsx`, render({ fileName, viewBox, svgPath }), () => {});
    console.log(`generateFile${fileName}Down`);
  });
}

function generateTreeShake() {
  console.log('generateTreeShakeLoading...');

  const render = lodash.template(
    `
export { default as <%= fileName %> } from './<%= fileName %>';`,
  );

  fs.writeFileSync(
    `../src/leeIcons/index.ts`,
    `
// GENERATE BY ../../scripts/generate.ts
// DON NOT EDIT IT MANUALLY
  `.trim(),
    () => {},
  );

  fileContent.forEach(({ fileName }) => {
    fs.appendFileSync(`../src/leeIcons/index.ts`, render({ fileName }), () => {});
  });

  console.log('generateTreeShakeSuccess');
}

function generateIcons() {
  // 删除目录
  rimraf('../src/leeIcons', () => {
    // 增加目录
    fs.mkdirSync('../src/leeIcons', () => {});

    // 读取icons-js文件,获取需要的数据
    fs.readFile('./iconfont.js', (err, data) => {
      // 将文件文本处理成想要的数据源
      handleFormatData(data.toString());

      // 生成文件
      generateFile();

      // 生成摇树首页
      generateTreeShake();
    });
  });
}

generateIcons();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/435401.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

protobuf序列化原理、安装与应用

目录 protobuf序列化 protobuf的原理 protobuf 的安装 编译message文件 应用protobuf protobuf序列化 protobuf是一种比json和xml等序列化工具更加轻量和高效的结构化数据存储格式&#xff0c;性能比json和xml真的强很多&#xff0c;毕竟google出品。 官网&#xff1a;https:…

C语言笔记 | 一元三次方程

文章目录 0x00 前言 0x01 问题分析 0x02 代码设计 0x03 完整代码 0x04 运行效果 0x05 参考文献 0x06 总结 0x00 前言 在 1545 年&#xff0c;意大利学者卡丹所写的《关于代数的大法》中&#xff0c;提出了一元三次方程的求根公式。人们将其称为卡丹公式。对于标准型的一…

Python 彩蛋 —— 开发人员留下的惊喜

Python 彩蛋 —— 开发人员留下的惊喜 简介&#xff1a;Python 核心程序开发人员在软件内部设计了2个彩蛋。一起来看看吧。 文章目录 Python 彩蛋 —— 开发人员留下的惊喜&#x1f4a1;彩蛋一&#xff1a;Python 之禅&#x1f4a1;彩蛋二&#xff1a;Python 有趣的漫画 &#…

程序员面试完之后,人麻了...

去面试吧 面不被录用的试 面hr为了完成任务的试 面一轮二轮没有下文试 面需要通勤2小时的试 面随时加班的试 ...... 今年的“金三银四”被网友们称为“铜三铁四”&#xff0c;招聘软件上的岗位都能背下来了&#xff0c;简历却依然石沉大海。 好不容易等来个回复&#xff…

南京邮电大学通达学院2023《电子装配实习》报告

南京邮电大学通达学院2023《电子装配实习》报告 一 声明二 题目/实习报告提示三 例答 红笺寄 休遣玉人知 ——赠nmy 一 声明 南京邮电大学通达学院2023《电子装配实习》报告 答案更新时间:2023.04.10&#xff0c;已更新完成&#xff0c;如无错误不在更新 由于作者解答能力有限…

计算带宽使用情况

由于大多数组织依靠其 IT 基础架构进行日常业务关键型运营&#xff0c;因此网络带宽可以对其网络性能产生巨大影响。连接不良可能会使组织花费大量资金并影响生产力。这就是为什么监控和计算带宽使用情况对于确保组织的最佳网络带宽性能至关重要的原因。 在计算企业的带宽使用…

Linux以非堵塞模式执行shell脚本

1. HOW 我们在linux系统的终端执行命令的时候&#xff0c;有些命令可以很快的执行完退出&#xff0c;我们就可以继续使用这个终端了 比如 ls 这个命令&#xff0c;它执行的很快&#xff0c;等他返回完结果之后&#xff0c;我们可以继续使用这个终端。 还有部分命令是不会立马…

算法——双指针技巧总结

算法——双指针技巧总结 一、双指针二、链表快慢指针19.删除链表的倒数第 N 个结点双指针 206.反转链表思路&#xff1a;双指针法递归法 92.反转链表 II1.递归2.迭代&#xff08;双指针头插法&#xff09; 876.链表的中间结点常规思路双指针思路 141.环形链表&#xff08;判断链…

【安全与风险】恶意软件:概念、攻击和检测

恶意软件:概念、攻击和检测 恶意软件的定义恶意软件的类型易损性如何防范恶意软件:终端用户的观点不足防病毒软件基于主机的恶意软件检测特征检测启发式检测 数据收集挑战沙箱分析蜜罐 恶意软件的定义 Malware一词是恶意软件的缩写。 恶意软件是任何以破坏设备、窃取数据为目…

Ubuntu Desktop 启用远程桌面(Vino和TigerVNC方式)

文章目录 前言使用Vino方式无显示器使用使用TigerVNC方式 前言 在很多领域的生产开发工作中常常需要用到 Ubuntu Desktop 系统&#xff0c;但是在一些日常的工作交流中又离不开Windows系统&#xff0c;这种时候比较常用的解决方案就是在Windows系统上使用虚拟机安装Ubuntu。不…

【广州华锐互动】AI高仿真数字人在企业服务中的应用

虚拟数字人是指利用人工智能技术和计算机图形学生成的高度逼真的虚拟人形象&#xff0c;它可以模拟人类的语言、情感、行为和外貌&#xff0c;从而成为一种强大的营销工具&#xff0c;可以为企业带来多种商业价值。 广州华锐互动作为一家15年虚拟现实内容制作商&#xff0c;已…

CSS背景,元素显示模式,盒模型

文章目录 颜色取值选择器进阶复合选择器后代选择器&#xff1a;空格子代选择器 并集选择器&#xff08;union selector&#xff09;交集选择器&#xff08;intersection selector&#xff09;emmet语法hover伪类选择器 背景相关背景颜色背景图片背景平铺图片位置背景相关连写im…

文字大小PointSize和PixelSize

无论PointSize&#xff08;点大小&#xff09;还是像素大小&#xff08;PixelSize&#xff09;&#xff0c;描述的都是文字在输出设备&#xff08;显示屏、打印机等&#xff09;上呈现的大小 首先理解两个概念&#xff1a;DPI&#xff08;Dots per Inch) 和 PPI&#xff08;Pix…

295-光纤数据收发 隔离卡 加速计算卡 基于 Kintex-7 XC7K325T的半高PCIe x4双路万兆光纤收发卡

基于 Kintex-7 XC7K325T的半高PCIe x4双路万兆光纤收发卡 一、板卡概述 板卡采用Xilinx公司的XC7K325T-2FFG900I芯片作为主处理器&#xff0c;可应用于万兆网络、高速数据采集、存储&#xff1b;光纤隔离网闸等领域。 二、功能和技术指标&#xff1a; 板卡功能 参…

背锅侠?软件测试各类bug分类定位,从功能到性能超细总结......

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 遇到功能性问题&a…

【服务器数据恢复】NetApp存储中的oracle数据库数据恢复案例

服务器数据恢复环境&#xff1a; NetApp某型号存储&#xff0c;共96块SAS硬盘&#xff0c;划分的lun都映射给小型机使用&#xff0c;存放的是Oracle数据库文件&#xff0c;采用ASM裸设备存储方式。 服务器故障&#xff1a; 管理员误操作删除了该NetApp存储上的所有lun。具体情…

【Java】Java绘制UML图

1.继承关系&#xff08;Inheritance&#xff09; 继承指的是一个类&#xff08;子类、子接口&#xff09;继承另外的一个类&#xff08;父类、父接口&#xff09;的功能&#xff0c;通过关键字 extends 明确标识 UML图 继承用一条带空心三角箭头的实线表示&#xff0c;从子类…

数字孪生可实现三维可视化智慧园区吗?

随着城市化的进程和信息化的发展&#xff0c;越来越多的城市拥有了智慧园区这一新的城市形态&#xff0c;通过“互联网”和物联网技术&#xff0c;实现了各种功能部门之间的信息共享与协同&#xff0c;提高了园区服务的质量和效率。然而&#xff0c;如何更好地实现园区管理和运…

DNS服务的正反向解析

目录 1.DNS域名解析服务概括 产生原因 作用&#xff1a; 2.正向解析 2.1 准备工作&#xff0c;关闭selinux和防火墙 2.2 安装DNS软件 2.3 服务端操作&#xff0c;编辑DNS主配置文件 2.4 服务端操作&#xff0c;编辑区域配置文件&#xff0c;可以在最后添加&#xff0c…

OpenAI文档翻译——搭建第一个自己的ChatGPT应用

这篇主要是讲了重头到位创建一个基于OpenAI API的应用程序的过程&#xff0c;同时给出了Node.js、Python版本的实例代码。应用程序的构建总体来说是很简单的就是一个接口调用&#xff0c;前提是我们需要提供密匙。 如果想要获取更好的结果返回一个是可以给模型提供一些列子从而…