
In 2019, I was very frustrated with Microservices architecture, and my colleague who was a frontend developer laugh at me because I was the only a developer in that team who worked on all 10 services one by one or simultaneously.
The year 2019 was starting off my professional career but I tried my best to understand microservices architecture and successfully built 10 microservices using Node.js.
I was the only backend engineer in our team and I also decided to search the same architecture for frontend then I discovered “Microfrontends” and show this architecture to the frontend developer, I said “You should implement this” but he never did.
Setup
npm i -g create-react-app // Installating globally
npm create-react-app app-container // Installing main container
npm create-react-app micro-frontend // Installing 1st frontend
npm create-react-app micro-frontend1 // Installing 2nd frontend
npm create-react-app micro-frontend2 // Installing 3rd frontend
In the first command, we are installing create-react-app
boilerplate globally within our system then we are installing app-container which will render itself frontend 1,2,3.
Note: The setup below will be the same for all boilerplates except for the app-container.
Within all of these boilerplates install react-app-rewired using npm
. We are using it because we need to change configuration without eject.
npm i react-app-rewired --save // This will also save module in package.json dependencies
Now we need to replace react-scripts to react-app-rewired
in package.json
scripts.
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
}
Last but not least we need to a new file within the src
directory in all boilerplates config-overrides.js
module.exports = {
webpack: (config, env) => {
config.optimization.runtimeChunk = false;
config.optimization.splitChunks = {
cacheGroups: {
default: false,
},
};
return config;
},
};
This code means that we are saying webpack that don’t cache stuff, but if you are more interested in caching you can start all frontend using react-scripts
without adding the config-overides.js
file.
Add setupProxy.js
file in src to set up a proxy for all micro-frontends.
module.exports = app => {
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
};
Update index.js
file in src in all micro-frontends.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// render micro frontend function
window.rendercreatereactapp = (containerId, history) => {
ReactDOM.render( <
App history = {
history
}
/>,
document.getElementById(containerId)
);
serviceWorker.unregister();
};
// unmount micro frontend function
window.unmountcreatereactapp = containerId => {
ReactDOM.unmountComponentAtNode(document.getElementById(containerId));
};
// Mount to root if it is not a micro frontend
if (!document.getElementById('createreactapp-container')) {
ReactDOM.render( < App / > , document.getElementById('root'));
}
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
Implementation
Now we will implement and run each and every “micro frontend” one by one and within the app container.
1: Micro-Frontend
This is our first micro frontend boilerplate we need to update a few things within it.
Update App.js
in the src directory with this code, according to this code we will render a logo with “I am a Micro Frontend” text.
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className = "App" >
<header className = "App-header" >
<img src = {`${process.env.REACT_APP_CONTENT_HOST}${logo}`} className = "App-logo" alt = "logo" / >
<p>I am Micro Frontend. </p>
<a className = "App-link" href = "https://reactjs.org" target = "_blank" rel = "noopener noreferrer">Learn React </a>
</header>
</div>
);
}
export default App;
Create a .env
file in the main directory of this boilerplate.
REACT_APP_CONTENT_HOST=http://localhost:4000
PORT = 4000
Then run npm start
to start React.js frontend using node and npm.
Output:

Note: Don’t turn it off we will later render it in the app-container.
2: Micro-Frontend2
This is our second micro frontend boilerplate we need to update a few things within it.
Update App.js
in the src directory with this code, according to this code we will render a logo with “I am a Micro Frontend 2” text.
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className = "App" >
<header className = "App-header" >
<img
src = {
`${process.env.REACT_APP_CONTENT_HOST}${logo}`
}
className = "App-logo"
alt = "logo" / >
<p>I am Micro Frontend 2. </p>
<a className = "App-link" href = "https://reactjs.org" target = "_blank" rel = "noopener noreferrer" >Learn React </a>
</header>
</div>
);
}
export default App;
Create a .env
file in the main directory of this boilerplate.
REACT_APP_CONTENT_HOST=http://localhost:4002
PORT=4002
Then run npm start
to start React.js frontend using node and npm.
Output:

Note: Don’t turn it off we will later render it in the app-container.
3: Micro-Frontend3
This is our last micro frontend boilerplate we need to update a few things within it.
Update App.js
in the src directory with this code, according to this code we will render a logo with “I am a Micro Frontend 3” text.
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className = "App" >
<header className = "App-header" >
<img src = {
`${process.env.REACT_APP_CONTENT_HOST}${logo}`
}
className = "App-logo"
alt = "logo" / >
<p>I am Micro Frontend 3. </p>
<a className = "App-link" href = "https://reactjs.org" target = "_blank" rel = "noopener noreferrer" >Learn React </a>
</header>
</div>
);
}
export default App;
Create a .env
file in the main directory of this boilerplate.
REACT_APP_CONTENT_HOST=http://localhost:4003
PORT=4003
Then run npm start
to start React.js frontend using node and npm.

Note: Don’t turn it off we will later render it in the app-container.
4: App-Container
This is our main app-container
boilerplate we need to update a few things within it.
You need to install react-router-dom for routing.
Update App.js in the src
directory with this code, we are rendering all “micro frontends” by using different link tags and NavLink.
mport React from 'react';
import {
NavLink,
BrowserRouter,
Route,
Switch
} from 'react-router-dom';
import MicroFrontend from './MicroFrontend';
const {
REACT_APP_CREATEREACTAPP_HOST: createreactappHost,
REACT_APP_CREATEREACTAPP2_HOST: createreactapp2Host,
REACT_APP_CREATEREACTAPP3_HOST: createreactapp3Host
} = process.env;
const CreateReactApp = ({
history
}) => ( <
MicroFrontend history = {
history
}
host = {
createreactappHost
}
name = "createreactapp" /
>
);
const CreateReactApp2 = ({
history
}) => ( <
MicroFrontend history = {
history
}
host = {
createreactapp2Host
}
name = "createreactapp2" /
>
);
const CreateReactApp3 = ({
history
}) => ( <
MicroFrontend history = {
history
}
host = {
createreactapp3Host
}
name = "createreactapp3" /
>
);
const Home = () => (
<>
<p>
What is a micro front - ends approach ? The term micro front - ends first came up in the ThoughtWorks Technology Radar in November 2016. It extends the concepts of microservices to front - end development.
</p>
<p>
The approach is to split the browser - based code into micro front - ends by breaking down application features.By making smaller and feature - centered codebases, we achieve the software development goal of decoupling.
</p>
<p>
Although the codebases are decoupled, the user experiences are coherent.In addition, each codebase can be implemented, upgraded, updated, and deployed independently.
</p>
<p>
Here is the paradise of micro front - ends.JavaScript applications,
regardless of frameworks and versions, are launched by a container.These applications, legacy and new, work together seamlessly, and act like one application.
</p>
</>
);
const App = props => {
return (
<BrowserRouter >
<h1>This is an example of micro frontend.</h1>
<p>
I am an App Container. < br / >
In the links below, Home is a component bundled with the App Container.We have three Micro Frontends: Create React App, Create React App2, and Create React App3.
</p>
<ul>
<li>
<NavLink to = "/home" > Home < /NavLink>
</li>
<li>
<NavLink to = "/createreactapp" >Micro Frontend: Create React App </NavLink>
</li>
<li>
<NavLink to = "/createreactapp2" >Micro Frontend: Create React App 2 </NavLink>
</li>
<li>
<NavLink to = "/createreactapp3" > Micro Frontend: Create React App 3 < /NavLink>
</li>
</ul>
<Switch>
<Route
path = "/home"
component = {
Home
}
/>
<Route
path = "/createreactapp"
render = {
() => < CreateReactApp / >
}
/>
<Route
path="/createreactapp2"
render={() => <CreateReactApp2 />}
/>
<Route
path=" / createreactapp3 "
render={() => <CreateReactApp3 />}
/>
</Switch>
</BrowserRouter>
);
};
export default App;
Create a Microfrontend.js file in the src directory of this boilerplate.
In this file, we are getting assets and builds of micro frontend to render them on the main app-container.
import React from 'react';
class MicroFrontend extends React.Component {
componentDidMount() {
const {
name,
host,
document
} = this.props;
const scriptId = `micro-frontend-script-${name}`;
if (document.getElementById(scriptId)) {
this.renderMicroFrontend();
return;
}
fetch(`${host}/asset-manifest.json`)
.then(res => res.json())
.then(manifest => {
const script = document.createElement('script');
script.id = scriptId;
script.crossOrigin = '';
script.src = `${host}${manifest['files']['main.js']}`;
script.onload = this.renderMicroFrontend;
document.head.appendChild(script);
});
}
componentWillUnmount() {
const {
name,
window
} = this.props;
window[`unmount${name}`] && window[`unmount${name}`](`${name}-container`);
}
renderMicroFrontend = () => {
const {
name,
window,
history
} = this.props;
window[`render${name}`] && window[`render${name}`](`${name}-container`, history);
};
render() {
return ;
}
}
MicroFrontend.defaultProps = {
document,
window,
};
export default MicroFrontend;
Create a .env
file in the main directory of this boilerplate.
REACT_APP_CREATEREACTAPP_HOST=http://localhost:4000
REACT_APP_CREATEREACTAPP2_HOST=http://localhost:4002
REACT_APP_CREATEREACTAPP3_HOST=http://localhost:4003
Then run npm start
to start React.js frontend using node and npm.
Output:

As you can see in the above gif, the hello section is coming from the main app-container
while other sections are coming from “Microfrontends”.
Conclusion
In this article, we learned to implement Microfrontend architecture by using React.js only, so if you are interested to experiment more then I will suggest you try multiple languages i.e Angular, Vue, and React.