11 min read
ā¢Question 43 of 47hardMicro-Frontends with Next.js
Implementing micro-frontend architecture.
Micro-Frontends
Module Federation
code.txtTSX
// next.config.js (host)
const NextFederationPlugin = require('@module-federation/nextjs-mf');
module.exports = {
webpack(config, options) {
config.plugins.push(
new NextFederationPlugin({
name: 'host',
remotes: {
shop: 'shop@http://localhost:3001/_next/static/chunks/remoteEntry.js',
blog: 'blog@http://localhost:3002/_next/static/chunks/remoteEntry.js',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
})
);
return config;
},
};
// Using remote component
const RemoteShop = dynamic(() => import('shop/ProductList'), {
ssr: false,
});
export default function Page() {
return <RemoteShop />;
}Multi-Zone Deployment
code.txtTSX
// Main app - next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/blog/:path*',
destination: 'https://blog.example.com/:path*',
},
{
source: '/shop/:path*',
destination: 'https://shop.example.com/:path*',
},
];
},
};
// Each zone is a separate Next.js app
// with its own deploymentIframe Isolation
code.txtTSX
// For complete isolation
export function MicroFrontend({ src }: { src: string }) {
return (
<iframe
src={src}
style={{ width: '100%', height: '100vh', border: 'none' }}
sandbox="allow-scripts allow-same-origin allow-forms"
/>
);
}
// Communication via postMessage
window.parent.postMessage({ type: 'navigate', url: '/checkout' }, '*');Shared Component Library
code.txtTSX
// packages/ui/Button.tsx
export function Button({ children, ...props }) {
return <button className="btn-primary" {...props}>{children}</button>;
}
// In each micro-frontend
import { Button } from '@company/ui';