项目图标组件处理
我们如何复用项目里的图标,如何维护和引用图标?
为了形成便于使用的图标库,做了如下调研:
- iconfont(webfont)
- unocss
- svgr
- iconPark
- unplugin-icons
我们希望达到的目的
- 开发自行维护,而不是由设计维护,第一是我们的设计稿经常变更,交给他们不放心,第二是这样我们使用图标会更复杂,有一些图标对于设计来说并不是“图标”,但是对于开发来说,我们需要上传到图标库去使用等等。
- 图标可以复用,可以变形和变色,保留动态效果。
- 组件库便于使用,不要占用太多的内存,如果可以按需下载更好。
其实综上所述,现在我们的图标有几种方案:1. 字体图标。2. 纯css图标(unocss)。3. svg图标(svgr,unplugin-icons)
最后经过综合考虑,我使用的是svgr的方案,多色图标用cdn链接,因为unocss要引入的额外东西太多。
iconfont
-
❌阿里的iconfont网站
很不幸的是我们上传的svg变形了,设计不是按照iconfont规范画的svg,导致我们的svg图标上传上去一整个变形和无法识别。 -
使用webfont自己转格式
转出来的图标也是缺斤少两,蚌埠住了,用不了。
——————
- 优势:
使用方便。 - 缺点:
字体图标文件下载比较慢,不能按需引入
svg需要设计规范,否则转出来会变形
unocss
https://github.com/unocss/unocss
https://antfu.me/posts/icons-in-pure-css-zh
https://juejin.cn/post/7398378565182537754
https://juejin.cn/post/7394789388154241033
官方文档的自定义图标教程:
https://unocss.dev/presets/icons#filesystemiconloader
https://unocss.dev/integrations/next
UnoCss的方案是无二次处理的纯css方案,从0开始只需要配置放图标的文件夹路径,之后就不需要任何其他操作,只把图标放到指定路径就能用了。
优势在于:
- css使用方便
- 按需加载
- 转为base64,比svg更加轻量。
使用方式:
- https://github.com/unocss/unocss/blob/main/examples/next
- https://github.com/vercel/next.js/discussions/33254
- 类型:https://github.com/iconify/iconify/blob/main/packages/utils/src/loader/types.ts#L86
遇到问题
HMR的问题,很郁闷
https://thundermiracle.com/blog/en/2022-06-07-next-with-unocss/
https://github.com/unocss/unocss/issues/419
https://github.com/unocss/unocss/issues/2103
https://github.com/unocss/unocss/issues/3198
1. 新增uno.config.js
安装yarn add -D unocss@0.58.9 @iconify/utils
,导出自定义svg
- 记得处理width / height为1em
- 替换颜色为currentColor
// uno.config.js
import { defineConfig, presetUno, presetIcons } from 'unocss';
import { FileSystemIconLoader } from '@iconify/utils/lib/loader/node-loaders';export default defineConfig({presets: [presetUno(),presetIcons({collections: {custom: FileSystemIconLoader('./assets'),},}),],
});
2. 安装webpack插件
yarn add -D @unocss/webpack@0.58.9
yarn add -D @unocss/preset-uno@0.59.9
这个版本,因为我用的next,只能接受cjs模块导出的依赖。
3. webpack配置
中间各种自己尝试的test icon
const { defineConfig, presetUno, presetIcons, presetAttributify } = require('unocss');
const { FileSystemIconLoader } = require('@iconify/utils/lib/loader/node-loaders');
const path = require('path');module.exports = defineConfig({rules: [['b-pink', { background: 'pink' }]],presets: [presetAttributify(),presetUno(),presetIcons({collections: {custom: FileSystemIconLoader(path.resolve(__dirname, './assets'), (svg) => {console.log('--', svg);}),test: {'my': "<svg width=24 height=24 viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M5.03412 5.03412C5.36606 4.70217 5.90425 4.70217 6.2362 5.03412L18.9654 17.7633C19.2973 18.0952 19.2973 18.6334 18.9654 18.9654C18.6334 19.2973 18.0952 19.2973 17.7633 18.9654L5.03412 6.2362C4.70217 5.90425 4.70217 5.36606 5.03412 5.03412Z' fill='currentColor'/> <path d='M18.9659 5.03412C18.6339 4.70217 18.0957 4.70217 17.7638 5.03412L5.03464 17.7633C4.70269 18.0952 4.70269 18.6334 5.03464 18.9654C5.36658 19.2973 5.90477 19.2973 6.23672 18.9654L18.9659 6.2362C19.2978 5.90425 19.2978 5.36606 18.9659 5.03412Z' fill='currentColor' /></svg>",},carbon: () => import('@iconify-json/carbon/icons.json').then((i) => i.default),circle: {circle: '<svg viewBox="0 0 120 120"><circle cx="60" cy="60" r="50"></circle></svg>',},},customizations: {transform(svg, collection, icon) {if (collection === 'custom') {console.log('?????', svg, collection, icon);}return svg.replace(/#fff/, 'currentColor');},},}),],
});
4. postcss
作用是可以看@assets
module.exports = {plugins: {'@unocss/postcss': {configOrPath: './uno.config.js',content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],},},
};
5. 调整icon样式
比如大小为1em,颜色为currentColor
还有模式:纯色icon是mask,多色icon是background等
unplugin-icons
https://www.npmjs.com/package/unplugin-icons
一个unocss去除了各种多余css的亚子,就是可以直接只用icons组件了,对于按需的人来说应该很有用。
SVGR
https://github.com/svg/svgo#configuration
https://react-svgr.com/docs/next/
https://react-svgr.com/docs/options
https://svgo.dev/docs/plugins/addAttributesToSVGElement/
用了之后感觉还挺方便的,只是作为一个优化SVG的工具,而且直接转成reactComponent,比unocss方便。
他们的官网已经写的很详细了,直接用@svgr/webpack配置就好
对于next这样配置,而且需要注意fileLoaderRule这个和官网上的例子不一样,我们要把所有svgr的loader都处理了,所以用filter不是用find。
还有就是导出的组件用removeAttrs去掉宽高颜色,不然我们的自己配置无法生效。
// https://react-svgr.com/docs/next/try {const fileLoaderRule = config.module.rules.filter((rule) => rule.test?.test?.('.svg'));if (fileLoaderRule.length) {config.module.rules.push({...fileLoaderRule[0],test: /\.svg$/i,resourceQuery: /url/, // *.svg?url},{test: /\.svg$/i,issuer: fileLoaderRule[0].issuer,resourceQuery: { not: [...(fileLoaderRule[0].resourceQuery?.not ?? []), /url/] }, // exclude if *.svg?urluse: [{loader: '@svgr/webpack',options: {svgoConfig: {plugins: [{name: 'preset-default',params: {overrides: {// 禁用会导致SSR问题的插件removeViewBox: false,},},},{ name: 'removeAttrs', params: { attrs: '(fill|stroke|width|height)' } },{name: 'addAttributesToSVGElement',params: {attributes: [{width: '1em',height: '1em',fill: 'currentColor',},],},},],},titleProp: true,ref: true,expandProps: 'end',namedExport: 'ReactComponent',},},],});fileLoaderRule.forEach((rule) => {rule.exclude = /\.svg$/i;});}} catch (e) {console.log('?????', e);}
iconPark
https://bytedance.larkoffice.com/wiki/wikcnJZV45hM71QgI60iwkzvXob
讲实话我觉得使用感比iconfont好多了,我上传svg不会变形。
但很令人难过的是,考虑到我们变动频繁性,以及生成链接需要经常替换的问题,舍弃了外部工具库的方案改为了自研。
如果是不怎么改,或者小项目用起来真的很舒服。