Skip to content

Commit a79f613

Browse files
committed
refactor: refactor dynamic module to use async function instead of rxjs
1 parent fcd9108 commit a79f613

File tree

5 files changed

+73
-83
lines changed

5 files changed

+73
-83
lines changed

extra-webpack.config.ts

+10-33
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,17 @@ export default {
77
},
88
plugins: [
99
new ModuleFederationPlugin({
10-
remotes: {
11-
mfe1: 'mfe1'
12-
},
1310
shared: {
14-
'@angular/core': {
15-
eager: true
16-
},
17-
'@angular/common': {
18-
eager: true
19-
},
20-
'@angular/common/': {
21-
eager: true
22-
},
23-
'@angular/router': {
24-
eager: true
25-
},
26-
'@angular/cdk': {
27-
eager: true
28-
},
29-
'@angular/cdk/': {
30-
eager: true
31-
},
32-
'@angular/material': {
33-
eager: true
34-
},
35-
'@angular/material/': {
36-
eager: true
37-
},
38-
rxjs: {
39-
eager: true
40-
},
41-
'rxjs/': {
42-
eager: true
43-
}
11+
'@angular/core': { eager: true },
12+
'@angular/common': { eager: true },
13+
'@angular/common/': { eager: true },
14+
'@angular/router': { eager: true },
15+
'@angular/cdk': { eager: true },
16+
'@angular/cdk/': { eager: true },
17+
'@angular/material': { eager: true },
18+
'@angular/material/': { eager: true },
19+
rxjs: { eager: true },
20+
'rxjs/': { eager: true }
4421
}
4522
})
4623
]

package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
"name": "angular-module-federation",
33
"version": "0.0.0",
44
"scripts": {
5-
"build": "ng build && ng build mf1",
6-
"serve:dist": "concurrently \"serve dist/shell -l 5000 -s\" \"serve dist/mf1 -l 3000 -s\" "
5+
"serve": "concurrently \"ng s -o\" \"ng s mf1\" \"ng s mf2\""
76
},
87
"private": true,
98
"resolutions": {

proxy.conf.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ const PROXY_CONFIG = [
44
'/mf1'
55
],
66
target: 'http://localhost:3000/',
7-
rewritePath: '',
87
changeOrigin: true,
9-
logLevel: 'debug',
108
pathRewrite: {
11-
'^/mf1': '', // rewrite path
9+
'^/mf1': '',
1210
}
1311
},
1412
];

src/app/app-routing.module.ts

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import { NgModule } from '@angular/core';
2-
import { Routes, RouterModule } from '@angular/router';
3-
import { map } from 'rxjs/operators';
4-
import { load } from './dynamic-module';
2+
import { RouterModule, Routes } from '@angular/router';
3+
import { loadRemoteModule } from './dynamic-module';
54

65
const routes: Routes = [
76
{
87
path: 'cathedrals',
9-
loadChildren: () => load('http://localhost:3000/', 'mf1', 'Module').pipe(
10-
map((module: any) => module.CathedralModule)
11-
).toPromise()
8+
loadChildren: () => loadRemoteModule('http://localhost:3000/remoteEntry.js', 'mf1', 'Module')
9+
.then(module => module.CathedralModule)
1210
},
1311
{
1412
path: 'cities',
15-
loadChildren: () => load('http://localhost:4000/', 'mf2', 'Module').pipe(
16-
map((module: any) => module.CityModule)
17-
)
13+
loadChildren: () => loadRemoteModule('http://localhost:4000/remoteEntry.js', 'mf2', 'Module')
14+
.then(module => module.CityModule)
1815
},
1916
{
2017
path: '',

src/app/dynamic-module.ts

+55-36
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,58 @@
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;
1732
}
1833

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+
}));
3958
}

0 commit comments

Comments
 (0)