Building shell application for micro frontends
source link: https://www.softwarepark.cc/blog/2021/7/9/building-shell-application-for-micro-frontends
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Building shell application for micro frontends
In this post, we will create the last piece of our micro frontends with the design system PoC. We now have a design system, several micro frontends consuming this design system, and we need now a shell application that will import micro frontends and display them. This shell application will import micro frontends using script
tags and script URLs hardcoded in index.html
in the real project, it would be driven by some sort of configuration.
This series will not cover two aspects: module federation and mounting microseconds to isolated virtual DOM. Module federation helps to lower the size of included script by requesting modules, used by more than one micro frontend, only once. If we want to increase isolation between micro frontend we can create a web component that will mount micro frontend to isolated virtual dom.
Create directory fitness-portal-shell
in the same directory as design-system
and micro frontends. Run the following commands, from the new directory to setup project dependencies:
Now we need a few files.
Create file ./src/App.js
with the following content:
import React from "react"; import { hot } from "react-hot-loader/root"; import MicroFrontend from "./MicroFrontend";
class App extends React.Component { render() { return [ "nutritionPortal", // Uncomment following lines if you created additional micro frontends // "exercisePortal", // "mealsPlannerPortal", // "recipesPortal" ].map((name) => ( <MicroFrontend key={name} name={name}></MicroFrontend> )); } }
export default hot(App);
Create file ./src/MicroFrontend.js
with the following content:
import React, { Component } from 'react'
export default class MicroFrontend extends Component {
get containerId() { return `mf-${this.props.name}`; }
render() { return <div id={this.containerId}></div> }
componentDidMount() { window[`${this.props.name}Mount`](document.getElementById(this.containerId), {isStandAlone: false}) }
componentWillUnmount() { window[`${this.props.name}Unmount`](document.getElementById(this.containerId), {isStandAlone: false}) } }
Create file ./src/index.js
with the following content:
import React from "react"; import ReactDOM from "react-dom"; import App from "./App";
var mountNode = document.getElementById("app"); ReactDOM.render(<App />, mountNode);
Create file ./src/index.html
with the following content:
<!DOCTYPE html> <html>
<head> <meta charset="utf-8"> <title></title> <script defer="" src="http://localhost:7001/main.js" ></script> <script defer="" src="http://localhost:7001/vendors.js" ></script> <script defer="" src="http://localhost:7001/runtime.js" ></script> <link rel="stylesheet" href="http://localhost:7001/main.css">
<!-- Uncomment following lines if you created additional micro frontends -->
<!-- <script defer="" src="http://localhost:7002/main.js" ></script> <script defer="" src="http://localhost:7002/vendors.js" ></script> <script defer="" src="http://localhost:7002/runtime.js" ></script> <link rel="stylesheet" href="http://localhost:7002/main.css">
<script defer="" src="http://localhost:7003/main.js" ></script> <script defer="" src="http://localhost:7003/vendors.js" ></script> <script defer="" src="http://localhost:7003/runtime.js" ></script> <link rel="stylesheet" href="http://localhost:7003/main.css">
<script defer="" src="http://localhost:7004/main.js" ></script> <script defer="" src="http://localhost:7004/vendors.js" ></script> <script defer="" src="http://localhost:7004/runtime.js" ></script> <link rel="stylesheet" href="http://localhost:7004/main.css"> --> </head>
<body> <div id="app"></div>
</body>
</html>
This is a naive implementation where we hard-code links to micro frontends' resources in a real project it would come from the configuration.
No we will configure build.
Create file ./.bablrc
with the following content:
Create file ./webpack.config.js
with the following content:
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const config = { entry: ["react-hot-loader/patch", "./src/index.js"], output: { path: path.resolve(__dirname, "dist"), filename: "[name].js", }, module: { rules: [ { test: /\.(js|jsx)$/, use: "babel-loader", exclude: /node_modules/, }, { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, { loader: "css-loader", options: { importLoaders: 1, }, }, ], }, ], }, resolve: { extensions: [".js"], alias: { "react-dom": "@hot-loader/react-dom", }, }, devServer: { contentBase: "./src", watchContentBase: true, port: 7000, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS" }, }, plugins: [ new HtmlWebpackPlugin({ template: "./src/index.html", }), new MiniCssExtractPlugin(), ], optimization: { runtimeChunk: "single", splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all", }, }, }, }, };
module.exports = (env, argv) => { if (argv.hot) { // Cannot use 'contenthash' when hot reloading is enabled. config.output.filename = "[name].js"; }
return config; };
Open ./package.json
and add following script to scripts
section:
You should be able to build the shell app now. Run npm start
. It should bind to port 7000
. Remember to build and run micro frontends first.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK