1
- import React , { useContext , useEffect , useMemo , useRef , useState } from 'react' ;
2
- import * as ReactRouterDOM from 'react-router-dom' ;
1
+ import React , { forwardRef } from 'react' ;
3
2
import type { ProviderParams } from '@module-federation/bridge-shared' ;
4
- import { LoggerInstance , pathJoin } from './utils' ;
5
- import { dispatchPopstateEnv } from '@module-federation/bridge-shared' ;
3
+ import { LoggerInstance } from './utils' ;
6
4
import {
7
5
ErrorBoundary ,
8
6
ErrorBoundaryPropsWithComponent ,
9
7
} from 'react-error-boundary' ;
10
-
11
- declare const __APP_VERSION__ : string ;
8
+ import RemoteApp from './remote' ;
12
9
13
10
export interface RenderFnParams extends ProviderParams {
14
11
dom ?: any ;
@@ -25,79 +22,67 @@ interface RemoteModule {
25
22
} ;
26
23
}
27
24
28
- interface RemoteAppParams {
29
- name : string ;
30
- providerInfo : NonNullable < RemoteModule [ 'provider' ] > ;
31
- dispathPopstate : boolean ;
32
- }
33
-
34
- const RemoteApp = ( {
35
- name,
36
- memoryRoute,
37
- basename,
38
- providerInfo,
39
- dispathPopstate,
40
- ...resProps
41
- } : RemoteAppParams & ProviderParams ) => {
42
- const rootRef = useRef ( null ) ;
43
- const renderDom = useRef ( null ) ;
44
- const providerInfoRef = useRef < any > ( null ) ;
45
- if ( dispathPopstate ) {
46
- const location = ReactRouterDOM . useLocation ( ) ;
47
- const [ pathname , setPathname ] = useState ( location . pathname ) ;
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
-
61
- useEffect ( ( ) => {
62
- const renderTimeout = setTimeout ( ( ) => {
63
- const providerReturn = providerInfo ( ) ;
64
- providerInfoRef . current = providerReturn ;
65
- const renderProps = {
66
- name,
67
- dom : rootRef . current ,
68
- basename,
69
- memoryRoute,
70
- ...resProps ,
71
- } ;
72
- renderDom . current = rootRef . current ;
25
+ function createLazyRemoteComponent < T , E extends keyof T > ( info : {
26
+ loader : ( ) => Promise < T > ;
27
+ loading : React . ReactNode ;
28
+ fallback : ErrorBoundaryPropsWithComponent [ 'FallbackComponent' ] ;
29
+ export ?: E ;
30
+ } ) {
31
+ const exportName = info ?. export || 'default' ;
32
+ return React . lazy ( async ( ) => {
33
+ LoggerInstance . log ( `createRemoteComponent LazyComponent create >>>` , {
34
+ lazyComponent : info . loader ,
35
+ exportName,
36
+ } ) ;
37
+ try {
38
+ const m = ( await info . loader ( ) ) as RemoteModule ;
39
+ // @ts -ignore
40
+ const moduleName = m && m [ Symbol . for ( 'mf_module_id' ) ] ;
73
41
LoggerInstance . log (
74
- `createRemoteComponent LazyComponent render >>>` ,
75
- renderProps ,
42
+ `createRemoteComponent LazyComponent loadRemote info >>>` ,
43
+ { name : moduleName , module : m , exportName } ,
76
44
) ;
77
- providerReturn . render ( renderProps ) ;
78
- } ) ;
79
45
80
- return ( ) => {
81
- clearTimeout ( renderTimeout ) ;
82
- setTimeout ( ( ) => {
83
- if ( providerInfoRef . current ?. destroy ) {
84
- LoggerInstance . log (
85
- `createRemoteComponent LazyComponent destroy >>>` ,
86
- { name, basename, dom : renderDom . current } ,
87
- ) ;
88
- providerInfoRef . current ?. destroy ( {
89
- dom : renderDom . current ,
90
- } ) ;
91
- }
92
- } ) ;
93
- } ;
94
- } , [ ] ) ;
46
+ // @ts -ignore
47
+ const exportFn = m [ exportName ] as any ;
95
48
96
- //@ts -ignore
97
- return < div ref = { rootRef } > </ div > ;
98
- } ;
49
+ if ( exportName in m && typeof exportFn === 'function' ) {
50
+ const RemoteAppComponent = forwardRef <
51
+ HTMLDivElement ,
52
+ {
53
+ basename ?: ProviderParams [ 'basename' ] ;
54
+ memoryRoute ?: ProviderParams [ 'memoryRoute' ] ;
55
+ }
56
+ > ( ( props , _ref ) => {
57
+ return (
58
+ < RemoteApp
59
+ name = { moduleName }
60
+ providerInfo = { exportFn }
61
+ exportName = { info . export || 'default' }
62
+ { ...props }
63
+ />
64
+ ) ;
65
+ } ) ;
99
66
100
- ( RemoteApp as any ) [ '__APP_VERSION__' ] = __APP_VERSION__ ;
67
+ return {
68
+ default : RemoteAppComponent ,
69
+ } ;
70
+ } else {
71
+ LoggerInstance . log (
72
+ `createRemoteComponent LazyComponent module not found >>>` ,
73
+ { name : moduleName , module : m , exportName } ,
74
+ ) ;
75
+ throw Error (
76
+ `Make sure that ${ moduleName } has the correct export when export is ${ String (
77
+ exportName ,
78
+ ) } `,
79
+ ) ;
80
+ }
81
+ } catch ( error ) {
82
+ throw error ;
83
+ }
84
+ } ) ;
85
+ }
101
86
102
87
export function createRemoteComponent < T , E extends keyof T > ( info : {
103
88
loader : ( ) => Promise < T > ;
@@ -114,121 +99,18 @@ export function createRemoteComponent<T, E extends keyof T>(info: {
114
99
: { }
115
100
: { } ;
116
101
102
+ const LazyComponent = createLazyRemoteComponent ( info ) ;
103
+
117
104
return (
118
105
props : {
119
106
basename ?: ProviderParams [ 'basename' ] ;
120
107
memoryRoute ?: ProviderParams [ 'memoryRoute' ] ;
121
108
} & RawComponentType ,
122
109
) => {
123
- const exportName = info ?. export || 'default' ;
124
- let basename = '/' ;
125
- let enableDispathPopstate = false ;
126
- let routerContextVal : any ;
127
- try {
128
- ReactRouterDOM . useLocation ( ) ;
129
- enableDispathPopstate = true ;
130
- } catch {
131
- enableDispathPopstate = false ;
132
- }
133
-
134
- if ( props . basename ) {
135
- basename = props . basename ;
136
- } else if ( enableDispathPopstate ) {
137
- const ReactRouterDOMAny : any = ReactRouterDOM ;
138
- // Avoid building tools checking references
139
- const useRouteMatch = ReactRouterDOMAny [ 'use' + 'RouteMatch' ] ; //v5
140
- const useHistory = ReactRouterDOMAny [ 'use' + 'History' ] ; //v5
141
- const useHref = ReactRouterDOMAny [ 'use' + 'Href' ] ;
142
- const UNSAFE_RouteContext = ReactRouterDOMAny [ 'UNSAFE_' + 'RouteContext' ] ;
143
-
144
- if ( UNSAFE_RouteContext /* react-router@6 */ ) {
145
- if ( useHref ) {
146
- basename = useHref ?.( '/' ) ;
147
- }
148
- routerContextVal = useContext ( UNSAFE_RouteContext ) ;
149
- if (
150
- routerContextVal &&
151
- routerContextVal . matches &&
152
- routerContextVal . matches [ 0 ] &&
153
- routerContextVal . matches [ 0 ] . pathnameBase
154
- ) {
155
- basename = pathJoin (
156
- basename ,
157
- routerContextVal . matches [ 0 ] . pathnameBase || '/' ,
158
- ) ;
159
- }
160
- } /* react-router@5 */ else {
161
- const match = useRouteMatch ?.( ) ; // v5
162
- if ( useHistory /* react-router@5 */ ) {
163
- // there is no dynamic switching of the router version in the project
164
- // so hooks can be used in conditional judgment
165
- const history = useHistory ?.( ) ;
166
- // To be compatible to [email protected] and @5.3.0 we cannot write like this `history.createHref(pathname)`
167
- basename = history ?. createHref ?.( { pathname : '/' } ) ;
168
- }
169
- if ( match /* react-router@5 */ ) {
170
- basename = pathJoin ( basename , match ?. path || '/' ) ;
171
- }
172
- }
173
- }
174
-
175
- const LazyComponent = useMemo ( ( ) => {
176
- //@ts -ignore
177
- return React . lazy ( async ( ) => {
178
- LoggerInstance . log ( `createRemoteComponent LazyComponent create >>>` , {
179
- basename,
180
- lazyComponent : info . loader ,
181
- exportName,
182
- props,
183
- routerContextVal,
184
- } ) ;
185
- try {
186
- const m = ( await info . loader ( ) ) as RemoteModule ;
187
- // @ts -ignore
188
- const moduleName = m && m [ Symbol . for ( 'mf_module_id' ) ] ;
189
- LoggerInstance . log (
190
- `createRemoteComponent LazyComponent loadRemote info >>>` ,
191
- { basename, name : moduleName , module : m , exportName, props } ,
192
- ) ;
193
-
194
- // @ts -ignore
195
- const exportFn = m [ exportName ] as any ;
196
-
197
- if ( exportName in m && typeof exportFn === 'function' ) {
198
- return {
199
- default : ( ) => (
200
- < RemoteApp
201
- name = { moduleName }
202
- dispathPopstate = { enableDispathPopstate }
203
- { ...info }
204
- { ...props }
205
- providerInfo = { exportFn }
206
- basename = { basename }
207
- />
208
- ) ,
209
- } ;
210
- } else {
211
- LoggerInstance . log (
212
- `createRemoteComponent LazyComponent module not found >>>` ,
213
- { basename, name : moduleName , module : m , exportName, props } ,
214
- ) ;
215
- throw Error (
216
- `Make sure that ${ moduleName } has the correct export when export is ${ String (
217
- exportName ,
218
- ) } `,
219
- ) ;
220
- }
221
- } catch ( error ) {
222
- throw error ;
223
- }
224
- } ) ;
225
- } , [ exportName , basename , props . memoryRoute ] ) ;
226
-
227
- //@ts -ignore
228
110
return (
229
111
< ErrorBoundary FallbackComponent = { info . fallback } >
230
112
< React . Suspense fallback = { info . loading } >
231
- < LazyComponent />
113
+ < LazyComponent { ... props } />
232
114
</ React . Suspense >
233
115
</ ErrorBoundary >
234
116
) ;
0 commit comments