Skip to content

[Bug]: HMR Problem in MFEs-React #313

@itsluce

Description

@itsluce

Describe the bug

Any change happen inside the MFEs or Shell won't be Appear until I do a reload for the page

// Shell/vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { federation } from '@module-federation/vite';
import { dependencies } from './package.json';
import path from "path"
import tailwindcss from "@tailwindcss/vite"

export default defineConfig({
  plugins: [
    react({reactRefreshHost:'http://localhost:4200'}),
    tailwindcss(),
    federation({
      name: 'shell',
      remotes: {
        mfe1: {
          type: 'module',
          name: 'mfe1',
          entry: 'http://localhost:4201/remoteEntry.js',
          entryGlobalName: 'mfe1',
          shareScope: 'default'
        },
        mfe2: {
          type: 'module',
          name: 'mfe2',
          entry: 'http://localhost:4202/remoteEntry.js',
          entryGlobalName: 'mfe2',
          shareScope: 'default'
        }
      },
      shared: {
        react: {
          singleton: true,
          requiredVersion: dependencies.react,
          strictVersion: false,
        },
        'react-dom': {
          singleton: true,
          requiredVersion: dependencies['react-dom'],
          strictVersion: false,
        },
        'react-router-dom': {
          singleton: true,
          requiredVersion: dependencies['react-router-dom'],
          strictVersion: false,
        },
      },
    }),
  ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  build: {
    target: 'esnext',
    minify: false,
    cssCodeSplit: false,
    rollupOptions: {
      external: [],
    }
  },
  server: {
    port: 4200,
    cors: true,
    hmr: {
      port: 4210,
      host: 'localhost',
    },
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
    },
    // Proxy configuration to handle MFE requests
    proxy: {
      '/mfe1': {
        target: 'http://localhost:4201',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/mfe1/, ''),
      },
      '/mfe2': {
        target: 'http://localhost:4202',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/mfe2/, ''),
      },
    },
    watch: {
      usePolling: true,
      interval: 100,
    }
  },
});
// MFE1/vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { federation } from '@module-federation/vite';
import { dependencies } from './package.json';
import path from "path"
import tailwindcss from "@tailwindcss/vite"

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),
    federation({
      name: 'mfe1',
      filename: 'remoteEntry.js',
      exposes: {
        './App': './src/App.tsx',
        './routes': './src/routes.tsx',
        './Button': './src/components/Button.tsx',
      },
      shared: {
        react: {
          singleton: true,
          requiredVersion: dependencies.react,
          strictVersion: false,
        },
        'react-dom': {
          singleton: true,
          requiredVersion: dependencies['react-dom'],
          strictVersion: false,
        },
        'react-router-dom': {
          singleton: true,
          requiredVersion: dependencies['react-router-dom'],
          strictVersion: false,
        },
      },
    }),
  ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  build: {
    target: 'esnext',
    minify: false,
    cssCodeSplit: false,
    rollupOptions: {
      external: [],
    }
  },
  server: {
    port: 4201,
    cors: true,
    // Enhanced HMR configuration
    hmr: {
      port: 4211, // Different HMR port to avoid conflicts
      host: 'localhost',
    },
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
    },
    // Watch options for better file detection
    watch: {
      usePolling: true,
      interval: 100,
    }
  },
});
// MFE2/vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { federation } from '@module-federation/vite';
import { dependencies } from './package.json';

export default defineConfig({
  plugins: [
    react(),
    federation({
      name: 'mfe2',
      filename: 'remoteEntry.js',
      exposes: {
        './App': './src/App.tsx',
        './routes': './src/routes.tsx',
      },
      shared: {
        react: {
          singleton: true,
          requiredVersion: dependencies.react,
          strictVersion: false,
        },
        'react-dom': {
          singleton: true,
          requiredVersion: dependencies['react-dom'],
          strictVersion: false,
        },
        'react-router-dom': {
          singleton: true,
          requiredVersion: dependencies['react-router-dom'],
          strictVersion: false,
        },
      },
    }),
  ],
  build: {
    target: 'esnext',
    minify: false,
    cssCodeSplit: false,
    rollupOptions: {
      external: [],
    }
  },
  server: {
    port: 4202,
    cors: true,
    hmr: {
      port: 4212, // Different HMR port
      host: 'localhost',
    },
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
    },
    watch: {
      usePolling: true,
      interval: 100,
    }
  },
});
// Shell/App.tsx

import { Suspense, lazy,  } from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import './App.css';

const Mfe1App = lazy(() =>
    import('mfe1/App').catch(err => {
        console.error('Failed to load MFE1:', err);
        return { default: () => <div>Error loading MFE1. Please ensure it's running on port 5001.</div> };
    })
);

const Mfe2App = lazy(() =>
    import('mfe2/App').catch(err => {
        console.error('Failed to load MFE2:', err);
        return { default: () => <div>Error loading MFE2. Please ensure it's running on port 5002.</div> };
    })
);

function App() {
    return (
        <BrowserRouter>
            <div className="shell-container">
                <header className="shell-header">
                    <h1>React Shell Application</h1>
                    <nav>
                        <Link to="/">Home</Link> | <Link to="/mfe1">MFE1</Link> | <Link to="/mfe2">MFE2</Link>
                    </nav>
                </header>

                <main className="shell-content">
                    <Suspense fallback={<div>Loading MFE...</div>}>
                        <Routes>
                            <Route path="/" element={<h2>Welcome to the Shell!</h2>} />
                            <Route path="/mfe1/*" element={<Mfe1App />} />
                            <Route path="/mfe2/*" element={<Mfe2App />} />
                            <Route path="/shared-button" element={
                                <div>
                                    <h3>Local Button Component:</h3>
                                    <button style={{ padding: '10px 20px', backgroundColor: 'lightblue' }}>
                                        Local Button
                                    </button>
                                </div>
                            } />
                            <Route path="*" element={<h2>404 - Not Found</h2>} />
                        </Routes>
                    </Suspense>
                </main>
            </div>
        </BrowserRouter>
    );
}

export default App;

Version

"@module-federation/vite": "^1.4.1",
 "vite": "^6.3.5"
"react": "^19.1.0",

Reproduction

HMR-MFEs-React

Relevant log output

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions