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

使用Encore、SVGR与React时SVG无法正确导入的问题

问题:Symfony + Encore + React 中SVG内联渲染失败

我维护的Symfony项目前端基于Encore构建,正在将部分前端重构为React。需要添加SVG图标,但无法用img标签引入,尝试用SVGR把SVG转成React组件,导入时却返回文件路径而非组件,导致createElement报错。

现有Encore配置

Encore
.setOutputPath('web/build/react')

// the public path used by the web server to access the previous directory
.setPublicPath('/build/react')
.addEntry('react', '/react/app.js')
// enable source maps during development
.enableSourceMaps(!Encore.isProduction())

// empty the outputPath dir before each build
.cleanupOutputBeforeBuild()

// show OS notifications when builds finish/fail
.enableBuildNotifications()

.enableSingleRuntimeChunk()

.enableStimulusBridge('./react/controllers.json')
.enableTypeScriptLoader()

// create hashed filenames (e.g. app.abc123.css)
.enableVersioning()
.configureBabel((config)=>{
    config.presets.push('@babel/preset-react')
})
.addRule({
    test: /\.(sass|scss|svg|png|jpe?g)$/,
    use: [
        'style-loader',
        {
            loader: 'css-loader',
            options: {
                modules: {
                    localIdentName: "[local]-[hash:base64:8]"
                }
            }
        },
        'sass-loader'
    ]
})
.addRule({
    test: /\.svg/,
    type: "asset/resource",
    generator: {
        filename: "[path][name]-[hash][ext][query]"
    }
})

var configReact = Encore.getWebpackConfig();
configReact.target = ['browserslist'];
configReact.name = 'react';

configReact.resolve.alias = {
        "@symfony/stimulus-bridge/controllers.json": "/react/controllers.json",
        "@src": "/react/src",
}

现有Icon组件代码

import React from "react";
import { DecoratedProps } from "@src/types/componentHelpers";
import arrow from "@src/assets/icons/arrow.svg";

export interface Props {
    icon: IconType
}

export default class Icon extends React.Component<DecoratedProps<Props>> {
    constructor(props: DecoratedProps<Props>) {
        super(props);
    }

    render() {
        return (<Arrow />)
    }
}

问题原因

  1. Encore的webpack规则中,SVG被同时匹配了两条规则:一条是和样式、图片一起走style/css/sass-loader,另一条是单独的asset/resource规则,导致webpack将SVG当作资源文件处理,导入时返回文件路径而非React组件。
  2. 组件中导入arrow.svg后直接使用<Arrow />,但既未定义该组件,也未将导入的SVG转换为React组件。

解决方案

步骤1:修改Encore配置,添加SVGR支持

首先安装SVGR依赖:

npm install @svgr/webpack --save-dev
# 或使用yarn
yarn add @svgr/webpack --dev

然后调整Encore的webpack规则:

Encore
// ... 保留其他原有配置
.addRule({
    // 移除原有规则中的svg匹配,SVG不需要走css-loader流程
    test: /\.(sass|scss|png|jpe?g)$/,
    use: [
        'style-loader',
        {
            loader: 'css-loader',
            options: {
                modules: {
                    localIdentName: "[local]-[hash:base64:8]"
                }
            }
        },
        'sass-loader'
    ]
})
// 针对JS/TSX文件中的SVG导入,用SVGR转为React组件
.addRule({
    test: /\.svg$/i,
    issuer: /\.[jt]sx?$/,
    use: ['@svgr/webpack'],
})
// 可选:如果需要在样式文件中导入SVG作为资源文件,保留这条规则
.addRule({
    test: /\.svg$/i,
    issuer: /\.(css|scss|sass)$/,
    type: 'asset/resource',
    generator: {
        filename: "[path][name]-[hash][ext][query]"
    }
})
// ... 保留其他原有配置

步骤2:调整Icon组件代码

现在导入SVG会直接得到React组件,修改组件代码如下:

import React from "react";
import { DecoratedProps } from "@src/types/componentHelpers";
// 注意组件名大写,符合React组件命名规范
import Arrow from "@src/assets/icons/arrow.svg";

// 定义允许的图标类型
export type IconType = 'arrow';

export interface Props {
    icon: IconType
}

export default class Icon extends React.Component<DecoratedProps<Props>> {
    render() {
        // 维护图标映射表,支持动态渲染
        const IconComponent = {
            arrow: Arrow
            // 可添加更多图标组件
        }[this.props.icon];
        
        return IconComponent ? <IconComponent /> : null;
    }
}

更推荐的函数式组件写法

import React from "react";
import { DecoratedProps } from "@src/types/componentHelpers";
import Arrow from "@src/assets/icons/arrow.svg";

export type IconType = 'arrow';

interface Props {
    icon: IconType;
}

const Icon: React.FC<DecoratedProps<Props>> = ({ icon }) => {
    const iconMap = {
        arrow: Arrow,
        // 可扩展更多图标
    };

    const IconComponent = iconMap[icon];
    return IconComponent ? <IconComponent /> : null;
};

export default Icon;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 16:22:47