@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/src/provider.tsx
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, { useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import { RouterContext } from './context';
|
|
4
|
+
import type {
|
|
5
|
+
ProviderParams,
|
|
6
|
+
RenderFnParams,
|
|
7
|
+
} from '@module-federation/bridge-shared';
|
|
8
|
+
import { LoggerInstance } from './utils';
|
|
9
|
+
|
|
10
|
+
type ProviderFnParams<T> = {
|
|
11
|
+
rootComponent: React.ComponentType<T>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function createBridgeComponent<T>(bridgeInfo: ProviderFnParams<T>) {
|
|
15
|
+
return () => {
|
|
16
|
+
const rootMap = new Map<any, ReactDOM.Root>();
|
|
17
|
+
|
|
18
|
+
const RawComponent = (info: { propsInfo: T; appInfo: ProviderParams }) => {
|
|
19
|
+
const { appInfo, propsInfo } = info;
|
|
20
|
+
const { name, memoryRoute, basename = '/' } = appInfo;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<RouterContext.Provider value={{ name, basename, memoryRoute }}>
|
|
24
|
+
<bridgeInfo.rootComponent {...propsInfo} basename={basename} />
|
|
25
|
+
</RouterContext.Provider>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
render(info: RenderFnParams & any) {
|
|
31
|
+
LoggerInstance.log(`createBridgeComponent render Info`, info);
|
|
32
|
+
const root = ReactDOM.createRoot(info.dom);
|
|
33
|
+
rootMap.set(info.dom, root);
|
|
34
|
+
const { name, basename, memoryRoute, ...propsInfo } = info;
|
|
35
|
+
root.render(
|
|
36
|
+
<RawComponent
|
|
37
|
+
propsInfo={propsInfo}
|
|
38
|
+
appInfo={{
|
|
39
|
+
name,
|
|
40
|
+
basename,
|
|
41
|
+
memoryRoute,
|
|
42
|
+
}}
|
|
43
|
+
/>,
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
destroy(info: { dom: HTMLElement }) {
|
|
47
|
+
LoggerInstance.log(`createBridgeComponent destroy Info`, {
|
|
48
|
+
dom: info.dom,
|
|
49
|
+
});
|
|
50
|
+
const root = rootMap.get(info.dom);
|
|
51
|
+
root?.unmount();
|
|
52
|
+
},
|
|
53
|
+
rawComponent: bridgeInfo.rootComponent,
|
|
54
|
+
__BRIDGE_FN__: (_args: T) => {},
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function ShadowRoot(info: { children: () => JSX.Element }) {
|
|
60
|
+
const [root] = useState(null);
|
|
61
|
+
const domRef = useRef(null);
|
|
62
|
+
useLayoutEffect(() => {});
|
|
63
|
+
|
|
64
|
+
return <div ref={domRef}>{root && <info.children />}</div>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// function ShadowContent() {}
|
package/src/router.tsx
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
// The upper alias react-router-dom$ into this file avoids the loop
|
|
3
|
+
import * as ReactRouterDom from 'react-router-dom/';
|
|
4
|
+
import { RouterContext } from './context';
|
|
5
|
+
import { LoggerInstance } from './utils';
|
|
6
|
+
|
|
7
|
+
function WraperRouter(
|
|
8
|
+
props:
|
|
9
|
+
| Parameters<typeof ReactRouterDom.BrowserRouter>[0]
|
|
10
|
+
| Parameters<typeof ReactRouterDom.MemoryRouter>[0],
|
|
11
|
+
) {
|
|
12
|
+
const { basename, ...propsRes } = props;
|
|
13
|
+
const routerContextProps = useContext(RouterContext) || {};
|
|
14
|
+
|
|
15
|
+
LoggerInstance.log(`WraperRouter info >>>`, {
|
|
16
|
+
...routerContextProps,
|
|
17
|
+
routerContextProps,
|
|
18
|
+
WraperRouterProps: props,
|
|
19
|
+
});
|
|
20
|
+
if (!routerContextProps) return <ReactRouterDom.BrowserRouter {...props} />;
|
|
21
|
+
|
|
22
|
+
if (routerContextProps?.memoryRoute) {
|
|
23
|
+
return (
|
|
24
|
+
<ReactRouterDom.MemoryRouter
|
|
25
|
+
{...props}
|
|
26
|
+
initialEntries={[routerContextProps?.memoryRoute.entryPath]}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return (
|
|
31
|
+
<ReactRouterDom.BrowserRouter
|
|
32
|
+
{...propsRes}
|
|
33
|
+
basename={routerContextProps?.basename || basename}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function WraperRouterProvider(
|
|
39
|
+
props: Parameters<typeof ReactRouterDom.RouterProvider>[0],
|
|
40
|
+
) {
|
|
41
|
+
const { router, ...propsRes } = props;
|
|
42
|
+
const routerContextProps = useContext(RouterContext) || {};
|
|
43
|
+
const routers = router.routes;
|
|
44
|
+
LoggerInstance.log(`WraperRouterProvider info >>>`, {
|
|
45
|
+
...routerContextProps,
|
|
46
|
+
routerContextProps,
|
|
47
|
+
WraperRouterProviderProps: props,
|
|
48
|
+
router,
|
|
49
|
+
});
|
|
50
|
+
if (!routerContextProps) return <ReactRouterDom.RouterProvider {...props} />;
|
|
51
|
+
if (routerContextProps.memoryRoute) {
|
|
52
|
+
const MemeoryRouterInstance = ReactRouterDom.createMemoryRouter(routers, {
|
|
53
|
+
initialEntries: [routerContextProps?.memoryRoute.entryPath],
|
|
54
|
+
});
|
|
55
|
+
return <ReactRouterDom.RouterProvider router={MemeoryRouterInstance} />;
|
|
56
|
+
} else {
|
|
57
|
+
const BrowserRouterInstance = ReactRouterDom.createBrowserRouter(routers, {
|
|
58
|
+
basename: routerContextProps.basename,
|
|
59
|
+
future: router.future,
|
|
60
|
+
window: router.window,
|
|
61
|
+
});
|
|
62
|
+
return (
|
|
63
|
+
<ReactRouterDom.RouterProvider
|
|
64
|
+
{...propsRes}
|
|
65
|
+
router={BrowserRouterInstance}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export * from 'react-router-dom/';
|
|
72
|
+
|
|
73
|
+
export { WraperRouter as BrowserRouter };
|
|
74
|
+
export { WraperRouterProvider as RouterProvider };
|
package/src/utils.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"useDefineForClassFields": true,
|
|
4
|
+
|
|
5
|
+
/* Bundler mode */
|
|
6
|
+
"allowImportingTsExtensions": true,
|
|
7
|
+
"resolveJsonModule": true,
|
|
8
|
+
|
|
9
|
+
"declarationDir": "./dist/types",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"module": "commonjs",
|
|
12
|
+
"target": "es5",
|
|
13
|
+
|
|
14
|
+
/* Linting */
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"declaration": true,
|
|
19
|
+
"emitDeclarationOnly": true,
|
|
20
|
+
"outDir": "dist",
|
|
21
|
+
"skipLibCheck": true,
|
|
22
|
+
"strict": true,
|
|
23
|
+
"moduleResolution": "node",
|
|
24
|
+
"lib": ["esnext", "dom"],
|
|
25
|
+
"jsx": "preserve",
|
|
26
|
+
"esModuleInterop": true,
|
|
27
|
+
"allowSyntheticDefaultImports": true,
|
|
28
|
+
"sourceMap": true,
|
|
29
|
+
"baseUrl": ".",
|
|
30
|
+
"paths": {
|
|
31
|
+
"@/*": ["src/*"]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"include": [
|
|
35
|
+
"src/**/*.ts",
|
|
36
|
+
"src/**/*.tsx",
|
|
37
|
+
"src/**/*.vue",
|
|
38
|
+
"src/remoteApp.tsx",
|
|
39
|
+
"src/create.ts"
|
|
40
|
+
],
|
|
41
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
|
42
|
+
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import vue from '@vitejs/plugin-vue';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import dts from 'vite-plugin-dts';
|
|
5
|
+
import react from '@vitejs/plugin-react';
|
|
6
|
+
import packageJson from './package.json';
|
|
7
|
+
|
|
8
|
+
const perDepsKeys = Object.keys(packageJson.peerDependencies);
|
|
9
|
+
|
|
10
|
+
export default defineConfig({
|
|
11
|
+
plugins: [
|
|
12
|
+
dts({
|
|
13
|
+
rollupTypes: true,
|
|
14
|
+
bundledPackages: [
|
|
15
|
+
'@module-federation/bridge-shared',
|
|
16
|
+
'react-error-boundary',
|
|
17
|
+
],
|
|
18
|
+
}),
|
|
19
|
+
],
|
|
20
|
+
build: {
|
|
21
|
+
lib: {
|
|
22
|
+
entry: {
|
|
23
|
+
index: path.resolve(__dirname, 'src/index.ts'),
|
|
24
|
+
router: path.resolve(__dirname, 'src/router.tsx'),
|
|
25
|
+
},
|
|
26
|
+
formats: ['cjs', 'es'],
|
|
27
|
+
fileName: (format, entryName) => `${entryName}.${format}.js`,
|
|
28
|
+
},
|
|
29
|
+
rollupOptions: {
|
|
30
|
+
external: [
|
|
31
|
+
...perDepsKeys,
|
|
32
|
+
'@remix-run/router',
|
|
33
|
+
'react-router',
|
|
34
|
+
'react-router-dom/',
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
minify: false,
|
|
38
|
+
},
|
|
39
|
+
define: {
|
|
40
|
+
__APP_VERSION__: JSON.stringify(packageJson.version),
|
|
41
|
+
},
|
|
42
|
+
});
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
define: {
|
|
6
|
+
__DEV__: true,
|
|
7
|
+
__TEST__: true,
|
|
8
|
+
__BROWSER__: false,
|
|
9
|
+
__VERSION__: '"unknow"',
|
|
10
|
+
__APP_VERSION__: '"0.0.0"',
|
|
11
|
+
},
|
|
12
|
+
plugins: [nxViteTsPaths()],
|
|
13
|
+
test: {
|
|
14
|
+
environment: 'jsdom',
|
|
15
|
+
include: [
|
|
16
|
+
path.resolve(__dirname, '__tests__/*.spec.ts'),
|
|
17
|
+
path.resolve(__dirname, '__tests__/*.spec.tsx'),
|
|
18
|
+
],
|
|
19
|
+
globals: true,
|
|
20
|
+
testTimeout: 10000,
|
|
21
|
+
},
|
|
22
|
+
});
|