Skip to content

Instantly share code, notes, and snippets.

@anatooly
Last active October 14, 2025 06:53
Show Gist options
  • Select an option

  • Save anatooly/7dc2ebd4545bfec969aeb500cdc6da03 to your computer and use it in GitHub Desktop.

Select an option

Save anatooly/7dc2ebd4545bfec969aeb500cdc6da03 to your computer and use it in GitHub Desktop.
Micro frontend custom
"use client";
import MicroFrontendLoader from "../MicroFrontendLoader";
export const ExampleWidget = () => {
const { theme } = useTheme();
const opts = {
theme: ",
userId: "",
onCallGetUser: async () => {
return { name: "" }
},
};
return (
<MicroFrontendLoader
url="http://localhost:3001/micro-app.js"
componentName="ExampleApp"
props={opts}
/>
);
};
"use client";
import * as _jsxruntime from "react/jsx-runtime";
import React from "react";
import ReactDOM from "react-dom/client";
if (typeof window !== "undefined") {
window.React = React;
window.ReactDOM = ReactDOM;
window.ReactJSXRuntime = _jsxruntime;
}
export default function JsxRuntimeProvider() {
return null;
}
"use client";
import { useEffect, useRef } from "react";
export default function MicroFrontendLoader({
url,
componentName,
props = {},
}) {
const containerRef = useRef(null);
useEffect(() => {
if (!containerRef.current) return;
let script = Array.from(document.scripts).find((s) => s.src === url);
const mountComponent = () => {
if (window.mountMicroComponent) {
window.mountMicroComponent(containerRef.current, componentName, props);
}
};
if (script) {
mountComponent();
return;
}
script = document.createElement("script");
script.src = url;
script.async = true;
script.onload = () => {
mountComponent();
};
document.head.appendChild(script);
}, [url, componentName, props]);
return <div ref={containerRef} />;
}
export default function ExampleApp(props) {
const { theme, userId, onCallGetUser } = props ?? {};
return null;
}
import React from "react";
import ReactDOM from "react-dom/client";
import ExampleApp from "./components/ExampleApp";
if (import.meta.env.MODE === "development") {
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
} else {
const componentRegistry = { ExampleApp };
const mountedRoots = new Map();
window.mountMicroComponent = (container, componentName, props) => {
const ComponentToRender = componentRegistry[componentName];
console.log({ container, componentName, props });
if (!container || !ComponentToRender) {
console.error(`Component "${componentName}" not found.`);
return;
}
const rootElement = (
<React.StrictMode>
<ComponentToRender {...props} />
</React.StrictMode>
);
if (mountedRoots.has(container)) {
mountedRoots.get(container).render(rootElement);
} else {
const root = ReactDOM.createRoot(container);
mountedRoots.set(container, root);
root.render(rootElement);
}
};
window.unmountMicroComponent = (container) => {
if (mountedRoots.has(container)) {
mountedRoots.get(container).unmount();
mountedRoots.delete(container);
}
};
}
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
base: "http://localhost:3001/",
plugins: [react()],
build: {
rollupOptions: {
// Not include all React core lib in result build
external: ["react", "react-dom/client", "react/jsx-runtime"],
output: {
globals: {
react: "React",
"react-dom/client": "ReactDOM",
"react/jsx-runtime": "ReactJSXRuntime",
},
format: "iife",
entryFileNames: "micro-app.js",
assetFileNames: `[name].[ext]`,
},
},
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment