Modern.js
Este chapter explains como para usar o Module Federation plugin em Modern.js e fornece uma simple exemplo esse demonstrates como para criar provider e consumer aplicações.
Environment
Node.js
Antes getting started, você vai precisa instale Node.js, e ensure esse seu Node.js versão é no lower than v20.19.5. We recommend usando o LTS versão de Node.js 22.
Você pode check o currently usado Node.js versão com o seguintes comando:
Se você não have Node.js installed em your current environment, ou o installed versão é lower than v20.19.5, você pode use nvm ou fnm para instalar o obrigatório versão.
Here é um exemplo de como para instalar o Node.js 22 LTS versão via nvm:
# Install the long-term support version of Node.js 22
nvm install 22 --lts
# Make the newly installed Node.js 22 as the default version
nvm alias default 22
# Switch to the newly installed Node.js 22
nvm use 22
nvm and fnm
Both nvm e fnm são Node.js versão management tools. Relatively speaking, nvm é mais mature e stable, enquanto fnm é implemented usando Rust, que fornece better performance than nvm.
pnpm
It é recomendado para usar pnpm para manage dependências:
Note
Modern.js também suporta dependência management com yarn e npm.
Crie Project
@modern-js/create fornece um interactive Q&A interface para initialize o projeto based no results, com initialization performed according para o padrão settings:
Crie consumer
npx @modern-js/create@latest modern-consumer
Crie provider
npx @modern-js/create@latest modern-provider
Instale plugins
Module Federation fornece uma matching plugin @module-federation/modern-js-v3 for Modern.js.
pnpm add @module-federation/modern-js-v3
Provider
1. Crie configuração arquivo
Crie uma module-federation.config.ts arquivo no projeto root diretório e write o seguintes content:
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. Apply plugin
Apply @module-federation/modern-js-v3 em 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. Crie precisa ser exposto componente
Crie o arquivo src/components/Image.tsx com o seguintes content:
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>
);
E crie o corresponding style arquivo, o content é as follows:
Image.module.css
.button {
background: red;
}
Consumer
1. Crie configuração arquivo
Crie uma module-federation.config.ts arquivo no projeto root diretório e write o seguintes content:
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. Apply plugin
Apply @module-federation/modern-js-v3 em 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. Tipo hint
Add paths em tsconfig.json para get o producer's tipo:
{
"compilerOptions": {
"paths": {
"*": ["./@mf-types/*"]
}
}
}
4. Consuma provider
Modify o entry page (src/routes/page.tsx) e reference o componentes fornecido pelo producer. O content é as follows:
page.tsx
import ProviderImage from 'remote/Image';
import './index.css';
const Index = () => (
<div className="container-box">
<ProviderImage />
</div>
);
export default Index;
CSS flickering issue
Start o projeto e visit http://localhost:3007/ e find esse SSR é working normally e o page pode ser rendered normally, but there vai ser uma problem de style flickering. Este é porque o producer's style arquivos cannot ser injected no corresponding HTML. Este issue pode ser resolved com createLazyComponent.
Modify o consumer code esse references o 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;
Depois modifying o page e revisiting it, você pode observe esse o retornado html vai ser automatically injected com o producer's style arquivo, thereby solving o CSS flickering problem.