@module-federation/bridge-react 0.0.0-next-20240619092013
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +134 -0
- package/__tests__/bridge.spec.tsx +68 -0
- package/__tests__/router.spec.tsx +82 -0
- package/__tests__/util.ts +36 -0
- package/dist/context-C7FfFcIe.cjs +42 -0
- package/dist/context-CoFgcMIF.js +43 -0
- package/dist/index.cjs.js +175 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.es.js +175 -0
- package/dist/router.cjs.js +90 -0
- package/dist/router.d.ts +11 -0
- package/dist/router.es.js +67 -0
- package/package.json +55 -0
- package/project.json +27 -0
- package/src/.eslintrc.js +9 -0
- package/src/context.tsx +4 -0
- package/src/create.tsx +178 -0
- package/src/index.ts +6 -0
- package/src/modern-app-env.d.ts +2 -0
- package/src/provider.tsx +67 -0
- package/src/router.tsx +74 -0
- package/src/utils.ts +3 -0
- package/tsconfig.json +42 -0
- package/tsconfig.node.json +11 -0
- package/vite.config.ts +42 -0
- package/vitest.config.ts +22 -0
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import React, { useContext, useMemo, useRef, useState, useEffect } from "react";
|
|
2
|
+
import { UNSAFE_RouteContext, useLocation } from "react-router-dom";
|
|
3
|
+
import { L as LoggerInstance, f, R as RouterContext } from "./context-CoFgcMIF.js";
|
|
4
|
+
import require$$0 from "react-dom";
|
|
5
|
+
const RemoteApp = ({
|
|
6
|
+
name,
|
|
7
|
+
memoryRoute,
|
|
8
|
+
basename,
|
|
9
|
+
providerInfo,
|
|
10
|
+
...resProps
|
|
11
|
+
}) => {
|
|
12
|
+
const rootRef = useRef(null);
|
|
13
|
+
const renderDom = useRef(null);
|
|
14
|
+
const location = useLocation();
|
|
15
|
+
const [pathname, setPathname] = useState(location.pathname);
|
|
16
|
+
const providerInfoRef = useRef(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (pathname !== "" && pathname !== location.pathname) {
|
|
19
|
+
LoggerInstance.log(`createRemoteComponent dispatchPopstateEnv >>>`, {
|
|
20
|
+
name,
|
|
21
|
+
pathname: location.pathname
|
|
22
|
+
});
|
|
23
|
+
f();
|
|
24
|
+
}
|
|
25
|
+
setPathname(location.pathname);
|
|
26
|
+
}, [location]);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const renderTimeout = setTimeout(() => {
|
|
29
|
+
const providerReturn = providerInfo();
|
|
30
|
+
providerInfoRef.current = providerReturn;
|
|
31
|
+
const renderProps = {
|
|
32
|
+
name,
|
|
33
|
+
dom: rootRef.current,
|
|
34
|
+
basename,
|
|
35
|
+
memoryRoute,
|
|
36
|
+
...resProps
|
|
37
|
+
};
|
|
38
|
+
renderDom.current = rootRef.current;
|
|
39
|
+
LoggerInstance.log(
|
|
40
|
+
`createRemoteComponent LazyComponent render >>>`,
|
|
41
|
+
renderProps
|
|
42
|
+
);
|
|
43
|
+
providerReturn.render(renderProps);
|
|
44
|
+
});
|
|
45
|
+
return () => {
|
|
46
|
+
clearTimeout(renderTimeout);
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
if ((_a = providerInfoRef.current) == null ? void 0 : _a.destroy) {
|
|
50
|
+
LoggerInstance.log(
|
|
51
|
+
`createRemoteComponent LazyComponent destroy >>>`,
|
|
52
|
+
{ name, basename, dom: renderDom.current }
|
|
53
|
+
);
|
|
54
|
+
(_b = providerInfoRef.current) == null ? void 0 : _b.destroy({
|
|
55
|
+
dom: renderDom.current
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
}, []);
|
|
61
|
+
return /* @__PURE__ */ React.createElement("div", { ref: rootRef });
|
|
62
|
+
};
|
|
63
|
+
RemoteApp["__APP_VERSION__"] = "0.0.1";
|
|
64
|
+
function createRemoteComponent(lazyComponent, info) {
|
|
65
|
+
return (props) => {
|
|
66
|
+
const exportName = (info == null ? void 0 : info.export) || "default";
|
|
67
|
+
const routerContextVal = useContext(UNSAFE_RouteContext);
|
|
68
|
+
let basename = "/";
|
|
69
|
+
if (routerContextVal.matches[0] && routerContextVal.matches[0].pathnameBase) {
|
|
70
|
+
basename = routerContextVal.matches[0].pathnameBase;
|
|
71
|
+
}
|
|
72
|
+
const LazyComponent = useMemo(() => {
|
|
73
|
+
return React.lazy(async () => {
|
|
74
|
+
LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
|
|
75
|
+
basename,
|
|
76
|
+
lazyComponent,
|
|
77
|
+
exportName,
|
|
78
|
+
props
|
|
79
|
+
});
|
|
80
|
+
const m2 = await lazyComponent();
|
|
81
|
+
const moduleName = m2 && m2[Symbol.for("mf_module_id")];
|
|
82
|
+
LoggerInstance.log(
|
|
83
|
+
`createRemoteComponent LazyComponent loadRemote info >>>`,
|
|
84
|
+
{ basename, name: moduleName, module: m2, exportName, props }
|
|
85
|
+
);
|
|
86
|
+
const exportFn = m2[exportName];
|
|
87
|
+
if (exportName in m2 && typeof exportFn === "function") {
|
|
88
|
+
return {
|
|
89
|
+
default: () => /* @__PURE__ */ React.createElement(
|
|
90
|
+
RemoteApp,
|
|
91
|
+
{
|
|
92
|
+
name: moduleName,
|
|
93
|
+
...info,
|
|
94
|
+
...props,
|
|
95
|
+
providerInfo: exportFn,
|
|
96
|
+
basename
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
throw Error("module not found");
|
|
102
|
+
});
|
|
103
|
+
}, [exportName, basename, props.memoryRoute]);
|
|
104
|
+
return /* @__PURE__ */ React.createElement(React.Suspense, { fallback: props.fallback }, /* @__PURE__ */ React.createElement(LazyComponent, null));
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
var client = {};
|
|
108
|
+
var m = require$$0;
|
|
109
|
+
if (process.env.NODE_ENV === "production") {
|
|
110
|
+
client.createRoot = m.createRoot;
|
|
111
|
+
client.hydrateRoot = m.hydrateRoot;
|
|
112
|
+
} else {
|
|
113
|
+
var i = m.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
|
114
|
+
client.createRoot = function(c, o) {
|
|
115
|
+
i.usingClientEntryPoint = true;
|
|
116
|
+
try {
|
|
117
|
+
return m.createRoot(c, o);
|
|
118
|
+
} finally {
|
|
119
|
+
i.usingClientEntryPoint = false;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
client.hydrateRoot = function(c, h, o) {
|
|
123
|
+
i.usingClientEntryPoint = true;
|
|
124
|
+
try {
|
|
125
|
+
return m.hydrateRoot(c, h, o);
|
|
126
|
+
} finally {
|
|
127
|
+
i.usingClientEntryPoint = false;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function createBridgeComponent(bridgeInfo) {
|
|
132
|
+
return () => {
|
|
133
|
+
const rootMap = /* @__PURE__ */ new Map();
|
|
134
|
+
const RawComponent = (info) => {
|
|
135
|
+
const { appInfo, propsInfo } = info;
|
|
136
|
+
const { name, memoryRoute, basename = "/" } = appInfo;
|
|
137
|
+
return /* @__PURE__ */ React.createElement(RouterContext.Provider, { value: { name, basename, memoryRoute } }, /* @__PURE__ */ React.createElement(bridgeInfo.rootComponent, { ...propsInfo, basename }));
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
render(info) {
|
|
141
|
+
LoggerInstance.log(`createBridgeComponent render Info`, info);
|
|
142
|
+
const root = client.createRoot(info.dom);
|
|
143
|
+
rootMap.set(info.dom, root);
|
|
144
|
+
const { name, basename, memoryRoute, ...propsInfo } = info;
|
|
145
|
+
root.render(
|
|
146
|
+
/* @__PURE__ */ React.createElement(
|
|
147
|
+
RawComponent,
|
|
148
|
+
{
|
|
149
|
+
propsInfo,
|
|
150
|
+
appInfo: {
|
|
151
|
+
name,
|
|
152
|
+
basename,
|
|
153
|
+
memoryRoute
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
},
|
|
159
|
+
destroy(info) {
|
|
160
|
+
LoggerInstance.log(`createBridgeComponent destroy Info`, {
|
|
161
|
+
dom: info.dom
|
|
162
|
+
});
|
|
163
|
+
const root = rootMap.get(info.dom);
|
|
164
|
+
root == null ? void 0 : root.unmount();
|
|
165
|
+
},
|
|
166
|
+
rawComponent: bridgeInfo.rootComponent,
|
|
167
|
+
__BRIDGE_FN__: (_args) => {
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
export {
|
|
173
|
+
createBridgeComponent,
|
|
174
|
+
createRemoteComponent
|
|
175
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const React = require("react");
|
|
4
|
+
const ReactRouterDom = require("react-router-dom/");
|
|
5
|
+
const context = require("./context-C7FfFcIe.cjs");
|
|
6
|
+
function _interopNamespaceDefault(e) {
|
|
7
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
8
|
+
if (e) {
|
|
9
|
+
for (const k in e) {
|
|
10
|
+
if (k !== "default") {
|
|
11
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
12
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: () => e[k]
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
n.default = e;
|
|
20
|
+
return Object.freeze(n);
|
|
21
|
+
}
|
|
22
|
+
const ReactRouterDom__namespace = /* @__PURE__ */ _interopNamespaceDefault(ReactRouterDom);
|
|
23
|
+
function WraperRouter(props) {
|
|
24
|
+
const { basename, ...propsRes } = props;
|
|
25
|
+
const routerContextProps = React.useContext(context.RouterContext) || {};
|
|
26
|
+
context.LoggerInstance.log(`WraperRouter info >>>`, {
|
|
27
|
+
...routerContextProps,
|
|
28
|
+
routerContextProps,
|
|
29
|
+
WraperRouterProps: props
|
|
30
|
+
});
|
|
31
|
+
if (!routerContextProps)
|
|
32
|
+
return /* @__PURE__ */ React.createElement(ReactRouterDom__namespace.BrowserRouter, { ...props });
|
|
33
|
+
if (routerContextProps == null ? void 0 : routerContextProps.memoryRoute) {
|
|
34
|
+
return /* @__PURE__ */ React.createElement(
|
|
35
|
+
ReactRouterDom__namespace.MemoryRouter,
|
|
36
|
+
{
|
|
37
|
+
...props,
|
|
38
|
+
initialEntries: [routerContextProps == null ? void 0 : routerContextProps.memoryRoute.entryPath]
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return /* @__PURE__ */ React.createElement(
|
|
43
|
+
ReactRouterDom__namespace.BrowserRouter,
|
|
44
|
+
{
|
|
45
|
+
...propsRes,
|
|
46
|
+
basename: (routerContextProps == null ? void 0 : routerContextProps.basename) || basename
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
function WraperRouterProvider(props) {
|
|
51
|
+
const { router, ...propsRes } = props;
|
|
52
|
+
const routerContextProps = React.useContext(context.RouterContext) || {};
|
|
53
|
+
const routers = router.routes;
|
|
54
|
+
context.LoggerInstance.log(`WraperRouterProvider info >>>`, {
|
|
55
|
+
...routerContextProps,
|
|
56
|
+
routerContextProps,
|
|
57
|
+
WraperRouterProviderProps: props,
|
|
58
|
+
router
|
|
59
|
+
});
|
|
60
|
+
if (!routerContextProps)
|
|
61
|
+
return /* @__PURE__ */ React.createElement(ReactRouterDom__namespace.RouterProvider, { ...props });
|
|
62
|
+
if (routerContextProps.memoryRoute) {
|
|
63
|
+
const MemeoryRouterInstance = ReactRouterDom__namespace.createMemoryRouter(routers, {
|
|
64
|
+
initialEntries: [routerContextProps == null ? void 0 : routerContextProps.memoryRoute.entryPath]
|
|
65
|
+
});
|
|
66
|
+
return /* @__PURE__ */ React.createElement(ReactRouterDom__namespace.RouterProvider, { router: MemeoryRouterInstance });
|
|
67
|
+
} else {
|
|
68
|
+
const BrowserRouterInstance = ReactRouterDom__namespace.createBrowserRouter(routers, {
|
|
69
|
+
basename: routerContextProps.basename,
|
|
70
|
+
future: router.future,
|
|
71
|
+
window: router.window
|
|
72
|
+
});
|
|
73
|
+
return /* @__PURE__ */ React.createElement(
|
|
74
|
+
ReactRouterDom__namespace.RouterProvider,
|
|
75
|
+
{
|
|
76
|
+
...propsRes,
|
|
77
|
+
router: BrowserRouterInstance
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.BrowserRouter = WraperRouter;
|
|
83
|
+
exports.RouterProvider = WraperRouterProvider;
|
|
84
|
+
Object.keys(ReactRouterDom).forEach((k) => {
|
|
85
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k))
|
|
86
|
+
Object.defineProperty(exports, k, {
|
|
87
|
+
enumerable: true,
|
|
88
|
+
get: () => ReactRouterDom[k]
|
|
89
|
+
});
|
|
90
|
+
});
|
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { default as default_2 } from 'react';
|
|
2
|
+
import * as ReactRouterDom from 'react-router-dom/';
|
|
3
|
+
|
|
4
|
+
export declare function BrowserRouter(props: Parameters<typeof ReactRouterDom.BrowserRouter>[0] | Parameters<typeof ReactRouterDom.MemoryRouter>[0]): default_2.JSX.Element;
|
|
5
|
+
|
|
6
|
+
export declare function RouterProvider(props: Parameters<typeof ReactRouterDom.RouterProvider>[0]): default_2.JSX.Element;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export * from "react-router-dom/";
|
|
10
|
+
|
|
11
|
+
export { }
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import * as ReactRouterDom from "react-router-dom/";
|
|
3
|
+
export * from "react-router-dom/";
|
|
4
|
+
import { R as RouterContext, L as LoggerInstance } from "./context-CoFgcMIF.js";
|
|
5
|
+
function WraperRouter(props) {
|
|
6
|
+
const { basename, ...propsRes } = props;
|
|
7
|
+
const routerContextProps = useContext(RouterContext) || {};
|
|
8
|
+
LoggerInstance.log(`WraperRouter info >>>`, {
|
|
9
|
+
...routerContextProps,
|
|
10
|
+
routerContextProps,
|
|
11
|
+
WraperRouterProps: props
|
|
12
|
+
});
|
|
13
|
+
if (!routerContextProps)
|
|
14
|
+
return /* @__PURE__ */ React.createElement(ReactRouterDom.BrowserRouter, { ...props });
|
|
15
|
+
if (routerContextProps == null ? void 0 : routerContextProps.memoryRoute) {
|
|
16
|
+
return /* @__PURE__ */ React.createElement(
|
|
17
|
+
ReactRouterDom.MemoryRouter,
|
|
18
|
+
{
|
|
19
|
+
...props,
|
|
20
|
+
initialEntries: [routerContextProps == null ? void 0 : routerContextProps.memoryRoute.entryPath]
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
return /* @__PURE__ */ React.createElement(
|
|
25
|
+
ReactRouterDom.BrowserRouter,
|
|
26
|
+
{
|
|
27
|
+
...propsRes,
|
|
28
|
+
basename: (routerContextProps == null ? void 0 : routerContextProps.basename) || basename
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
function WraperRouterProvider(props) {
|
|
33
|
+
const { router, ...propsRes } = props;
|
|
34
|
+
const routerContextProps = useContext(RouterContext) || {};
|
|
35
|
+
const routers = router.routes;
|
|
36
|
+
LoggerInstance.log(`WraperRouterProvider info >>>`, {
|
|
37
|
+
...routerContextProps,
|
|
38
|
+
routerContextProps,
|
|
39
|
+
WraperRouterProviderProps: props,
|
|
40
|
+
router
|
|
41
|
+
});
|
|
42
|
+
if (!routerContextProps)
|
|
43
|
+
return /* @__PURE__ */ React.createElement(ReactRouterDom.RouterProvider, { ...props });
|
|
44
|
+
if (routerContextProps.memoryRoute) {
|
|
45
|
+
const MemeoryRouterInstance = ReactRouterDom.createMemoryRouter(routers, {
|
|
46
|
+
initialEntries: [routerContextProps == null ? void 0 : routerContextProps.memoryRoute.entryPath]
|
|
47
|
+
});
|
|
48
|
+
return /* @__PURE__ */ React.createElement(ReactRouterDom.RouterProvider, { router: MemeoryRouterInstance });
|
|
49
|
+
} else {
|
|
50
|
+
const BrowserRouterInstance = ReactRouterDom.createBrowserRouter(routers, {
|
|
51
|
+
basename: routerContextProps.basename,
|
|
52
|
+
future: router.future,
|
|
53
|
+
window: router.window
|
|
54
|
+
});
|
|
55
|
+
return /* @__PURE__ */ React.createElement(
|
|
56
|
+
ReactRouterDom.RouterProvider,
|
|
57
|
+
{
|
|
58
|
+
...propsRes,
|
|
59
|
+
router: BrowserRouterInstance
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
WraperRouter as BrowserRouter,
|
|
66
|
+
WraperRouterProvider as RouterProvider
|
|
67
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@module-federation/bridge-react",
|
|
3
|
+
"version": "0.0.0-next-20240619092013",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"author": "zhouxiao <codingzx@gmail.com>",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.cjs.js",
|
|
10
|
+
"module": "./dist/index.es.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.es.js",
|
|
16
|
+
"require": "./dist/index.cjs.js"
|
|
17
|
+
},
|
|
18
|
+
"./router": {
|
|
19
|
+
"types": "./dist/router.d.ts",
|
|
20
|
+
"import": "./dist/router.es.js",
|
|
21
|
+
"require": "./dist/router.cjs.js"
|
|
22
|
+
},
|
|
23
|
+
"./*": "./*"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@loadable/component": "^5.16.4",
|
|
27
|
+
"react-error-boundary": "^4.0.13",
|
|
28
|
+
"@module-federation/bridge-shared": "0.0.0-next-20240619092013"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"react": "=18",
|
|
32
|
+
"react-dom": "=18",
|
|
33
|
+
"react-router-dom": ">=5"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@testing-library/react": "15.0.7",
|
|
37
|
+
"@types/react": "18.2.79",
|
|
38
|
+
"@types/react-dom": "18.2.25",
|
|
39
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
40
|
+
"@vitejs/plugin-vue": "^5.0.4",
|
|
41
|
+
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
|
42
|
+
"jsdom": "^24.1.0",
|
|
43
|
+
"react": "18.1.0",
|
|
44
|
+
"react-dom": "18.1.0",
|
|
45
|
+
"react-router-dom": "6.22.3",
|
|
46
|
+
"typescript": "^5.2.2",
|
|
47
|
+
"vite": "^5.2.0",
|
|
48
|
+
"vite-plugin-dts": "^3.9.1"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"dev": "vite",
|
|
52
|
+
"build": "vite build",
|
|
53
|
+
"preview": "vite preview"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bridge-react",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/bridge/bridge-react/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"targets": {
|
|
7
|
+
"build": {
|
|
8
|
+
"executor": "nx:run-commands",
|
|
9
|
+
"options": {
|
|
10
|
+
"commands": ["npm run build --prefix packages/bridge/bridge-react"]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"test": {
|
|
14
|
+
"executor": "nx:run-commands",
|
|
15
|
+
"options": {
|
|
16
|
+
"parallel": false,
|
|
17
|
+
"commands": [
|
|
18
|
+
{
|
|
19
|
+
"command": "vitest run -c packages/bridge/bridge-react/vitest.config.ts",
|
|
20
|
+
"forwardAllArgs": false
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"tags": ["type:pkg"]
|
|
27
|
+
}
|
package/src/.eslintrc.js
ADDED
package/src/context.tsx
ADDED
package/src/create.tsx
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
ReactNode,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import { UNSAFE_RouteContext, useLocation } from 'react-router-dom';
|
|
10
|
+
import type { ProviderParams } from '@module-federation/bridge-shared';
|
|
11
|
+
import { LoggerInstance } from './utils';
|
|
12
|
+
import { dispatchPopstateEnv } from '@module-federation/bridge-shared';
|
|
13
|
+
|
|
14
|
+
declare const __APP_VERSION__: string;
|
|
15
|
+
|
|
16
|
+
export interface RenderFnParams extends ProviderParams {
|
|
17
|
+
dom?: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface RemoteModule {
|
|
21
|
+
provider: () => {
|
|
22
|
+
render: (
|
|
23
|
+
info: ProviderParams & {
|
|
24
|
+
dom: any;
|
|
25
|
+
},
|
|
26
|
+
) => void;
|
|
27
|
+
destroy: (info: { dom: any }) => void;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface RemoteAppParams {
|
|
32
|
+
name: string;
|
|
33
|
+
providerInfo: NonNullable<RemoteModule['provider']>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const RemoteApp = ({
|
|
37
|
+
name,
|
|
38
|
+
memoryRoute,
|
|
39
|
+
basename,
|
|
40
|
+
providerInfo,
|
|
41
|
+
...resProps
|
|
42
|
+
}: RemoteAppParams & ProviderParams) => {
|
|
43
|
+
const rootRef = useRef(null);
|
|
44
|
+
const renderDom = useRef(null);
|
|
45
|
+
const location = useLocation();
|
|
46
|
+
const [pathname, setPathname] = useState(location.pathname);
|
|
47
|
+
const providerInfoRef = useRef<any>(null);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (pathname !== '' && pathname !== location.pathname) {
|
|
51
|
+
LoggerInstance.log(`createRemoteComponent dispatchPopstateEnv >>>`, {
|
|
52
|
+
name,
|
|
53
|
+
pathname: location.pathname,
|
|
54
|
+
});
|
|
55
|
+
dispatchPopstateEnv();
|
|
56
|
+
}
|
|
57
|
+
setPathname(location.pathname);
|
|
58
|
+
}, [location]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const renderTimeout = setTimeout(() => {
|
|
62
|
+
const providerReturn = providerInfo();
|
|
63
|
+
providerInfoRef.current = providerReturn;
|
|
64
|
+
const renderProps = {
|
|
65
|
+
name,
|
|
66
|
+
dom: rootRef.current,
|
|
67
|
+
basename,
|
|
68
|
+
memoryRoute,
|
|
69
|
+
...resProps,
|
|
70
|
+
};
|
|
71
|
+
renderDom.current = rootRef.current;
|
|
72
|
+
LoggerInstance.log(
|
|
73
|
+
`createRemoteComponent LazyComponent render >>>`,
|
|
74
|
+
renderProps,
|
|
75
|
+
);
|
|
76
|
+
providerReturn.render(renderProps);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return () => {
|
|
80
|
+
clearTimeout(renderTimeout);
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
if (providerInfoRef.current?.destroy) {
|
|
83
|
+
LoggerInstance.log(
|
|
84
|
+
`createRemoteComponent LazyComponent destroy >>>`,
|
|
85
|
+
{ name, basename, dom: renderDom.current },
|
|
86
|
+
);
|
|
87
|
+
providerInfoRef.current?.destroy({
|
|
88
|
+
dom: renderDom.current,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
95
|
+
//@ts-ignore
|
|
96
|
+
return <div ref={rootRef}></div>;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
(RemoteApp as any)['__APP_VERSION__'] = __APP_VERSION__;
|
|
100
|
+
|
|
101
|
+
export function createRemoteComponent<T, E extends keyof T>(
|
|
102
|
+
lazyComponent: () => Promise<T>,
|
|
103
|
+
info?: {
|
|
104
|
+
export?: E;
|
|
105
|
+
},
|
|
106
|
+
) {
|
|
107
|
+
type ExportType = T[E] extends (...args: any) => any
|
|
108
|
+
? ReturnType<T[E]>
|
|
109
|
+
: never;
|
|
110
|
+
type RawComponentType = '__BRIDGE_FN__' extends keyof ExportType
|
|
111
|
+
? ExportType['__BRIDGE_FN__'] extends (...args: any) => any
|
|
112
|
+
? Parameters<ExportType['__BRIDGE_FN__']>[0]
|
|
113
|
+
: {}
|
|
114
|
+
: {};
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
props: {
|
|
118
|
+
basename?: ProviderParams['basename'];
|
|
119
|
+
memoryRoute?: ProviderParams['memoryRoute'];
|
|
120
|
+
fallback: ReactNode;
|
|
121
|
+
} & RawComponentType,
|
|
122
|
+
) => {
|
|
123
|
+
const exportName = info?.export || 'default';
|
|
124
|
+
const routerContextVal = useContext(UNSAFE_RouteContext);
|
|
125
|
+
let basename = '/';
|
|
126
|
+
if (
|
|
127
|
+
routerContextVal.matches[0] &&
|
|
128
|
+
routerContextVal.matches[0].pathnameBase
|
|
129
|
+
) {
|
|
130
|
+
basename = routerContextVal.matches[0].pathnameBase;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const LazyComponent = useMemo(() => {
|
|
134
|
+
//@ts-ignore
|
|
135
|
+
return React.lazy(async () => {
|
|
136
|
+
LoggerInstance.log(`createRemoteComponent LazyComponent create >>>`, {
|
|
137
|
+
basename,
|
|
138
|
+
lazyComponent,
|
|
139
|
+
exportName,
|
|
140
|
+
props,
|
|
141
|
+
});
|
|
142
|
+
const m = (await lazyComponent()) as RemoteModule;
|
|
143
|
+
// @ts-ignore
|
|
144
|
+
const moduleName = m && m[Symbol.for('mf_module_id')];
|
|
145
|
+
LoggerInstance.log(
|
|
146
|
+
`createRemoteComponent LazyComponent loadRemote info >>>`,
|
|
147
|
+
{ basename, name: moduleName, module: m, exportName, props },
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// @ts-ignore
|
|
151
|
+
const exportFn = m[exportName] as any;
|
|
152
|
+
|
|
153
|
+
if (exportName in m && typeof exportFn === 'function') {
|
|
154
|
+
return {
|
|
155
|
+
default: () => (
|
|
156
|
+
<RemoteApp
|
|
157
|
+
name={moduleName}
|
|
158
|
+
{...info}
|
|
159
|
+
{...props}
|
|
160
|
+
providerInfo={exportFn}
|
|
161
|
+
basename={basename}
|
|
162
|
+
/>
|
|
163
|
+
),
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
throw Error('module not found');
|
|
168
|
+
});
|
|
169
|
+
}, [exportName, basename, props.memoryRoute]);
|
|
170
|
+
|
|
171
|
+
//@ts-ignore
|
|
172
|
+
return (
|
|
173
|
+
<React.Suspense fallback={props.fallback}>
|
|
174
|
+
<LazyComponent />
|
|
175
|
+
</React.Suspense>
|
|
176
|
+
);
|
|
177
|
+
};
|
|
178
|
+
}
|
package/src/index.ts
ADDED