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

基于Webpack的React微前端项目图片加载404问题求助

微前端Module Federation图片加载404问题解决

问题说明

开发基于Module Federation的React Webpack微前端项目,现状:

  • 主机应用运行在 http://localhost:3000/
  • 微前端应用运行在 http://localhost:3001
  • 图片资源存放在微前端应用中,微前端单独运行时图片加载正常,但嵌入主机应用后图片返回404错误

需求:所有React组件保留在微前端应用中,图片必须从3001端口加载,不能迁移到主机应用。

问题原因

组件中使用相对路径/images/default.png,当微前端嵌入主机应用时,浏览器会以主机应用的域名(3000端口)为基础请求图片,即访问http://localhost:3000/images/default.png,但图片实际存储在3001端口,因此出现404。

解决方案

1. 配置微前端Webpack公共路径

在微前端的webpack.config.js的output节点中添加publicPath,指定微前端资源的基础URL:

output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'bundle.js',
    publicPath: 'http://localhost:3001/' // 新增公共路径配置
},

2. 修改组件图片路径引用

在微前端组件中,使用Webpack提供的__webpack_public_path__变量拼接图片路径,确保请求指向微前端的3001端口:

<img src={`${__webpack_public_path__}images/default.png`} className='shadow-md shadow-gray-400' />

3. 优化微前端Webpack图片加载规则

移除重复的图片loader配置(file-loader和url-loader重复定义了相同文件类型),合并为一套规则:

{
    test: /\.(png|jpe?g|gif)$/i,
    use: [
        {
            loader: 'url-loader',
            options: {
                limit: false,
            },
        },
    ],
},

修改后的完整代码

微前端应用webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const { ModuleFederationPlugin } = require('webpack').container;
const packageJson = require('./package.json');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = {
    mode: 'development',
    entry: './src/index.tsx',
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: 'bundle.js',
        publicPath: 'http://localhost:3001/' // 新增公共路径配置
    },
    devServer: {
        port: 3001,
        hot: true,
        historyApiFallback: true,
    },
    module: {
        rules: [
            {
                test: /\.(?:js|ts|tsx)$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-react', '@babel/preset-env', '@babel/preset-typescript'],
                        plugins: [
                            "@babel/plugin-transform-runtime",
                            require.resolve('react-refresh/babel')
                        ]
                    }
                }
            },
            {
                test: /\.(?:css|scss)$/,
                include: path.resolve(__dirname, 'src'),
                use: [
                    { loader: "style-loader" },
                    { loader: "css-loader", options: { sourceMap: true } },
                    { loader: "postcss-loader", options: { sourceMap: true } },
                    { loader: "sass-loader", options: { sourceMap: true } },
                ],
            },
            // 合并后的图片加载规则
            {
                test: /\.(png|jpe?g|gif)$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: false,
                        },
                    },
                ],
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js', '.scss', '.css'],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: path.join(__dirname, 'public', 'index.html'),
        }),
        new ReactRefreshWebpackPlugin(),
        new ModuleFederationPlugin({
            name: 'McmpPortal',
            filename: 'remoteEntry.js',
            exposes: {
                './SupportPortal': './src/App.tsx',
            },
            shared: { ...packageJson.dependencies }
        }),
    ],
}

修改后的微前端组件

const Info = () => {
    return (
        <div className='home-info'>

            <div className={`info left ${TW_CLASS.BOX_SHADOW} `}>

                <div className='user-info'>
                    <div className='user-img'>
                        {/* 使用__webpack_public_path__拼接图片路径 */}
                        <img src={`${__webpack_public_path__}images/default.png`} className='shadow-md shadow-gray-400' />
                    </div>
                    <div>
                        <h4>John Doe</h4>
                        <p>Senior Technical Executive</p>
                    </div>
                </div>

                <div className='services'>
                    <h4 className='mb-3.5'>Active Services</h4>

                    <div className='grid grid-cols-2 gap-4'>
                        <div className='active-services'>
                            <div>
                                <p><strong>Consulting Services</strong></p>
                                <p>Expiry Date: 12 Dec 2024</p>
                            </div>
                            <div>
                                <p><strong>Azure Managed Services - Gold</strong></p>
                                <p>Expiry Date: 12 Dec 2024</p>
                            </div>
                            <div>
                                <p><strong>Azure Managed Services - Platinum</strong></p>
                                <p>Expiry Date: 12 Dec 2024</p>
                            </div>
                        </div>

                        <div className='service-information-cards'>
                            <h6>SLA</h6>
                            <ul>
                                <li>Scope of Services to be covered</li>
                                <li>Performance metrics</li>
                                <li>Penalties for contract breach</li>
                                <li>Customer responsibilities</li>
                                <li>Service provider responsibilities</li>
                            </ul>
                        </div>

                    </div>

                </div>

            </div>

            <div className={`info right ${TW_CLASS.BOX_SHADOW} `}>
                <h4>Support Portal</h4>
                <p>Text</p>
            </div>

        </div>
    )
}

注:生产环境若微前端域名动态变化,可在入口文件中动态设置__webpack_public_path__适配:

__webpack_public_path__ = process.env.MICRO_APP_PUBLIC_PATH || 'http://localhost:3001/';

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 16:05:55