🌏 GitHub
React18 + webapck5
项目Demo: feat: ✨ 封装全局SVG组件
🗂 svg-sprite-loader
安装
npm
npm install svg-sprite-loader -D
yarn
yarn add svg-sprite-loader -D
创建SvgIcon组件
- 路径:src/components/SvgIcon/index.tsx
import React, {FC} from 'react';
import './index.less';
interface SvgIconProps {
svgName: string; // svg名字
svgClass?: string; // 自定义类名
color?: string; // 填充颜色
}
const SvgIcon: FC<SvgIconProps> = (props) => {
const {svgName, color, svgClass} = props;
return (
<i aria-hidden='true'>
<svg className={`svg-class ${svgClass}`}>
<use xlinkHref={'#icon-' + svgName} fill={color} />
</svg>
</i>
);
};
export default SvgIcon;
- 路径:src/components/SvgIcon/index.less
.svg-class {
display: inline-block;
width: 1em;
min-width: 14px;
height: 1em;
overflow: hidden;
font-size: 50px;
}
📲 增加svg统一出口
const importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
try {
importAll(require.context('./svg', true, /\.svg$/));
} catch (error) {
console.log(error);
}
export {}; // 默认导出,ts如若不导出,会警告
- 测试 my.svg
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1560995527910" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2159" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M376.672 285.248c0-82.702-69.85-149.805-156.116-149.805-86.148 0.06-156.056 67.103-156.056 149.805 0 40.25 16.597 76.809 43.521 103.78-7.343 29.532-11.164 60.255-11.164 91.931 0 142.423 78.148 267.398 195.518 337.419l31.223-123.012c-63.76-51.324-104.356-128.25-104.356-214.347 0-15.66 1.314-31.021 3.941-45.906 85.072-1.43 153.489-67.936 153.489-149.865z m133.906-83.656c53.97 0 104.416 14.052 147.818 38.643-6.866 16.85-10.508 35.129-10.508 54.242 0 82.761 69.849 149.805 155.996 149.805 86.148 0 156.116-67.103 156.116-149.805s-69.968-149.805-156.116-149.805c-20.179 0-39.521 3.691-57.133 10.36C679.708 110.257 598.457 84 510.578 84c-59.461 0-115.997 12.086-167.1 33.759l71.341 99.255c29.969-10.003 62.208-15.422 95.759-15.422z m290.858 291.93c-4.656 101.815-66.207 189.519-154.862 234.591-25.79-48.526-78.386-81.749-139.041-81.749-86.267 0-156.116 67.103-156.116 149.805 0 82.702 69.848 149.864 156.116 149.864 64.655 0 120.296-37.809 143.817-91.633 159.162-55.313 272.83-201.666 272.83-373.381 0-8.812-0.358-17.505-0.955-26.139l-121.789 38.642zM376.672 285.248c0-82.702-69.85-149.805-156.116-149.805-86.148 0.06-156.056 67.103-156.056 149.805 0 40.25 16.597 76.809 43.521 103.78-7.343 29.532-11.164 60.255-11.164 91.931 0 142.423 78.148 267.398 195.518 337.419l31.223-123.012c-63.76-51.324-104.356-128.25-104.356-214.347 0-15.66 1.314-31.021 3.941-45.906 85.072-1.43 153.489-67.936 153.489-149.865z m133.906-83.656c53.97 0 104.416 14.052 147.818 38.643-6.866 16.85-10.508 35.129-10.508 54.242 0 82.761 69.849 149.805 155.996 149.805 86.148 0 156.116-67.103 156.116-149.805s-69.968-149.805-156.116-149.805c-20.179 0-39.521 3.691-57.133 10.36C679.708 110.257 598.457 84 510.578 84c-59.461 0-115.997 12.086-167.1 33.759l71.341 99.255c29.969-10.003 62.208-15.422 95.759-15.422z m290.858 291.93c-4.656 101.815-66.207 189.519-154.862 234.591-25.79-48.526-78.386-81.749-139.041-81.749-86.267 0-156.116 67.103-156.116 149.805 0 82.702 69.848 149.864 156.116 149.864 64.655 0 120.296-37.809 143.817-91.633 159.162-55.313 272.83-201.666 272.83-373.381 0-8.812-0.358-17.505-0.955-26.139l-121.789 38.642zM376.672 285.248c0-82.702-69.85-149.805-156.116-149.805-86.148 0.06-156.056 67.103-156.056 149.805 0 40.25 16.597 76.809 43.521 103.78-7.343 29.532-11.164 60.255-11.164 91.931 0 142.423 78.148 267.398 195.518 337.419l31.223-123.012c-63.76-51.324-104.356-128.25-104.356-214.347 0-15.66 1.314-31.021 3.941-45.906 85.072-1.43 153.489-67.936 153.489-149.865z m133.906-83.656c53.97 0 104.416 14.052 147.818 38.643-6.866 16.85-10.508 35.129-10.508 54.242 0 82.761 69.849 149.805 155.996 149.805 86.148 0 156.116-67.103 156.116-149.805s-69.968-149.805-156.116-149.805c-20.179 0-39.521 3.691-57.133 10.36C679.708 110.257 598.457 84 510.578 84c-59.461 0-115.997 12.086-167.1 33.759l71.341 99.255c29.969-10.003 62.208-15.422 95.759-15.422z m290.858 291.93c-4.656 101.815-66.207 189.519-154.862 234.591-25.79-48.526-78.386-81.749-139.041-81.749-86.267 0-156.116 67.103-156.116 149.805 0 82.702 69.848 149.864 156.116 149.864 64.655 0 120.296-37.809 143.817-91.633 159.162-55.313 272.83-201.666 272.83-373.381 0-8.812-0.358-17.505-0.955-26.139l-121.789 38.642z" p-id="2160"></path></svg>
- 如果出现如果出现以上报错。说明项目环境TypeScript不识别webpack,需要安装@types/webpack-env依赖识别webpack类型文件。没有报错则忽略。
yarn add --dev @types/webpack-env
- require.context()
- webpack官方地址:require.context
可以通过 require.context()
函数来创建自己的 context。可以给这个函数传入三个参数:一个要搜索的目录,一个标记表示是否还搜索其子目录, 以及一个匹配文件的正则表达式。Webpack 会在构建中解析代码中的 require.context()
。
⚙️ webpack配置
增加loader
- 注意:新添加svg-sprite-loader放到
test: /\.(eot|svg|ttf|woff|woff2?)$/
之后,loader是从后往前执行
{
test: /\.(eot|ttf|woff|woff2?)$/,
exclude: path.resolve(__dirname, '../src/assets/icons'), // 不处理 svg类型文件
type: 'asset/resource'
},
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: path.resolve(__dirname, '../src/assets/icons'),
options: {
symbolId: 'icon-[name]' // symbolId和use使用的名称对应 <use xlinkHref={"#icon-" + svgName} />
}
}
使用SvgIcon
引入
- index.tsx 入口文件引入
- import '@/assets/icons/index';
import React from 'react';
import ReactDOM from 'react-dom/client';
import {BrowserRouter} from 'react-router-dom';
import '@/assets/icons/index'; // 入口文件引入
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLDivElement);
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
组件使用
import React from 'react';
import {observer} from 'mobx-react-lite';
import {useStores} from '@/store';
import SvgIcon from '@/components/SvgIcon';
import './index.less';
const HomeOne = () => {
const {globalStore, aboutStore} = useStores();
const {count, name} = globalStore;
const {count: aboutCount} = aboutStore;
return (
<div className='home-one-root'>
<SvgIcon svgName='my' color='pink' svgClass='icon-my' />
<SvgIcon svgName='loop' color='#1db02e' />
<SvgIcon svgName='loading' color='#1db02e' />
HomeOne
<p>{name}</p>
<p> globalStore: {count}</p>
<p> aboutStore: {aboutCount}</p>
</div>
);
};
export default observer(HomeOne);
.home-one-root {
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
height: 800px;
font-size: 50px;
background: #c6e2ff;
border-radius: 10px;
.icon-my {
font-size: 100px;
}
}