Creating a micro-frontend blackbox with React
Blackbox pattern is a pattern developed to solve a lot of issues that usually come up in MFE development.
You can find more here:
https://medium.com/@naimgaberlo/micro-frontend-blackbox-pattern-295c40b681e4
In this post, we are going to make a deep-dive in blackboxes by going through a step by step guide using React and Webpack.
Source can be found at the end of the article. So here we go…
Step 1 - Create a React Typescript app
Steps detailed here:
https://create-react-app.dev/docs/adding-typescript/
Step 2 - Eject React app to create custom webpack build
npm run eject
Step 3 - Create vanilla.tsx
vanilla.tsx is the file which performs the following:
- Create a React renderer for vanilla JS
- Register basic React’s lifecycle events to window
- “Listen” to caller MFE’s ‘openBlackbox’ custom event to render itself on DOM element set in “init” function
import React from "react";import ReactDOM from "react-dom";import App from "./App";// buffer of DOM elements rendering React componentslet nodes: Element[] = [];let hostElement: Element;const reactContentRenderer = {unmountAll: () => {if (nodes.length === 0) {return;}nodes.forEach((node) => ReactDOM.unmountComponentAtNode(node));nodes = [];},unmount: (node: Element) => {ReactDOM.unmountComponentAtNode(node);},init: (targetNode: Element) => {hostElement = targetNode;},render: (props: any, callback: () => void) => {const reactElement = React.createElement(App, props, null);ReactDOM.render(reactElement as any, hostElement, callback);nodes.push(hostElement);return reactElement;},};//register self as window propertywindow["blackbox"] = reactContentRenderer;//and listen to window custom event//which will be invoked via caller MFEwindow.addEventListener("openBlackbox",(e: any) => {const eventDetail = e.detail;console.log("Blackbox open with payload", eventDetail);reactContentRenderer.render(eventDetail, () => {});},false);
Step 4 - Custom webpack build
- Create webpack.vanilla.config.js (a copy of existing webpack.config.js)
- Change the webpack.vanilla.config.js entry:
entry: './src/vanilla.tsx'
- and output:
path: path.resolve(__dirname, '../build')
filename: 'blackbox.js'
- remove splitChunks & runtimeChunk in case you need a single file as output
Step 5 - Custom build-vanilla.js
ConfigFactory variable should be changed to point to freshly created webpack.vanilla.config.js
const configFactory = require('../config/webpack.vanilla.config');
Step 6 - Fix tsconfig.json
Add the following compilerOption in tsconfig.json to suppress any array index(by default number is expected)
“suppressImplicitAnyIndexErrors”: true
Step 7 - Add build:vanilla to package.json and run
In package.json add the following in scripts line:
"build:vanilla": "node scripts/build-vanilla.js"
… and run
npm run build:vanilla
Step 8 - Ready to test!
Run the following in terminal:
cd build
serve -s
The above will serve static files produced as output of step 7.
In your browser if you open the url provided by serve’s output , you will see a blank screen.
To invoke your blackbox from the browser’s console run the following two commands in your developer tool’s console:
window["blackbox"].init(document.getElementById("root"));
window.dispatchEvent(new CustomEvent('openBlackbox',{detail:{test:'string'}}));
Result should be the following
Step 9 - Create a custom event to be subscribed by host
In case you want to be ready for next post, blackbox should dispatch its own “finish” event as described in blackbox pattern.
In order to do so , simply add paste the following in “App.tsx”
import React from "react";import "./App.css";function App() {const closeBlackbox = () => {const event = new CustomEvent("blackboxClosed", {detail: { type: "edit" },bubbles: true,});window.dispatchEvent(event);};return (<div className="App"><header className="App-header"><button onClick={closeBlackbox}>Close blackbox</button></header></div>);}export default App;
In our MFE host we will subscribe to this event to listen to updates from our blackbox. More details in next post ;)
Last words
This is it for today!
In the next post we will create a MFE based app to handle our blackbox using single-spa framework!
As promised, source code can be found in the following repo:
https://github.com/ngkamperlo/blackbox
Thanks for reading and happy coding guys!