You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

设计系统中动态加载SVG图标导致TypeScript报错及Webpack加载器问题的解决方案咨询

设计系统中动态加载SVG图标导致TypeScript报错及Webpack加载器问题的解决方案咨询

我最近在维护一个设计系统库,里面的Icon组件原本是通过静态导入所有SVG图标的方式实现的,结果导致打包后的体积直接冲到了6MB,这实在太夸张了!

先跟大家说下原本的实现:我有个images.ts用来统一导出所有SVG图标:

export { default as SvgArrow } from './arrow.svg';
export { default as SvgCopy } from './copy.svg';
...
export { default as SvgWater } from './water.svg';

然后Icon组件里直接导入所有图标,根据传入的iconName来渲染对应的图标:

import * as Icons from '../images';

// 渲染时获取当前图标
const CurrentIcon = Icons[iconName];

这种写法虽然简单,但所有用了<Icon />的组件都会把全部SVG打包进去,包体积直接炸了。

为了瘦身,我改成了动态加载当前需要的图标,代码是这样的:

const [IconComponent, setIconComponent] = useState<React.ElementType | null>(
  null,
);

useEffect(() => {
  const loadIcon = async () => {
    const icons = await import('../icons');

    setIconComponent(() => icons[iconName]);
  };
  loadIcon();
}, [iconName]);

改完之后效果立竿见影,包体积直接从6MB降到了700KB!但新的问题又来了——TypeScript疯狂报错,在使用这个设计系统的消费应用里,满屏都是类似这样的错误:

You may need an appropriate loader to handle this file type, currently
no loaders are configured to process this file.

只要我把代码改回静态导入,所有错误就都消失了,但包体积又回到了6MB,这真的很矛盾。

我试过各种办法:Webpack魔法注释、用eval(虽然能跑,但这明显是歪门邪道,安全性和性能都没保障)、优化useEffect的类型定义,但都没用,还是一堆TS错误。

下面是我的tsconfig和Webpack配置,大家帮我看看问题出在哪?

我的tsconfig.json配置:

{
  "compilerOptions": {
    "baseUrl": ".",
    "target": "es2020",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "declaration": true,
    "outDir": "./dist",
    "rootDir": ".",
    "declarationDir": "./dist",
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "module": "es2020",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "sourceMap": true,
    "declarationMap": true,
    "jsx": "react-jsx",
    "incremental": false,
    "paths": {
      "components/*": ["components/*"],
      "utils/*": ["utils/*"],
    },
    "plugins": []
  },
  "include": ["**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules", "dist"]
}

Webpack配置文件:

const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { getEntries } = require('./getEntries');

module.exports = {
  entry: getEntries(),
  mode: 'production',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: (pathData) => {
      const name = pathData.chunk.name;

      return `${name}.js`;
    },
    libraryTarget: 'module',
    globalObject: 'this',
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.svg$/,
        use: [
          {
            loader: '@svgr/webpack',
            options: {
              typescript: true,
              ref: true,
            },
          },
        ],
      },
    ],
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    alias: {
      components: path.resolve(__dirname, 'components'),
      theme: path.resolve(__dirname, 'theme'),
      images: path.resolve(__dirname, 'images'),
      types: path.resolve(__dirname, 'types'),
    },
  },
  externals: {
    '@mui/material': '@mui/material',
    next: 'next',
    react: 'react',
    'react-dom': 'react-dom',
  },
  optimization: {
    minimizer: [new TerserPlugin()],
  },
  plugins: [new CleanWebpackPlugin()],
  experiments: {
    outputModule: true,
  },
};

我还查过相关的问题,试过各种公开方案,除了eval都不管用。另外说一下,我用了@svgr/webpack来处理SVG,静态导入的时候完全没问题,图标都能正常渲染。

现在我发现如果在消费应用里加个忽略.d.ts的loader,应用能跑,但这显然不是长久之计——我希望我的设计系统库能开箱即用,用户不用额外配置就能正常使用,同时还能享受到动态加载带来的体积优化。

有没有大佬能帮我看看这个问题到底该怎么解决?

备注:内容来源于stack exchange,提问作者marcus-linmarkson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 14:08:08