-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
App.js
129 lines (107 loc) · 3.07 KB
/
App.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import React from "react";
function loadComponent(scope, module) {
return async () => {
// Initializes the share scope. This fills it with known provided modules from this build and all remotes
await __webpack_init_sharing__("default");
const container = window[scope]; // or get the container somewhere else
// Initialize the container, it may provide shared modules
await container.init(__webpack_share_scopes__.default);
const factory = await window[scope].get(module);
const Module = factory();
return Module;
};
}
const useDynamicScript = (args) => {
const [ready, setReady] = React.useState(false);
const [failed, setFailed] = React.useState(false);
React.useEffect(() => {
if (!args.url) {
return;
}
const element = document.createElement("script");
element.src = args.url;
element.type = "text/javascript";
element.async = true;
setReady(false);
setFailed(false);
element.onload = () => {
console.log(`Dynamic Script Loaded: ${args.url}`);
setReady(true);
};
element.onerror = () => {
console.error(`Dynamic Script Error: ${args.url}`);
setReady(false);
setFailed(true);
};
document.head.appendChild(element);
return () => {
console.log(`Dynamic Script Removed: ${args.url}`);
document.head.removeChild(element);
};
}, [args.url]);
return {
ready,
failed,
};
};
function System(props) {
const { ready, failed } = useDynamicScript({
url: props.system && props.system.url,
});
if (!props.system) {
return <h2>Not system specified</h2>;
}
if (!ready) {
return <h2>Loading dynamic script: {props.system.url}</h2>;
}
if (failed) {
return <h2>Failed to load dynamic script: {props.system.url}</h2>;
}
const Component = React.lazy(
loadComponent(props.system.scope, props.system.module)
);
return (
<React.Suspense fallback="Loading System">
<Component />
</React.Suspense>
);
}
function App() {
const [system, setSystem] = React.useState(undefined);
function setApp2() {
setSystem({
url: "http://localhost:3002/remoteEntry.js",
scope: "app2",
module: "./Widget",
});
}
function setApp3() {
setSystem({
url: "http://localhost:3003/remoteEntry.js",
scope: "app3",
module: "./Widget",
});
}
return (
<div
style={{
fontFamily:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"',
}}
>
<h1>Dynamic System Host</h1>
<h2>App 1</h2>
<p>
The Dynamic System will take advantage Module Federation{" "}
<strong>remotes</strong> and <strong>exposes</strong>. It will no load
components that have been loaded already.
</p>
<button onClick={setApp2}>Load App 2 Widget</button>
<button onClick={setApp3}>Load App 3 Widget</button>
<div style={{ marginTop: "2em" }}>
<System system={system} />
</div>
</div>
);
}
export default App;