Modern.js
Este capítulo explica cómo usar el plugin de Module Federation en Modern.js e incluye un ejemplo sencillo que muestra cómo crear aplicaciones provider y consumer.
Entorno
Node.js
Antes de empezar, necesitas instalar Node.js y asegurarte de que tu versión de Node.js no sea inferior a v20.19.5. Recomendamos usar la versión LTS de Node.js 24.
Puedes comprobar la versión de Node.js que estás usando con el siguiente comando:
Si no tienes Node.js instalado en tu entorno actual, o la versión instalada es inferior a v20.19.5, puedes usar nvm o fnm para instalar la versión necesaria.
Este es un ejemplo de cómo instalar la versión LTS de Node.js 24 mediante nvm:
# Install the long-term support version of Node.js 24
nvm install 24 --lts
# Make the newly installed Node.js 24 as the default version
nvm alias default 24
# Switch to the newly installed Node.js 24
nvm use 24
nvm y fnm
Tanto nvm como fnm son herramientas de gestión de versiones de Node.js. En términos relativos, nvm es más maduro y estable, mientras que fnm está implementado en Rust, lo que le da un mejor rendimiento que nvm.
pnpm
Se recomienda usar pnpm para gestionar las dependencias:
Note
Modern.js también admite la gestión de dependencias con yarn y npm.
Crear el proyecto
@modern-js/create ofrece una interfaz interactiva de preguntas y respuestas para inicializar el proyecto según tus respuestas, con la inicialización basada en la configuración por defecto:
Crear el consumer
npx @modern-js/create@latest modern-consumer
Crear el provider
npx @modern-js/create@latest modern-provider
Instalar los plugins
Module Federation proporciona el plugin @module-federation/modern-js-v3 para Modern.js.
pnpm add @module-federation/modern-js-v3
Configurar Module Federation
Provider
1. Crear el archivo de configuración
Crea un archivo module-federation.config.ts en el directorio raíz del proyecto con el siguiente contenido:
module-federation.config.ts
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
export default createModuleFederationConfig({
name: 'provider',
filename: 'remoteEntry.js',
exposes: {
'./Image': './src/components/Image.tsx',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
});
2. Aplicar el plugin
Aplica @module-federation/modern-js-v3 en modern.config.ts :
modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
// https://modernjs.dev/en/configure/app/usage
export default defineConfig({
server: {
ssr: {
mode: 'stream',
},
port: 3006,
},
plugins: [appTools(), moduleFederationPlugin()],
});
3. Crear el componente que se va a exponer
Crea el archivo src/components/Image.tsx con el siguiente contenido:
Image.tsx
import React from 'react';
import styles from './Image.module.css';
export default (): JSX.Element => (
<div
id="remote-components"
style={{
backgroundColor: '#1ee9c1',
color: 'lightgrey',
padding: '1rem',
}}
>
<h2>
<strong>remote</strong> image
</h2>
<button
id="remote-components-button"
style={{ marginBottom: '1rem' }}
onClick={() => alert('[remote-components] Client side Javascript works!')}
>
Click me to test i'm interactive!
</button>
<img
id="remote-components-image"
src="https://module-federation.io/module-federation-logo.svg"
style={{ width: '100px' }}
alt="serge"
/>
<button className={styles['button']}>Button from remote</button>
</div>
);
Y crea el archivo de estilos correspondiente con el siguiente contenido:
Image.module.css
.button {
background: red;
}
Consumer
1. Crear el archivo de configuración
Crea un archivo module-federation.config.ts en el directorio raíz del proyecto con el siguiente contenido:
module-federation.config.ts
import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
export default createModuleFederationConfig({
name: 'consumer',
remotes: {
remote: 'provider@http://localhost:3006/mf-manifest.json',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
});
2. Aplicar el plugin
Aplica @module-federation/modern-js-v3 en modern.config.ts:
modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
// https://modernjs.dev/en/configure/app/usage
export default defineConfig({
server: {
ssr: {
mode: 'stream',
},
port: 3007,
},
plugins: [appTools(), moduleFederationPlugin()],
});
3. Sugerencias de tipos
Añade paths en tsconfig.json para obtener los tipos del producer:
{
"compilerOptions": {
"paths": {
"*": ["./@mf-types/*"]
}
}
}
4. Consumir el provider
Modifica la página de entrada (src/routes/page.tsx) y referencia los componentes que proporciona el producer. El contenido es el siguiente:
page.tsx
import ProviderImage from 'remote/Image';
import './index.css';
const Index = () => (
<div className="container-box">
<ProviderImage />
</div>
);
export default Index;
Problema de parpadeo de CSS
Arranca el proyecto y visita http://localhost:3007/: verás que el SSR funciona con normalidad y la página se renderiza correctamente, pero aparece un problema de parpadeo de estilos. Esto se debe a que los archivos de estilos del producer no pueden inyectarse en el HTML correspondiente. Este problema se puede resolver con createLazyComponent.
Modifica el código del consumer que referencia al producer:
src/routes/page.tsx
import { getInstance } from '@module-federation/modern-js-v3/runtime';
import { lazyLoadComponentPlugin } from '@module-federation/modern-js-v3/data-fetch';
import './index.css';
const instance = getInstance();
instance.registerPlugins([lazyLoadComponentPlugin()]);
const RemoteSSRComponent = instance.createLazyComponent({
loader: () => import('remote/Image'),
loading: 'loading...',
export: 'default',
fallback: ({ error }) => {
if (error instanceof Error && error.message.includes('not exist')) {
return <div>fallback - not existed id</div>;
}
return <div>fallback</div>;
},
});
const Index = () => (
<div className="container-box">
<RemoteSSRComponent />
</div>
);
export default Index;
Tras modificar la página y volver a visitarla, verás que el HTML devuelto incluye automáticamente el archivo de estilos del producer, lo que resuelve el problema de parpadeo de CSS.