Skip to content

Commit 21ed1a4

Browse files
authored
Add nested components example (module-federation#15)
* add nested components example * remove duplicate nested readme
1 parent a695980 commit 21ed1a4

23 files changed

+330
-2
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@ This repository is to showcase examples on Webpack 5's new Module Federation can
1616
- [x] [Dynamic System Host](./dynamic-system-host/README.md) — Swap between remotes at runtime.
1717
- [x] [Redux Reducer Injection](./redux-reducer-injection.md) — Dynamically inject reducers to host store at runtime.
1818
- [x] [Shared Routes](./shared-routes2) — Compose federated routes for a seamless user experience.
19-
- [ ] Nested Interleaved Components
19+
- [x] [Nested Components](./nested/README.md) — Nested remote components.
2020
- [x] [Share Context Provider](./shared-context/README.md) — App1 and App2 with shared Context Provider.
2121
- [ ] Non-UI Module
2222
- [x] Routing
23-
- [ ] Nested
2423
- [x] [Version Discrepancy](./version-discrepancy/README.md) — Federated apps depending on different versions of a dependency without side-effects.
2524
- [x] [TypeScript](./typescript/README.md) — Simple host/remote example using TypeScript.
2625
- [ ] NextJS

nested/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Nested Example
2+
3+
This example demos loading nested remote components.
4+
5+
- `app1` is the host application and async loads `ButtonContainer` from `app2`.
6+
- `app2` is a standalone application that exposes `ButtonContainer` component which async loads `Button`.
7+
- `app3` is a standalone application that exposes `Button` component.
8+
9+
# Running Demo
10+
11+
Run `yarn start`. This will build and serve both `app1`, `app2`, and `app3` on ports 3001, 3002, and 3003 respectively.
12+
13+
- [localhost:3001](http://localhost:3001/) (HOST)
14+
- [localhost:3002](http://localhost:3002/) (STANDALONE REMOTE)
15+
- [localhost:3003](http://localhost:3003/) (STANDALONE REMOTE)

nested/app1/package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@nested/app1",
3+
"version": "0.0.0",
4+
"private": true,
5+
"devDependencies": {
6+
"@babel/core": "^7.9.0",
7+
"@babel/preset-react": "^7.9.1",
8+
"babel-loader": "^8.1.0",
9+
"html-webpack-plugin": "git://github.com/ScriptedAlchemy/html-webpack-plugin#master",
10+
"serve": "^11.3.0",
11+
"webpack": "git://github.com/webpack/webpack.git#dev-1",
12+
"webpack-cli": "^3.3.11",
13+
"webpack-dev-server": "^3.10.3"
14+
},
15+
"scripts": {
16+
"start": "webpack-dev-server",
17+
"build": "webpack --mode production",
18+
"serve": "serve dist -p 3001"
19+
},
20+
"dependencies": {
21+
"react": "^16.13.1",
22+
"react-dom": "^16.13.1"
23+
}
24+
}

nested/app1/public/index.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<html>
2+
<head>
3+
<script src="http://localhost:3002/remoteEntry.js"></script>
4+
<script src="http://localhost:3003/remoteEntry.js"></script>
5+
</head>
6+
<body>
7+
<div id="root"></div>
8+
</body>
9+
</html>

nested/app1/src/App.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from "react";
2+
3+
const RemoteButtonContainer = React.lazy(() => import("app2/ButtonContainer"));
4+
5+
const App = () => (
6+
<div>
7+
<h1>Nested</h1>
8+
<h2>App 1</h2>
9+
<p>app 1 body</p>
10+
<React.Suspense fallback="Loading Button Container">
11+
<RemoteButtonContainer />
12+
</React.Suspense>
13+
</div>
14+
);
15+
16+
export default App;

nested/app1/src/bootstrap.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import App from "./App";
2+
import React from "react";
3+
import ReactDOM from "react-dom";
4+
5+
ReactDOM.render(<App />, document.getElementById("root"));

nested/app1/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import("./bootstrap");

nested/app1/webpack.config.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const HtmlWebpackPlugin = require("html-webpack-plugin");
2+
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
3+
const path = require("path");
4+
5+
module.exports = {
6+
entry: "./src/index",
7+
mode: "development",
8+
devServer: {
9+
contentBase: path.join(__dirname, "dist"),
10+
port: 3001
11+
},
12+
output: {
13+
publicPath: "http://localhost:3001/"
14+
},
15+
module: {
16+
rules: [
17+
{
18+
test: /\.jsx?$/,
19+
loader: "babel-loader",
20+
options: {
21+
presets: ["@babel/preset-react"]
22+
}
23+
}
24+
]
25+
},
26+
plugins: [
27+
new ModuleFederationPlugin({
28+
name: "app1",
29+
library: { type: "var", name: "app1" },
30+
remotes: {
31+
app2: "app2",
32+
app3: "app3"
33+
},
34+
shared: ["react", "react-dom"]
35+
}),
36+
new HtmlWebpackPlugin({
37+
template: "./public/index.html"
38+
})
39+
]
40+
};

nested/app2/package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@nested/app2",
3+
"version": "0.0.0",
4+
"private": true,
5+
"devDependencies": {
6+
"@babel/core": "^7.9.0",
7+
"@babel/preset-react": "^7.9.1",
8+
"babel-loader": "^8.1.0",
9+
"html-webpack-plugin": "git://github.com/ScriptedAlchemy/html-webpack-plugin#master",
10+
"serve": "^11.3.0",
11+
"webpack": "git://github.com/webpack/webpack.git#dev-1",
12+
"webpack-cli": "^3.3.11",
13+
"webpack-dev-server": "^3.10.3"
14+
},
15+
"scripts": {
16+
"start": "webpack-dev-server",
17+
"build": "webpack --mode production",
18+
"serve": "serve dist -p 3001"
19+
},
20+
"dependencies": {
21+
"react": "^16.13.1",
22+
"react-dom": "^16.13.1"
23+
}
24+
}

nested/app2/public/index.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<html>
2+
<head>
3+
<script src="http://localhost:3003/remoteEntry.js"></script>
4+
</head>
5+
<body>
6+
<div id="root"></div>
7+
</body>
8+
</html>

nested/app2/src/App.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import ButtonContainer from "./ButtonContainer";
2+
import React from "react";
3+
4+
const App = () => (
5+
<div>
6+
<h1>Nested</h1>
7+
<h2>App 2</h2>
8+
<ButtonContainer />
9+
</div>
10+
);
11+
12+
export default App;

nested/app2/src/ButtonContainer.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
3+
const RemoteButton = React.lazy(() => import("app3/Button"));
4+
5+
const style = {
6+
padding: 12,
7+
backgroundColor: "#cccccc"
8+
};
9+
10+
const ButtonContainer = () => (
11+
<div style={style}>
12+
App 2 Container
13+
<br />
14+
<br />
15+
<React.Suspense fallback="Loading Button">
16+
<RemoteButton />
17+
</React.Suspense>
18+
</div>
19+
);
20+
21+
export default ButtonContainer;

nested/app2/src/bootstrap.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import App from "./App";
2+
import React from "react";
3+
import ReactDOM from "react-dom";
4+
5+
ReactDOM.render(<App />, document.getElementById("root"));

nested/app2/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import("./bootstrap");

nested/app2/webpack.config.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const HtmlWebpackPlugin = require("html-webpack-plugin");
2+
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
3+
const path = require("path");
4+
5+
module.exports = {
6+
entry: "./src/index",
7+
mode: "development",
8+
devServer: {
9+
contentBase: path.join(__dirname, "dist"),
10+
port: 3002
11+
},
12+
output: {
13+
publicPath: "http://localhost:3002/"
14+
},
15+
module: {
16+
rules: [
17+
{
18+
test: /\.jsx?$/,
19+
loader: "babel-loader",
20+
options: {
21+
presets: ["@babel/preset-react"]
22+
}
23+
}
24+
]
25+
},
26+
plugins: [
27+
new ModuleFederationPlugin({
28+
name: "app2",
29+
library: { type: "var", name: "app2" },
30+
filename: "remoteEntry.js",
31+
exposes: {
32+
ButtonContainer: "./src/ButtonContainer"
33+
},
34+
remotes: {
35+
app3: "app3"
36+
},
37+
shared: ["react", "react-dom"]
38+
}),
39+
new HtmlWebpackPlugin({
40+
template: "./public/index.html"
41+
})
42+
]
43+
};

nested/app3/package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@nested/app3",
3+
"version": "0.0.0",
4+
"private": true,
5+
"devDependencies": {
6+
"@babel/core": "^7.9.0",
7+
"@babel/preset-react": "^7.9.1",
8+
"babel-loader": "^8.1.0",
9+
"html-webpack-plugin": "git://github.com/ScriptedAlchemy/html-webpack-plugin#master",
10+
"serve": "^11.3.0",
11+
"webpack": "git://github.com/webpack/webpack.git#dev-1",
12+
"webpack-cli": "^3.3.11",
13+
"webpack-dev-server": "^3.10.3"
14+
},
15+
"scripts": {
16+
"start": "webpack-dev-server",
17+
"build": "webpack --mode production",
18+
"serve": "serve dist -p 3002"
19+
},
20+
"dependencies": {
21+
"react": "^16.13.1",
22+
"react-dom": "^16.13.1"
23+
}
24+
}

nested/app3/public/index.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<html>
2+
<body>
3+
<div id="root"></div>
4+
</body>
5+
</html>

nested/app3/src/App.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import LocalButton from "./Button";
2+
import React from "react";
3+
4+
const App = () => (
5+
<div>
6+
<h1>Nested</h1>
7+
<h2>App 3</h2>
8+
<LocalButton />
9+
</div>
10+
);
11+
12+
export default App;

nested/app3/src/Button.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from "react";
2+
3+
const style = {
4+
padding: 12,
5+
backgroundColor: "aquamarine"
6+
};
7+
8+
const Button = () => <button style={style}>App 3 Button</button>;
9+
10+
export default Button;

nested/app3/src/bootstrap.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import App from "./App";
2+
import React from "react";
3+
import ReactDOM from "react-dom";
4+
5+
ReactDOM.render(<App />, document.getElementById("root"));

nested/app3/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import("./bootstrap");

nested/app3/webpack.config.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const HtmlWebpackPlugin = require("html-webpack-plugin");
2+
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
3+
const path = require("path");
4+
5+
module.exports = {
6+
entry: "./src/index",
7+
mode: "development",
8+
devServer: {
9+
contentBase: path.join(__dirname, "dist"),
10+
port: 3003
11+
},
12+
output: {
13+
publicPath: "http://localhost:3003/"
14+
},
15+
module: {
16+
rules: [
17+
{
18+
test: /\.jsx?$/,
19+
loader: "babel-loader",
20+
options: {
21+
presets: ["@babel/preset-react"]
22+
}
23+
}
24+
]
25+
},
26+
plugins: [
27+
new ModuleFederationPlugin({
28+
name: "app3",
29+
library: { type: "var", name: "app3" },
30+
filename: "remoteEntry.js",
31+
exposes: {
32+
Button: "./src/Button"
33+
},
34+
shared: ["react", "react-dom"]
35+
}),
36+
new HtmlWebpackPlugin({
37+
template: "./public/index.html"
38+
})
39+
]
40+
};

nested/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"private": true,
3+
"scripts": {
4+
"start": "lerna run --scope @nested/* --parallel start",
5+
"build": "lerna run --scope @nested/* build",
6+
"serve": "lerna run --scope @nested/* --parallel serve"
7+
}
8+
}

0 commit comments

Comments
 (0)