I am trying react module federation. I have created two react apps(modulefederation1, modulefederation2) using create-react-app command. I am getting 'Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/react/react' error when i run the application.
Node version: v16.14.2
Below is my code.
modulefederation1:
Package.json:
{
"name": "modulefederation1",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.1",
"@types/node": "^16.11.36",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.4",
"html-webpack-plugin": "^5.5.0",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-scripts": "5.0.1",
"serve": "^13.0.2",
"ts-loader": "^9.3.0",
"typescript": "^4.6.4",
"web-vitals": "^2.1.4",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.0"
},
"scripts": {
"start": "webpack serve --open",
"build": "webpack --config webpack.prod.js",
"serve": "serve dist -p 3002",
"clean": "rm -rf dist"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
webpack.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // only add this if you don't have yet
const { ModuleFederationPlugin } = webpack.container;
const deps = require('./package.json').dependencies;
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
console.log({ isProduction });
return {
entry: './src/index.tsx',
mode: process.env.NODE_ENV || 'development',
devServer: {
port: 3000,
open: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.(js|jsx|tsx|ts)$/,
loader: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'container',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js'
},
shared: {
...deps,
react: { singleton: true, eager: true, requiredVersion: deps.react },
'react-dom': {
singleton: true,
eager: true,
requiredVersion: deps['react-dom'],
},
},
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
};
public/index.html:
<html>
<head>
<title>CONTAINER</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
src/index.tsx:
import './bootstrap';
src/bootstrap.tsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
src/App.tsx:
import React from 'react';
const ModuleFederationTwo = React.lazy(() => import('app1/ModuleFederationTwo'));
function App() {
return (
<div >
Container application
</div>
);
}
export default App;
modulefederation2:
Pacakge.json file is same as modulefederation1 except "name": "modulefederation2"
webpack.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
const path = require('path');
const deps = require('./package.json').dependencies;
module.exports = {
entry: './src/index.tsx',
mode: 'development',
devServer: {
port: 3001,
open: true,
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
rules: [
{
test: /\.(js|jsx|tsx|ts)$/,
loader: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
// expose each component
'./ModuleFederationTwo': './src/App',
},
shared: {
...deps,
react: { singleton: true, eager: true, requiredVersion: deps.react },
'react-dom': {
singleton: true,
eager: true,
requiredVersion: deps['react-dom'],
},
},
}),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
src/index.tsx and src/bootstrap.tsx file is same as modulefederation1
src/App.tsx:
import React from 'react';
import './App.css';
function App() {
return (
<div className="App">
MFE application One
</div>
);
}
export default App;
I run both modulefederation1, modulefederation2 using yarn start.
I get main.js:1312 Uncaught Error: Shared module is not available for eager consumption: webpack/sharing/consume/default/react/react error when i run modulefederation1 application.
When i browsed everyone say that index code should be moved to bootstrap which i have done already. Do i have any other solution?
Network:
I was able to make above code work by changing the below code.
modulefederation1:
public/index.html:- add script tag <script src="http://localhost:3001/remoteEntry.js"></script>
<html>
<head>
<script src="http://localhost:3001/remoteEntry.js"></script>
<title>CONTAINER</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
webpack.config.js: Change remotes app1 value
remotes: {
app1: 'app1'
},