Last active
November 19, 2019 13:49
-
-
Save kirill-chirkov-at-clouty/db37a02b212af6d64c021be71024f135 to your computer and use it in GitHub Desktop.
Lazy angular module loading
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable, NgModuleFactory } from '@angular/core'; | |
import { first } from 'rxjs/operators'; | |
import { OperatorSignupComponent } from '../../../components/operator-signup/operator-signup.component'; | |
import { OperatorSignupModule } from '../../../components/operator-signup/operator-signup.module'; | |
import { DialogService } from '../../../ui/dialog/dialog.service'; | |
import { ModuleKey } from '../../module-loader/models/module-key.enum'; | |
import { ModuleLoaderService } from '../../module-loader/module-loader.service'; | |
import { OperatorSignupDataModel } from './models/operator-signup-data.model'; | |
// loadChildren is essential for compiler to work, fixed in Ivy | |
// https://github.com/angular/angular/issues/32194 | |
export const OPERATOR_MODULE_LOADER = { | |
loadChildren: () => import('../../../components/operator-signup/operator-signup.module').then(m => m.OperatorSignupModule) | |
}; | |
@Injectable({ | |
providedIn: 'root', | |
}) | |
export class OperatorModalService { | |
constructor( | |
private dialog: DialogService, | |
private moduleLoader: ModuleLoaderService, | |
) { | |
} | |
public open(payload: OperatorSignupDataModel): void { | |
this.moduleLoader.moduleChanges<OperatorSignupModule>(ModuleKey.PROMO_SIGNUP, OPERATOR_MODULE_LOADER.loadChildren) | |
.pipe( | |
first(), | |
) | |
.subscribe((ngModuleFactory: NgModuleFactory<OperatorSignupModule>) => { | |
this.dialog.open(OperatorSignupComponent, {ngModuleFactory, data: payload}); | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Compiler, Injectable, Injector, NgModuleFactory, Type } from '@angular/core'; | |
import { from, Observable, of, throwError } from 'rxjs'; | |
import { filter, switchMap, catchError } from 'rxjs/operators'; | |
import { StoreKey } from '../../config/store-key.enum'; | |
import { takeUntilDestroyed } from '../../helpers/observables/take-until-destroyed'; | |
import { StoreService } from '../store/store.service'; | |
import { ModuleKey } from './models/module-key.enum'; | |
@Injectable({ | |
providedIn: 'root', | |
}) | |
export class ModuleLoaderService { | |
constructor( | |
private store: StoreService, | |
private injector: Injector, | |
) { | |
} | |
public moduleChanges<T>(moduleKey: ModuleKey, importLine: () => Promise<NgModuleFactory<T> | Type<T>>): Observable<NgModuleFactory<T>> { | |
const storeKey = this.keyOf(moduleKey); | |
if (!this.store.has(storeKey)) { | |
this.store.set(storeKey, null); | |
this.loadModule(moduleKey, importLine); | |
} | |
return this.store.itemChanges<NgModuleFactory<T>>(storeKey) | |
.pipe( | |
filter((value) => Boolean(value)), | |
); | |
} | |
private loadModule<T>(moduleKey: ModuleKey, importLine: () => Promise<NgModuleFactory<T> | Type<T>>): void { | |
from(importLine()) | |
.pipe( | |
switchMap((moduleFactoryOrType: NgModuleFactory<T> | Type<T>) => this.compile(moduleFactoryOrType)), | |
takeUntilDestroyed(this), | |
) | |
.subscribe((moduleFactory: NgModuleFactory<T>) => { | |
this.store.set(this.keyOf(moduleKey), moduleFactory); | |
}); | |
} | |
/** Convert type to factory */ | |
private compile<T>(type: NgModuleFactory<T> | Type<T>): Observable<NgModuleFactory<T>> { | |
// AOT mode | |
if (type instanceof NgModuleFactory) { | |
return of(type as NgModuleFactory<T>); | |
} | |
try { | |
// Seems like we're in JIT mode in here | |
const compiler = this.injector.get(Compiler); | |
if (compiler) { | |
try { | |
return from(compiler.compileModuleAsync(type as Type<T>)); | |
} catch (e) { | |
console.error(`Module loader failed to compile type ${type}`); | |
console.error(e); | |
return of(null); | |
} | |
} else { | |
return of(null); | |
} | |
} catch (e) { | |
return of(null); | |
} | |
} | |
private keyOf(moduleKey: ModuleKey): [StoreKey.LAZY_MODULE, string] { | |
return [StoreKey.LAZY_MODULE, `${moduleKey}`]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment