React: Micro Frontend using Webpack 5 Module Federation
Yassine Sellami
Posted on October 2, 2022
In progress !!!!!!!!
Init projects
mkdir /opt/mfe
cd /opt/mfe
# create dashboard app
npx create-react-app dashboard-app --template typescript
# create profile app
npx create-react-app profile-app --template typescript
# create host app
npx create-react-app container --template typescript
Install dependencies
Add mui
npm install @mui/material @emotion/react @emotion/styled
npm install @fontsource/roboto
npm install @mui/icons-material
Add MFE dep
npm install --save-dev webpack webpack-cli webpack-merge
html-webpack-plugin webpack-dev-server
npm install --save-dev @babel/core @babel/eslint-parser @babel/plugin-transform-runtime @babel/preset-env @babel/preset-react @babel/preset-typescript @babel/runtime babel-loader css-loader postcss postcss-loader style-loader
Config
- Replace
index.tsx
withbootstrap.tsx
: - create file
./src/index.ts
:
import { createBrowserHistory, Update } from 'history';
import('./bootstrap').then(({ mount }) => {
const localRoot = document.getElementById('dashboardApp-local');
const browserHistory = createBrowserHistory();
mount({
mountPoint: localRoot!,
historyStrategy: browserHistory,
});
});
Add file .babelrc
:
vi .babelrc
----
{
"presets": [
"@babel/preset-typescript",
"@babel/preset-react",
"@babel/preset-env"
],
"plugins": [["@babel/transform-runtime"]]
}
Add file webpack.config.js
:
vi webpack.config.js
----
const HtmlWebPackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const deps = require('./package.json').dependencies;
module.exports = {
output: {
publicPath: 'http://localhost:8081/',
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
},
devServer: {
port: 8081,
historyApiFallback: true,
headers: {
'Access-Control-Allow-Origin': '*',
},
},
module: {
rules: [
{
test: /\.m?js/,
type: 'javascript/auto',
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'dashboard-app',
filename: 'remoteEntry.js',
remotes: {},
exposes: {
'./DashboardAppIndex': './src/bootstrap',
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
'react-dom': {
singleton: true,
requiredVersion: deps['react-dom'],
},
},
}),
new HtmlWebPackPlugin({
template: './src/index.html',
}),
],
};
- Replace run script:
"scripts": {
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"build:start": "cd dist && PORT=8082 npx serve",
"start": "webpack serve --open --mode development",
"start:live": "webpack serve --open --mode development --live-reload --hot"
},
- Webpack config for container:
const HtmlWebPackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const deps = require('./package.json').dependencies;
module.exports = {
output: {
publicPath: 'http://localhost:8080/',
},
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
},
devServer: {
port: 8080,
historyApiFallback: true,
headers: {
'Access-Control-Allow-Origin': '*',
},
},
module: {
rules: [
{
test: /\.m?js/,
type: 'javascript/auto',
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'container',
filename: 'remoteEntry.js',
remotes: {
dashboardApp: 'dashboardApp@http://localhost:8081/remoteEntry.js',
profileApp: 'profileApp@http://localhost:8082/remoteEntry.js',
},
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
'react-dom': {
singleton: true,
requiredVersion: deps['react-dom'],
},
},
}),
new HtmlWebPackPlugin({
template: './src/index.html',
}),
],
};
💖 💪 🙅 🚩
Yassine Sellami
Posted on October 2, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.