Last active
November 18, 2019 05:25
-
-
Save MurhafSousli/ba5e479a3c9dd80c76d68a6c7ac9a9d8 to your computer and use it in GitHub Desktop.
Article code
This file contains hidden or 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, PLATFORM_ID } from '@angular/core'; | |
import { DOCUMENT, isPlatformBrowser } from '@angular/common'; | |
import { BehaviorSubject, Observable, from, EMPTY } from 'rxjs'; | |
import { catchError, tap, map, filter, take } from 'rxjs/operators'; | |
import { ExternalLibrary, ExternalLibraryOptions, EXTERNAL_LIBRARY_OPTIONS } from './models'; | |
// @dynamic | |
@Injectable({ | |
providedIn: 'root' | |
}) | |
export class ExternalLibraryLoader { | |
// Source stream, should be kept private | |
private readonly _ready = new BehaviorSubject(null); | |
// Stream that emits when the external library is loaded and ready to use | |
readonly ready = this._ready.asObservable().pipe( | |
filter((hljs: ExternalLibrary) => !!hljs), | |
take(1) | |
); | |
constructor(@Inject(DOCUMENT) doc: any, | |
@Inject(PLATFORM_ID) platformId: object) { | |
// Check if script is already provided by user | |
if (isPlatformBrowser(platformId) && doc.defaultView[libName]) { | |
this._ready.next(doc.defaultView[libName]); | |
} else { | |
// Load external library | |
loadExternalLibrary().pipe( | |
tap((lib: ExternalLibrary) => { | |
// Sometimes the external library has to be available in `window` object as property to make this work | |
doc.defaultView[libName] = lib; | |
// In case you want to set library options | |
if (this._options) { | |
lib.configure(this._options); | |
} | |
// Set state to ready | |
this._ready.next(lib); | |
}), | |
// Handle loader errors | |
catchError((e: any) => { | |
console.error('Unable to load external library', e); | |
return EMPTY; | |
}) | |
).subscribe(); | |
} | |
} | |
} | |
/** | |
* Import external library | |
*/ | |
function loadExternalLibrary(): Observable<any> { | |
return importModule(import('highlight.js')); | |
} | |
/** | |
* Map loader response to module object | |
*/ | |
function importModule(moduleLoader: Promise<any>): Observable<any> { | |
return from(moduleLoader).pipe( | |
filter((module: any) => !!module && !!module.default), | |
map((module: any) => module.default) | |
); | |
}; | |
This file contains hidden or 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, Inject, Optional } from '@angular/core'; | |
import { Observable } from 'rxjs'; | |
import { map } from 'rxjs/operators'; | |
import { ExternalLibraryLoader } from './loader'; | |
import { ExternalLibrary, ExternalLibraryOptions, EXTERNAL_LIBRARY_OPTIONS } from './models'; | |
@Injectable({ | |
providedIn: 'root' | |
}) | |
export class ExternalLibraryService { | |
constructor(private _loader: ExternalLibraryLoader, | |
@Optional() @Inject(EXTERNAL_LIBRARY_OPTIONS) private _options: ExternalLibraryOptions) { | |
// (Optional) Execute some code once library is lazy-loaded and ready to use | |
_loader.ready.pipe().subscribe((lib: ExternalLibrary) => { | |
// (Optional) Set library options if presented | |
if (options) { | |
// (Assuming library has a set config function) | |
lib.configure(options.config); | |
} | |
}); | |
} | |
/** | |
* Start exposing all the library's functions that you need as observables | |
*/ | |
doSomething(params: any): Observable<void> { | |
return this._loader.ready.pipe( | |
map((lib: ExternalLibrary) => lib.doSomething(params)) | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment