I try to implement a simple example about Module Federation with vanilla js functions.
Directory structure:
── packages
├── home
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ └── index.js
│ └── webpack.config.js
└── nav
├── index.html
├── package.json
├── src
│ ├── Header.js
│ ├── index.js
└── webpack.config.js
The expecting result is that home
app render the Header
of the nav
.
Webpack config of nav
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const deps = require("./package.json").dependencies;
module.exports = {
mode: 'development',
entry: './src/index.js',
optimization: {
minimize: false
},
resolve: {
extensions: [".js"],
},
output: {
publicPath: "http://localhost:4001/",
},
plugins: [
new ModuleFederationPlugin({
name: "nav",
filename: "remoteEntry.js",
library: {type: 'var', name: 'nav'},
exposes: {
"./Header": "./src/Header"
},
shared: {
...deps
}
}),
new HtmlWebpackPlugin({
title: 'Module Federation Example',
}),
],
}
Webpack config of home
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')
const deps = require("./package.json").dependencies;
module.exports = {
mode: 'development',
entry: './src/index.js',
optimization: {
minimize: false,
},
resolve: {
extensions: [".js"],
},
output: {
publicPath: "http://localhost:4000/",
},
plugins: [
new ModuleFederationPlugin({
name: "home",
filename: "remoteEntry.js",
remotes: {
nav: "nav@http://localhost:4001/remoteEntry.js"
},
shared: {
...deps
}
}),
new HtmlWebpackPlugin({
title: 'Module Federation Example',
}),
],
}
This is the Header:
export default () => {
const node = document.createElement('div');
node.innerHTML = 'Header';
node.style = 'padding: 1em; box-sizing: border-box;display: flex;background: aquamarine;font-family:sans-serif;'
return node;
}
In index.js
file in home
is where i import the Header
:
import Header from 'nav/Header';
const Greetings = () => {
const node = document.createElement('h1');
node.innerHTML = 'App Shell';
return node;
}
document.addEventListener("DOMContentLoaded", () => {
document.body.appendChild(Greetings());
document.body.appendChild(Header());
});
After build and serve on the url of the home
app i retrieve this error:
Uncaught TypeError: __webpack_modules__[moduleId] is not a function
at __webpack_require__ (main.js:66:41)
at eval (index.js:2:68)
at ./src/index.js (main.js:19:1)
at __webpack_require__ (main.js:66:41)
at main.js:217:37
at main.js:219:12
You can reproduce here in StackBlitz.
I tried to add a library option library: {type: 'var', name: 'nav'},
in the ModuleFederationPlugin but i don't understand why is not working.
I expected to see the nav/Header
rendered inside home app.
I found the solution.
The error arises because I was importing the remote module directly into the index.js
.
The remote module is loaded asynchronously so it was not yet available for import and hence the error.
The fastest solution is to import the remote modules into a bootstrap.js
file to make sure they are available and import it in index.js
index.js
import("./bootstrap");
bootstrap.js
import Header from 'nav/Header';
// other logics ...