https://github.com/ant-design/ant-design-web3/pull/761/files
实现了icon-preview(通过jsdoc, 鼠标放在组件上可以看到icon的样式),因为打包方式、产物以及命名上有一些不同,可能需要稍加改造。
这个同步脚本应该后续也用得上,略加改造同步 svg 可以提高后续添加 svg 的效率直接拖入图片就可以转成组件代码,降低cv和命名心智。
- 在package.json中设置命令可以直接执行ts脚本
"icons:generate": "NODE_OPTIONS='--experimental-specifier-resolution=node' node --loader ts-node/esm ./packages/icons/scripts/generate.ts"
- 通过
mport * as allIconDefs from '@ant-design/web3-icons'
获取所有组件,使用camelToKebab
函数转换需要符合自己命名需求的组件
- 通过 template 设置render模版
import pkg from 'lodash';
const { template } = pkg;
全部代码
import * as fs from 'fs';
import * as path from 'path';
import { promisify } from 'util';
import * as allIconDefs from '@ant-design/web3-icons';
import pkg from 'lodash';const __dirname = new URL(import.meta.url).pathname;
const { template } = pkg;const writeFile = promisify(fs.writeFile);interface IconDefinition {[key: string]: any;
}
interface IconDefinitionWithIdentifier extends IconDefinition {svgIdentifier: string;svgBase64: string | null;
}function camelToKebab(camelCaseString: string) {return camelCaseString.replace(/([a-z\d])([A-Z][a-z\d])|([A-Z]+(?![a-z\d]))/g, '$1$3-$2').toLowerCase();
}function detectRealPath(_path: string) {try {return fs.existsSync(_path) ? _path : null;} catch (e) {return null;}
}function svg2base64(svgPath: string, size = 50) {const svg = fs.readFileSync(svgPath, 'utf-8');const svgWithStyle = svg.replace(/<svg/, `<svg width="${size}" height="${size}" fill="#cacaca"`);const base64 = Buffer.from(svgWithStyle).toString('base64');return `data:image/svg+xml;base64,${base64}`;
}function walk<T>(fn: (iconDef: IconDefinitionWithIdentifier) => Promise<T>) {return Promise.all(Object.keys(allIconDefs).map((svgIdentifier) => {const iconDef = (allIconDefs as { [id: string]: IconDefinition })[svgIdentifier];const svgPathToKebab = camelToKebab(svgIdentifier);const realSvgPath = detectRealPath(path.resolve(__dirname, `../../src/svgs/${svgPathToKebab}.svg`),);let svgBase64: string | null = null;if (realSvgPath) {try {svgBase64 = svg2base64(realSvgPath);} catch (e) {}}return fn({ svgIdentifier, svgBase64, svgPathToKebab, ...iconDef });}),);
}async function generateIcons() {const iconsDir = path.join(__dirname, '../../src/svgs');try {await promisify(fs.access)(iconsDir);} catch (err) {await promisify(fs.mkdir)(iconsDir);}const render = template(`
// GENERATE BY ./scripts/generate.ts
// DON NOT EDIT IT MANUALLY
import * as React from 'react';
import AntdIcon from '@ant-design/icons';
import { type IconBaseProps } from '@ant-design/icons/lib/components/Icon';
import { ConfigProvider } from 'antd';
import classnames from 'classnames';import SVGComponent from '../svgs/<%= svgPathToKebab %>.svg';<% if (svgBase64) { %> /**![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=%3C%25%3D%20svgBase64%20%25%3E&pos_id=img-c6iaG6Dw-1712112320363) */ <% } %>
export const <%= svgIdentifier %> = React.forwardRef<HTMLSpanElement, IconBaseProps>((props, ref) => {const { getPrefixCls } = React.useContext(ConfigProvider.ConfigContext);const prefixCls = getPrefixCls('web3-icon-<%= svgPathToKebab %>');return (<AntdIcon{...props}className={classnames(prefixCls, props.className)}ref={ref}component={SVGComponent}/>);
});<%= svgIdentifier %>.displayName = '<%= svgIdentifier %>';`.trim(),);await walk(async (item) => {// generate icon fileconst svgPathToKebab = camelToKebab(item.svgIdentifier);try {await writeFile(path.resolve(__dirname, `../../src/components/${svgPathToKebab}.tsx`),render(item),);} catch (error) {}});// generate icon indexconst entryText = Object.keys(allIconDefs).sort().map((svgIdentifier) => `export * from './components/${camelToKebab(svgIdentifier)}';`).join('\n');await promisify(fs.appendFile)(path.resolve(__dirname, '../../src/index.ts'),`// GENERATE BY ./scripts/generate.ts// DON NOT EDIT IT MANUALLY${entryText}`.trim(),);
}generateIcons();