Skip to content

Instantly share code, notes, and snippets.

@MurhafSousli
Last active November 18, 2019 05:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MurhafSousli/ba5e479a3c9dd80c76d68a6c7ac9a9d8 to your computer and use it in GitHub Desktop.
Save MurhafSousli/ba5e479a3c9dd80c76d68a6c7ac9a9d8 to your computer and use it in GitHub Desktop.
Article code
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)
);
};
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