@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.
@@ -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
@@ -0,0 +1,3 @@
1
+ import { Logger } from '@module-federation/bridge-shared';
2
+
3
+ export const LoggerInstance = new Logger('bridge-react');
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
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true,
8
+ "strict": true
9
+ },
10
+ "include": ["vite.config.ts"]
11
+ }
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
+ });
@@ -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
+ });