Skip to content

Commit d362cdb

Browse files
authored
feat: support Module Federation format (#240)
Add format called 'mf' to build Module Federation assets and add example for both host and remote scene in rslib
1 parent 760968b commit d362cdb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1768
-36
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ test-results
1818
!.vscode/settings.json
1919
!.vscode/extensions.json
2020
.idea/
21-
.nx/
21+
.nx/
22+
**/@mf-types
23+
**/@mf-types/**
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Rsbuild Project
2+
3+
Module Federation Host Example
4+
5+
## Setup
6+
7+
Install the dependencies:
8+
9+
```bash
10+
pnpm install
11+
```
12+
13+
## Get Started
14+
15+
Start the dev server:
16+
17+
```bash
18+
pnpm dev
19+
```
20+
21+
Build the app for production:
22+
23+
```bash
24+
pnpm build
25+
```
26+
27+
Preview the production build locally:
28+
29+
```bash
30+
pnpm preview
31+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "@example/mf-host",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"build": "rsbuild build",
7+
"dev": "rsbuild dev",
8+
"preview": "rsbuild preview"
9+
},
10+
"dependencies": {
11+
"react": "^18.3.1",
12+
"react-dom": "^18.3.1"
13+
},
14+
"devDependencies": {
15+
"@module-federation/rsbuild-plugin": "^0.0.2",
16+
"@rsbuild/core": "~1.0.14",
17+
"@rsbuild/plugin-react": "^1.0.4",
18+
"@types/react": "^18.3.11",
19+
"@types/react-dom": "^18.3.1",
20+
"typescript": "^5.6.3"
21+
}
22+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
2+
import { defineConfig } from '@rsbuild/core';
3+
import { pluginReact } from '@rsbuild/plugin-react';
4+
5+
export default defineConfig({
6+
plugins: [
7+
pluginReact(),
8+
pluginModuleFederation({
9+
name: 'rsbuild_host',
10+
remotes: {
11+
rslib: 'rslib@http://localhost:3001/mf/mf-manifest.json',
12+
},
13+
shared: {
14+
react: {
15+
singleton: true,
16+
},
17+
'react-dom': {
18+
singleton: true,
19+
},
20+
},
21+
shareStrategy: 'loaded-first',
22+
}),
23+
],
24+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
body {
2+
margin: 0;
3+
color: #fff;
4+
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
5+
background-image: linear-gradient(to bottom, #020917, #101725);
6+
}
7+
8+
.content {
9+
display: flex;
10+
min-height: 100vh;
11+
line-height: 1.1;
12+
text-align: center;
13+
flex-direction: column;
14+
justify-content: center;
15+
}
16+
17+
.content h1 {
18+
font-size: 3.6rem;
19+
font-weight: 700;
20+
}
21+
22+
.content p {
23+
font-size: 1.2rem;
24+
font-weight: 400;
25+
opacity: 0.5;
26+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Counter } from 'rslib';
2+
import './App.css';
3+
4+
const App = () => {
5+
return (
6+
<div className="content">
7+
<Counter />
8+
<h1>Rsbuild with React</h1>
9+
<p>Start building amazing things with Rsbuild.</p>
10+
</div>
11+
);
12+
};
13+
14+
export default App;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom/client';
3+
import App from './App';
4+
5+
const rootEl = document.getElementById('root');
6+
if (rootEl) {
7+
const root = ReactDOM.createRoot(rootEl);
8+
root.render(
9+
<React.StrictMode>
10+
<App />
11+
</React.StrictMode>,
12+
);
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="@rsbuild/core/types" />
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import('./bootstrap');
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"lib": ["DOM", "ES2020"],
5+
"module": "ESNext",
6+
"jsx": "react-jsx",
7+
"noEmit": true,
8+
"strict": true,
9+
"skipLibCheck": true,
10+
"isolatedModules": true,
11+
"resolveJsonModule": true,
12+
"moduleResolution": "bundler",
13+
"useDefineForClassFields": true,
14+
"allowImportingTsExtensions": true,
15+
"paths": {
16+
"*": ["./@mf-types/*"]
17+
}
18+
},
19+
"include": ["src"]
20+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# @examples/mf-react-component
2+
3+
This example demonstrates how to use Rslib to build a simple Module Federation React component.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "@examples/mf-react-component",
3+
"private": true,
4+
"exports": {
5+
".": {
6+
"import": "./dist/esm/index.mjs",
7+
"require": "./dist/cjs/index.js",
8+
"types": "./dist/cjs/index.d.ts"
9+
}
10+
},
11+
"main": "./dist/cjs/index.js",
12+
"module": "./dist/esm/index.mjs",
13+
"types": "./dist/cjs/index.d.ts",
14+
"scripts": {
15+
"build": "rslib build",
16+
"serve": "pnpm build && http-server -p 3001 ./dist/ --cors"
17+
},
18+
"devDependencies": {
19+
"@module-federation/enhanced": "^0.6.11",
20+
"@module-federation/rsbuild-plugin": "^0.0.2",
21+
"@rsbuild/plugin-react": "^1.0.4",
22+
"@rslib/core": "workspace:*",
23+
"@types/react": "^18.3.11",
24+
"http-server": "^14.1.1",
25+
"react": "^18.3.1",
26+
"react-dom": "^18.3.1"
27+
},
28+
"peerDependencies": {
29+
"react": "*"
30+
}
31+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
2+
import { pluginReact } from '@rsbuild/plugin-react';
3+
import { defineConfig } from '@rslib/core';
4+
5+
const shared = {
6+
dts: {
7+
bundle: false,
8+
},
9+
};
10+
11+
export default defineConfig({
12+
lib: [
13+
{
14+
...shared,
15+
format: 'esm',
16+
output: {
17+
distPath: {
18+
root: './dist/esm',
19+
},
20+
},
21+
},
22+
{
23+
...shared,
24+
format: 'cjs',
25+
output: {
26+
distPath: {
27+
root: './dist/cjs',
28+
},
29+
},
30+
},
31+
{
32+
...shared,
33+
format: 'mf',
34+
output: {
35+
distPath: {
36+
root: './dist/mf',
37+
},
38+
assetPrefix: 'http://localhost:3001/mf',
39+
},
40+
plugins: [
41+
pluginModuleFederation({
42+
name: 'rslib_provider',
43+
exposes: {
44+
'.': './src/index.tsx',
45+
},
46+
shared: {
47+
react: {
48+
singleton: true,
49+
},
50+
'react-dom': {
51+
singleton: true,
52+
},
53+
},
54+
}),
55+
],
56+
},
57+
],
58+
plugins: [pluginReact()],
59+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
interface CounterButtonProps {
2+
onClick: () => void;
3+
label: string;
4+
[key: string]: any;
5+
}
6+
7+
export const CounterButton: React.FC<CounterButtonProps> = ({
8+
onClick,
9+
label,
10+
...props
11+
}) => (
12+
<button type="button" onClick={onClick} {...props}>
13+
{label}
14+
</button>
15+
);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { init, loadRemote } from '@module-federation/enhanced/runtime';
2+
import { Suspense, createElement, lazy } from 'react';
3+
import { CounterButton } from './CounterButton';
4+
import { useCounter } from './useCounter';
5+
6+
init({
7+
name: 'rslib_provider',
8+
remotes: [
9+
{
10+
name: 'mf_remote',
11+
entry: 'http://localhost:3002/mf-manifest.json',
12+
},
13+
],
14+
});
15+
16+
export const Counter: React.FC = () => {
17+
const { count, increment, decrement } = useCounter();
18+
19+
return (
20+
<div>
21+
<Suspense fallback={<div>loading</div>}>
22+
{createElement(
23+
lazy(
24+
() =>
25+
loadRemote('mf_remote') as Promise<{
26+
default: React.FC;
27+
}>,
28+
),
29+
)}
30+
</Suspense>
31+
<h2>
32+
<span id="mf-e2e-lib-title">Counter From Rslib MF Format: </span>
33+
<span id="mf-e2e-lib-content">{count}</span>
34+
</h2>
35+
<CounterButton id="mf-e2e-lib-decrease" onClick={decrement} label="-" />
36+
<CounterButton id="mf-e2e-lib-increase" onClick={increment} label="+" />
37+
</div>
38+
);
39+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useState } from 'react';
2+
3+
export const useCounter = (initialValue = 0) => {
4+
const [count, setCount] = useState(initialValue);
5+
6+
const increment = () => setCount((prev) => prev + 1);
7+
const decrement = () => setCount((prev) => prev - 1);
8+
9+
return { count, increment, decrement };
10+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"jsx": "react-jsx",
4+
"strict": true,
5+
"skipLibCheck": true
6+
},
7+
"include": ["src/**/*"]
8+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Rsbuild Project
2+
3+
Module Federation Remote Example
4+
5+
## Setup
6+
7+
Install the dependencies:
8+
9+
```bash
10+
pnpm install
11+
```
12+
13+
## Get Started
14+
15+
Start the dev server:
16+
17+
```bash
18+
pnpm dev
19+
```
20+
21+
Build the app for production:
22+
23+
```bash
24+
pnpm build
25+
```
26+
27+
Preview the production build locally:
28+
29+
```bash
30+
pnpm preview
31+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "@example/mf-remote",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"build": "rsbuild build",
7+
"dev": "rsbuild dev",
8+
"preview": "rsbuild preview"
9+
},
10+
"dependencies": {
11+
"react": "^18.3.1",
12+
"react-dom": "^18.3.1"
13+
},
14+
"devDependencies": {
15+
"@module-federation/rsbuild-plugin": "^0.0.2",
16+
"@rsbuild/core": "~1.0.14",
17+
"@rsbuild/plugin-react": "^1.0.4",
18+
"@types/react": "^18.3.11",
19+
"@types/react-dom": "^18.3.1",
20+
"typescript": "^5.6.3"
21+
}
22+
}

0 commit comments

Comments
 (0)