Micro Frontends
Extending the microservices idea to front end development. In the current trends, most of the application are migrating based on microservices architecture. In Microservice architecture, each feature or business is developed by independent teams and each team specialises in their respective feature and develops end-end.
Monolith web applications sits on top of microservices which is a single page application develops all the features. Gradually application grows and team faces difficulty to maintain the entire application. Alike Microservices, design the same pattern from frontend and it is named as Micro Frontends, thought has come in the late 2016 by the Thoughtworks.
Now Web application can maintain by independent teams for end-end development on each feature or business or module without knowing what other module does.
Module federation
New method of sharing code between frontend applications which makes code more straight forward and more independent. Module federation is one of the exciting features in Javascript architecture used in Webpack 5, loads code dynamically at runtime to reduce code duplication and host application loads only missing dependencies. It is one of the best ways to design the application in Microservice approach. And it has many benefits to web application if utilized appropriately.
Alternatives
For Micro Frontends design, there are many other alternatives:
- Bit
- Single-SPA
- SystemJs
- And many more ways to design the Micro Frontends.
Module Federation is not a framework, it is a plugin that is added to Webpack, which gives you freedom and flexibility to build your project the way you want and also offers developers to choose the technology they want to use. It integrates components at runtime.
Module Federation Configuration
It is very easy to integrate Module federation within the application. It has two main concepts:
Remote Federated Module: Expose the components you want to share in Webpack.config.js
Container Federated Module: Consume and Render the exposed components by the Remote Federated Module.
Step by Step
Create two react applications, one for host (Shop-container) and other for remote(product) using below command
- Shop-container
npx create-react-app shop-container
- Product
npx create-react-app product
Install Webpack in both applications
npm i webpack webpack-dev-server webpack-cli css-loader
html-webpack-plugin sass sass-loader style-loader url-loader
@babel/core @babel/preset-env @babel/preset-react
babel-loader -D
Import Module Federation plugin as below
const ModuleFederationPlugin =
require("webpack/lib/container/ModuleFederationPlugin");
const dependencies = require("./package.json").dependencies;
Create webpack.config.js file under root folder of Product application and plugin module federations
- Product application
plugins: [
new HtmlWebpackPlugin({
template: "src/index.html",
}),
new ModuleFederationPlugin({
name: "product",
filename: "remoteEntry.js",
remotes: {},
exposes: {
'./App': './src/App.js',
},
shared: {
...dependencies,
react: {
singleton: true,
requiredVersion: dependencies.react,
},
"react-dom": {
singleton: true,
requiredVersion: dependencies["react-dom"],
},
},
})
]
Under ModuleFederationPlugin, few of the properties which are common in use
exposes: property is to expose the component which you want to share. If you share root components, all components will be loaded and route works the way it is.
shared: It is to include packages you needed when using this remote application. Suppose say, if you have angular as host/container application, remote is based on react, then it is where you include react packages to load the application. There are many benefits under the hood. some of them are singleton, avoid duplicate packages, loads missing packages and so on.
filename: This plugin generates file with the name mentioned here and renders the file dynamically at runtime.
Similarly create webpack.config.js file under root folder of Shop-container application and plugin module federations.
plugins: [
new ModuleFederationPlugin({
name: "shop-container",
remotes: {
product: "product@http://localhost:4500/remoteEntry.js"
},
exposes: {},
shared: {
...dependencies,
react: {
singleton: true,
requiredVersion: dependencies.react,
},
"react-dom": {
singleton: true,
requiredVersion: dependencies["react-dom"],
},
},
})
]
- remotes: It is to mention all remote applications url along with filename. Here, shop-container application consumes Product application.
Now import product component and render the remote content as below
import Product from 'product/App';
const App = () => {
return (
<>
<Header></Header>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Product />} />
</Routes>
<Footer></Footer>
</>
);
}
export default App;
use key name which mentioned in remotes property inside webpack.config.js and import the component name.
import Product from 'product/App';
and use the component
Below are the screeshots of container and remote applications
- product application
- Shop-container Application
For Reference, complete source code is in below repository
[https://github.com/sandeep0515/microfrontends-react]
We can create independent repositories for each application, containerized the applications separately and maintain the code easily.
Happy coding!
Top comments (2)
Thank you for the post, I’ll surely try this include the dev/uat/prod setup too
Thank you for the post. Nice article