|
1 |
| -import { Type } from '@angular/core'; |
2 |
| -import { from, fromEvent, Observable, of } from 'rxjs'; |
3 |
| -import { delayWhen, first, map, switchMap, tap } from 'rxjs/operators'; |
4 |
| - |
5 |
| -declare function __webpack_init_sharing__(scope: string): Promise<void>; |
6 |
| - |
7 |
| -declare var __webpack_share_scopes__: any; |
8 |
| - |
9 |
| -export function load(url: string, id: string, moduleName: string): Observable<Type<any>> { |
10 |
| - return loadRemoteEntry(url, id) |
11 |
| - .pipe( |
12 |
| - tap(() => __webpack_init_sharing__('default')), |
13 |
| - tap((module: any) => module.init(__webpack_share_scopes__.default)), |
14 |
| - switchMap((module: any) => from(module.get(moduleName))), |
15 |
| - map((factory: any) => factory()) |
16 |
| - ); |
| 1 | +type Scope = unknown; |
| 2 | +type Factory = () => any; |
| 3 | + |
| 4 | +type Container = { |
| 5 | + init(shareScope: Scope): void; |
| 6 | + get(module: string): Factory; |
| 7 | +}; |
| 8 | + |
| 9 | +declare const __webpack_init_sharing__: (shareScope: string) => Promise<void>; |
| 10 | +declare const __webpack_share_scopes__: { default: Scope }; |
| 11 | + |
| 12 | +/** |
| 13 | + * Loads a remote with the given name an gets the given module from the container. |
| 14 | + * @param remoteEntryUrl url pointing to the remoteEntry.js of the remote |
| 15 | + * @param remoteName name of the remote declared by the remote |
| 16 | + * @param moduleName name of the exposed module |
| 17 | + */ |
| 18 | +export async function loadRemoteModule<T>(remoteEntryUrl: string, remoteName: string, moduleName: string): Promise<any> { |
| 19 | + await loadRemoteEntry(remoteEntryUrl); |
| 20 | + await loadRemoteEntry(remoteEntryUrl); |
| 21 | + |
| 22 | + // initialize default scope |
| 23 | + await __webpack_init_sharing__('default'); |
| 24 | + // get the remote container from the window |
| 25 | + const container = window[remoteName] as Container; |
| 26 | + |
| 27 | + // initialize the remote container with the default scope |
| 28 | + container.init(__webpack_share_scopes__.default); |
| 29 | + // get the factory from the container |
| 30 | + const factory = await container.get(moduleName); |
| 31 | + return factory() as T; |
17 | 32 | }
|
18 | 33 |
|
19 |
| -export function loadRemoteEntry(url: string, |
20 |
| - id: string): Observable<any> { |
21 |
| - const module = document.getElementById(id); |
22 |
| - |
23 |
| - if (module) { |
24 |
| - return of(window[id]); |
25 |
| - } |
26 |
| - |
27 |
| - const script = scriptTag(url, id); |
28 |
| - const load$ = fromEvent(script, 'load').pipe(first()); |
29 |
| - document.head.appendChild(script); |
30 |
| - |
31 |
| - return load$.pipe(map(() => window[id])); |
32 |
| -} |
33 |
| - |
34 |
| -function scriptTag(url: string, moduleName: string): HTMLScriptElement { |
35 |
| - const script = document.createElement('script'); |
36 |
| - script.src = url + 'remoteEntry.js'; |
37 |
| - script.id = moduleName; |
38 |
| - return script; |
| 34 | +const loadedModules = {}; |
| 35 | + |
| 36 | +/** |
| 37 | + * Loads the remoteEntry file by appending it to the head. |
| 38 | + * @param url url pointing to the remoteEntry.js of the remote |
| 39 | + */ |
| 40 | +async function loadRemoteEntry(url: string): Promise<void> { |
| 41 | + return new Promise<void>(((resolve, reject) => { |
| 42 | + |
| 43 | + if (loadedModules[url]) { |
| 44 | + resolve(); |
| 45 | + return; |
| 46 | + } |
| 47 | + |
| 48 | + const script = document.createElement('script'); |
| 49 | + script.src = url; |
| 50 | + |
| 51 | + script.onerror = reject; |
| 52 | + script.onload = () => { |
| 53 | + loadedModules[url] = true; |
| 54 | + resolve(); |
| 55 | + }; |
| 56 | + document.head.appendChild(script); |
| 57 | + })); |
39 | 58 | }
|
0 commit comments