Generates type-safe Microfrontend Renderers, Starters and Host Integrations from an OpenMicrofrontends description.
Note
This generator does currently not support importMaps for ES modules, since the Browser support is incomplete (see https://bugzilla.mozilla.org/show_bug.cgi?id=1916277). For the moment we recommend using SystemJS in conjunction with importMaps.
- Node.js >= 20
- Node.js >= 20
- devDependencies
- @open-microfrontends/types
- Some Templates might require additional dependencies, see below
- Java >= 17
- Some Templates might require additional runtime dependencies, see below
Add to your package.json:
{
"devDependencies": {
"@open-microfrontends/types": "^1.0.0",
"@open-microfrontends/generator": "^1.0.0"
}
}To generate code run:
omg <descriptionFile> <outFolder> -t <template1>,<template2>
Example:
omg microfrontends.yaml src/_generated -t renderers
Arguments:
- descriptionFile: The OpenMicrofrontends description (yaml/json)
- outFolder: The target folder for generated code (not required for --validationOnly)
Options:
| Option | Description |
|---|---|
| -t, --templates | A comma separated list of templates to use |
| -a, --additionalProperties | A comma separated list of extra properties to pass to the templates |
| -v, --validationOnly | Only validate given spec file and exit |
| --help | Usage info |
| Template | Description |
|---|---|
| renderers | Client-side Renderers for the Microfrontends server |
| renderersServerSide | Server-side Renderers for the Microfrontends server |
| startersBrowserStandalone | Starters for a plain HTML Host Application |
| starters | Full Starters for a Host Application with backend integration (security, proxying, SSR) |
| hostBackendIntegrationsNodeJs | Host Application backend integrations for a Node.js backend |
| hostBackendIntegrationsJavaServlet | Host Application backend integrations for a Java-based backend |
Generates a microfrontendRenderers.ts file that contains the client-side Renderers that need to be implemented. The generated code is plain JavaScript and does not depend on any libraries.
Add this to the index file of your Microfrontend:
import {MyFirstMicrofrontendRenderer, MyFirstMicrofrontendRendererFunctionName} from './_generated/microfrontendsRenderers';
const rendererFn: MyFirstMicrofrontendRenderer = async (host, context) => {
const {config, messageBus} = context;
host.innerHTML = '<div>My Microfrontend 1</div>';
return {
onRemove: () => {
// ...
}
}
};
// If you bundle your code to ESM oder SystemJS
export default {
[MyFirstMicrofrontendRendererFunctionName]: rendererFn,
};
// Or otherwise (this always works)
// window[MyFirstMicrofrontendRendererFunctionName] = rendererFn;This template also creates useful constants for paths that can be used on the server like this:
import {MyMicrofrontendAssetsBasePath} from '../_generated/microfrontendRenderers';
const app = express();
// ...
app.use(MyMicrofrontendAssetsBasePath, express.static(resolve(serverDir, 'public')));Generates a microfrontendRenderersServerSide.ts file that contains the server-side Renderers that need to be implemented. The generated code is plain JavaScript and does not depend on any libraries.
- Implement the server-side Renderer
// renderMicrofrontend.ts
import type {MyFirstMicrofrontendServerSideRenderer} from "../_generated/microfrontendRenderersServerSide";
import Microfrontend from "../Microfrontend.vue";
const renderer: MyFirstMicrofrontendServerSideRenderer = async (requestBody) => {
const { id, config } = requestBody;
const html = /* render your Microfrontend here */ '';
return {
html,
};
};
export default renderer;- Implement the route (depends on the framework you are using, in this example we use Express)
// ssrRoute.ts
import type {Request, Response} from 'express';
import renderMicrofrontend from '../renderMicrofrontend';
export default async (req: Request, res: Response) => {
try {
const response = await renderMicrofrontend(req.body);
res.json(response);
} catch (e: any) {
console.error('Server-side rendering failed!', e),
res.sendStatus(500);
}
}- Add the route under the correct path
import {MyFirstMicrofrontendServerSideRendererPath} from '../_generated/microfrontendRenderersServerSide';
import ssrRoute from './ssrRoute';
const app = express();
app.use(express.json());
app.post(MyFirstMicrofrontendServerSideRendererPath, ssrRoute);Generates a microfrontendStarters.ts file that contains functions to launch the Microfrontends on an arbitrary HTML page.
Important
This template does not fully support the OpenMicrofrontends specification, in particular it does not support API proxies, some security aspects or SSR. So, it is only suitable for Microfrontends that don't need any of those features.
Note
This template uses a very basic cache busting mechanism by just appending the timestamp to every JS and CSS asset. It sets the last digit of the timestamp seconds to 0, so the browser will cache the files for 10 seconds at max.
import {startMyFirstMicrofrontend} from './_generated/microfrontendClients';
const hostElement = document.getElementById('root');
const {close, messages} = await startMyFirstMicrofrontend('https://my-microfrontend-server.com', hostElement, {
id: '1',
// lang: 'en',
// user,
config: {
welcomeMessage: 'Microfrontend Demo!',
},
messageBus,
});
// Send a message to the Microfrontend
messages.publish('topic', {});Generates a microfrontendStarters.ts file that contains functions to launch the Microfrontends in the frontend of the Host Application. This template requires the backend code from one of the hostBackendIntegrationsXXX templates (below) to function properly.
| Property | Description |
|---|---|
| omBasePath | The base path of OpenMicrofrontends integrations. Default: /__om__ |
import {startMyFirstMicrofrontend} from './_generated/microfrontendClients';
const hostElement = document.getElementById('root');
const {close, messages} = await startMyFirstMicrofrontend(hostElement, {
id: '1',
// lang, user, permissions, apiProxyPaths are provided by the backend integration
config: {
welcomeMessage: 'Microfrontend Demo!',
},
messageBus,
});
// Send a message to the Microfrontend
messages.publish('topic', {});Generates a microfrontendHostIntegrations.ts file that contains backend integrations for Node.js-based Host Applications, including security, proxying and SSR.
It creates a middleware per Microfrontend that can be integrated into any backend framework (like Express, Fastify, etc.);
| Property | Description |
|---|---|
| omBasePath | The base path of OpenMicrofrontends integrations. Default: /__om__ |
First, implement the generated <Micfrontend-Name>BaseSetup interface generated for each Microfrontend:
import {MyMicrofrontendBaseSetup} from './_generated/microfrontendHostIntegrations';
export default class MyMicrofrontendBaseSetupImpl implements MyMicrofrontendBaseSetup {
get microfrontendBaseUrl() {
return 'http://localhost:7830'
};
async getUser(req: IncomingMessage) {
// TODO
return null;
}
// Other generated methods
}Then, add the generated middleware. For example, with Express:
import {myMicrofrontendHostIntegrationMiddleware} from './_generated/microfrontendHostIntegrations';
const app = express();
// ...
app.use(myMicrofrontendHostIntegrationMiddleware(
new MyMicrofrontendBaseSetupImpl()
));After this, you can start the Microfrontend with the functions generated by the starters template.
If the Microfrontend supports SSR, you can fetch the server-side rendered HTML and add it to the page. With Express this would look like this:
import {myMicrofrontendServerSideRender} from './_generated/microfrontendHostIntegrations';
app.get('index', async (req, res) => {
try {
const {contentHtml, headHtml} = await myMicrofrontendServerSideRender(req, {
id: '1',
// lang, user, permissions
config: {
welcomeMessage: 'Microfrontend Demo!',
},
});
return res.render('index', {
microfrontend1ContentHtml: contentHtml,
microfrontend1HeadHtml: headHtml,
});
} catch (e) {
// TODO
}
});And in the template:
<html>
<head>
<%-microfrontend1HeadHtml%>
</head>
<body>
<h1>Microfrontend Host Application</h1>
<!-- Important: There should be no whitespace between the div and pre-rendered content -->
<div id="root"><%-microfrontend1ContentHtml%></div>
<!-- Script that starts the Microfrontend -->
<script src="main.js"></script>
</body>
</html>The template also generates a constant with the Annotations in the Microfrontend description (if any). It can be used in the Host Application logic.
Generates an OpenMicrofrontendHostIntegrations.java file that contains backend integrations for Java Servlet-based Host Applications, including security and proxying.
It creates a Filter per Microfrontend that can be integrated into any backend framework that supports Java Servlets (like Spring Boot, etc.);
Note
The main purpose of this template is to demonstrate that a backend integration is possible in arbitrary languages. It is not fully type-safe, and SSR is not supported (at the moment).
| Property | Description |
|---|---|
| omBasePath | The base path of OpenMicrofrontends integrations. Default: /__om__ |
| packageName | The Java package (default: _generated) |
First, implement the generated <Micfrontend-Name>BaseSetup interface generated for each Microfrontend:
import _generated.OpenMicrofrontendHostIntegrations;
public class MyMicrofrontendBaseSetupImpl implements OpenMicrofrontendHostIntegrations.MyMicrofrontendHostIntegrationFilter.MicrofrontendBaseSetup {
@Override
public String getMicrofrontendBaseUrl() {
return "http://localhost:7830";
}
@Override
public OpenMicrofrontendHostIntegrations.User getUser(HttpServletRequest req) {
// TODO
return null;
}
// Other generated methods
}Then, add the generated Servlet Filter. For example, with Spring Boot:
import _generated.OpenMicrofrontendHostIntegrations;
@SpringBootApplication
public class HostIntegrationDemoApplication {
// ...
@Bean
public Filter createMyMicrofrontendFilter() {
return new OpenMicrofrontendHostIntegrations.MyMicrofrontendHostIntegrationFilter(new MyMicrofrontendBaseSetupImpl());
}
}After this, you can start the Microfrontend with the functions generated by the starters template.
In this repository you can find examples of Microfrontends and Host Applications which use this generator.
Any contribution is highly welcome!
You can contribute by
- Requesting new features
- Creating issues
- Submitting pull requests