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

如何让Create React App项目中外部模块的SVG React组件导入正常工作?

问题原因分析

这个问题的核心在于Create React App(CRA)的webpack默认配置规则:

CRA内置的@svgr/webpack loader只会对项目自身src目录下的SVG文件进行处理,将其转换为React组件(也就是你用到的ReactComponent导出)。而对于node_modules目录下的文件,CRA默认会用file-loader处理SVG,这时候导出的是SVG文件的路径字符串,而非React组件。

当你的@foo/ui组件库通过tsc编译后,只是把TypeScript转成了JavaScript,import { ReactComponent as Logo } from '@foo/design/static/img/logo.svg'这条导入语句被原封不动保留了下来。当@foo/project尝试解析这条来自node_modules/@foo/ui的导入时,webpack不会触发@svgr/webpack,自然找不到ReactComponent导出,就会报错。

而你直接在@foo/project的根组件里导入SVG时,因为文件路径属于项目src目录(或者说webpack默认的处理范围),所以@svgr/webpack正常工作,SVG被转为React组件。


针对内部组件库的最简单解决方法

因为你的组件库是仅内部使用的,不需要对外发布到npm,这里推荐几个低成本的解决方案:

方案1:提前将SVG转为React组件(最直接)

不需要依赖任何打包配置修改,直接把SVG文件转换成React组件代码,嵌入到@foo/ui中:

  1. 把@foo/design/static/img/logo.svg的内容复制出来,创建一个Logo.tsx组件:
// @foo/ui/src/components/Logo.tsx
import React, { FC } from 'react';

export const Logo: FC = () => (
  <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
    {/* 这里粘贴原SVG的path等内容 */}
    <path d="M..." fill="#000" />
  </svg>
);
  1. 在MyComponent中导入这个React组件,而非直接导入SVG:
// MyComponent.ts
import React, { FC } from 'react';
import { Logo } from './Logo'; // 换成你的组件路径
export const MyComponent: FC = () => {
  return (
    <div>
      Some stuff.
      <Logo />
    </div>
  );
};

这样tsc编译后,MyComponent.js里就没有SVG导入语句了,@foo/project使用时完全不需要处理SVG,直接用组件即可。

方案2:用craco/react-app-rewired修改项目webpack配置

如果你不想手动转SVG,可以修改@foo/project的webpack配置,让它对node_modules/@foo/design下的SVG启用@svgr/webpack:

  1. 安装craco(比react-app-rewired更简洁的CRA配置修改工具):
npm install @craco/craco --save-dev
  1. 在项目根目录创建craco.config.js:
module.exports = {
  webpack: {
    configure: (webpackConfig) => {
      // 找到CRA中处理SVG的规则
      const svgRule = webpackConfig.module.rules.find(rule =>
        rule.oneOf?.some(item => item.test?.toString() === '/\\.svg$/')
      );
      
      if (svgRule) {
        // 让规则包含@foo/design下的SVG文件
        svgRule.oneOf.forEach(item => {
          if (item.test?.test('.svg')) {
            item.include = [
              ...(item.include || []),
              /node_modules\/@foo\/design/
            ];
          }
        });
      }
      
      return webpackConfig;
    }
  }
};
  1. 修改package.json的脚本命令,用craco替换react-scripts:
"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test"
}

之后重启项目,webpack就会正确处理@foo/ui中导入的@foo/design下的SVG了。

方案3:给组件库添加打包工具(适合大量SVG场景)

如果你的@foo/ui有很多SVG需要处理,可以用Rollup代替纯tsc编译,配合@svgr/rollup插件把SVG转为React组件后再打包:

  1. 安装依赖:
npm install rollup @rollup/plugin-typescript @svgr/rollup --save-dev
  1. 创建rollup.config.js:
import typescript from '@rollup/plugin-typescript';
import svgr from '@svgr/rollup';

export default {
  input: 'src/index.ts', // 你的组件库入口文件
  output: {
    dir: 'lib',
    format: 'esm',
    sourcemap: true
  },
  plugins: [
    svgr({ exportType: 'named', jsxRuntime: 'automatic' }),
    typescript({ tsconfig: './tsconfig.json' })
  ],
  external: ['react', 'react-dom'] // 排除react相关依赖,让使用方提供
};
  1. 修改package.json的编译命令:
"scripts": {
  "build": "rollup -c"
}

这样打包后的@foo/ui/lib里的代码已经把SVG转为React组件了,@foo/project直接导入就能用,不需要额外配置。


内容的提问来源于stack exchange,提问作者Soullivaneuh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 14:37:47