Webpack 5 - Module Federation
Share bundles between independent Applications
Motivation
Let’s assume we have one of the following use cases:
The first use case is let’s say we have multiple micro frontends that are distributed and deployed independently. So, in every micro frontend we have some UI elements, like buttons and input fields.
And we want to share our reusable buttons and input fields between these micro frontends because we want to avoid code duplication and we want to decouple these view elements from our micro frontends.
The second use case is let’s say we have Multiple Applications under the same brand that are deployed independently.
In every one of these applications we have a “lead form”, a contact form that collects potential customers information and sends them back to some specific endpoint.
So we don’t want to write this form multiple times between our applications or we don’t want to copy/paste the form source code in all projects and consequently we will get a WET codebase.
If we want to customize this “lead form”, we want to do this independently and deploy only the new form and avoid deploying all other applications.
Module Federation
Webpack 5 introduces a new feature Module Federation, that allow us to reuse bundle files between different and independent application (application webpack builds).
We can implement the contact “lead form” that you can see in the image in GREEN BORDER in Application 1 (black) and Application 2 (red) can just use it as a remote bundle.
In this pattern we can spot a micro frontend architecture.
The Technical Side
All the magic of the Module Federation can be configured in your webpack.config.js file, so basically this feature is just a configuration that can be added to webpacks’ config object.
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const htmlConfig = {
// ...
};
module.exports = {
entry: './src/index.js',
output: {
publicPath: 'http://localhost:5200/',
path: path.resolve(__dirname, 'dist')
},
module: {
// ...
},
plugins: [
new ModuleFederationPlugin({
library: { type: "var", name: "FormApp" },
name: "FormApp",
filename: "remoteEntry.js",
exposes: {
"./Form": "./src/Form"
},
remotes: {
App: "App",
},
shared: {
"@material-ui/core": {
eager: true,
singleton: true,
},
"react": {
eager: true,
singleton: true,
},
"react-dom": {
eager: true,
singleton: true,
},
},
}),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin(htmlConfig)
]
};
If you are not familiar with Webpack, check out the full course on:
Webpack 5: Complete Developers Guide 2020
In the webpack.config.js, we can add the Module Federation Plugin in our plugins section.
So this is actualy Application 1 webpack config, as it exposes the Form component, and if any other Application like Application 2 wants to consume this component, it also needs to use the Module Federation Plugin but in order to consume the component.
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
// ....
plugins: [
new ModuleFederationPlugin({
// ...
remotes: {
RemoteForm: "FormApp",
},
shared: ["react", "react-dom"],
}),
// ....
]
};
Conclusion
Webpack 5 will allow us share components or any other javascript modules between applications in an easy and strraightforward way.
Webpack 5: Complete Developers Guide 2020