I am trying to create a sample microfrontend in react which contains Products app and the container app
products app's webpack.config.js
const htmlWebPackPlugin=require('html-webpack-plugin');
const moduleFederationPlugin=require('webpack/lib/container/ModuleFederationPlugin');
module.exports={
devtool:"eval-source-map",
mode:'development',
devServer:{
port:8081
},
plugins:[
new moduleFederationPlugin({
name:'products',
filename:'remoteEntry.js',
exposes:{
'./productsIndex':'./src/index'
}
}),
new htmlWebPackPlugin({
template:'./public/index.html'
})
]
};
index.js file
import faker from 'faker';
let products='';
for (let index = 0; index < 5; index++) {
products+=`<div>${faker.commerce.productName()}</div>`;
}
document.querySelector('#products').innerHTML=products;
product app's index.html
<html>
<head></head>
<body>
<div id="products"></div>
</body>
</html>
container app's webpack.config.js
const htmlWebPackPlugin=require('html-webpack-plugin');
const moduleFederationPlugin=require('webpack/lib/container/ModuleFederationPlugin');
module.exports={
devtool:"eval-source-map",
mode:'development',
devServer:{
port:8080
},
plugins:[
new moduleFederationPlugin({
name:'containers',
remotes:{
products:'products@http://localhost:8081/remoteEntry.js'
}
}),
new htmlWebPackPlugin({
template:'./public/index.html'
})
]
};
container app's bootstrap.js
import 'products/productsIndex';
console.log('container');
container app's index.js
import('./bootstrap');
container app's index.html
<html>
<head></head>
<body>
<div id="products"></div>
</body>
</html>
When I run the container app, remote files are loading fine but getting error as
Uncaught (in promise) TypeError: fn is not a function
while loading "./productsIndex" from webpack/container/reference/products
at handleFunction (main.js:500:31)
at onInitialized (main.js:512:60)
at main.js:502:52
at async Promise.all (:8080/index 0)
Found the reason for this error, when the remote name given in Module Federation Plugin and the id given to dom element in remote HTML are same, this error will come
In this case, inside the product's moduleFederation config name is 'products' and in the container app's index.html has a div with id 'products', to fix the issue just have to change the name in any one place
The reason for this behavior is, that remoteEntry.js will create a global variable as remote name (that is var cart;) and when we have a dom element with id, the browser creates a global variable with the same id, so the variable created on the dom element will override the variable created by remoteEntry.js