Browse Source

refactor: remove old load method of LazyLoadService

pull/4364/head
mehmet-erim 6 years ago
parent
commit
a7382b5cc9
  1. 115
      npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts
  2. 94
      npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts

115
npm/ng-packs/packages/core/src/lib/services/lazy-load.service.ts

@ -1,8 +1,7 @@
import { Injectable } from '@angular/core';
import { concat, Observable, of, ReplaySubject, throwError } from 'rxjs';
import { concat, Observable, of, throwError } from 'rxjs';
import { delay, retryWhen, shareReplay, take, tap } from 'rxjs/operators';
import { LoadingStrategy } from '../strategies';
import { uuid } from '../utils';
@Injectable({
providedIn: 'root',
@ -10,108 +9,20 @@ import { uuid } from '../utils';
export class LazyLoadService {
readonly loaded = new Map<string, HTMLScriptElement | HTMLLinkElement>();
loadedLibraries: { [url: string]: ReplaySubject<void> } = {};
load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable<Event> {
if (this.loaded.has(strategy.path)) return of(new CustomEvent('load'));
load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable<Event>;
/**
*
* @deprecated Use other overload that requires a strategy as first param
*/
load(
urlOrUrls: string | string[],
type: 'script' | 'style',
content?: string,
targetQuery?: string,
position?: InsertPosition,
): Observable<void>;
load(
strategyOrUrl: LoadingStrategy | string | string[],
retryTimesOrType?: number | 'script' | 'style',
retryDelayOrContent?: number | string,
targetQuery: string = 'body',
position: InsertPosition = 'beforeend',
): Observable<Event | void> {
if (strategyOrUrl instanceof LoadingStrategy) {
const strategy = strategyOrUrl;
const retryTimes = typeof retryTimesOrType === 'number' ? retryTimesOrType : 2;
const retryDelay = typeof retryDelayOrContent === 'number' ? retryDelayOrContent : 1000;
if (this.loaded.has(strategy.path)) return of(new CustomEvent('load'));
return strategy.createStream().pipe(
retryWhen(error$ =>
concat(
error$.pipe(delay(retryDelay), take(retryTimes)),
throwError(new CustomEvent('error')),
),
return strategy.createStream().pipe(
retryWhen(error$ =>
concat(
error$.pipe(delay(retryDelay), take(retryTimes)),
throwError(new CustomEvent('error')),
),
tap(() => this.loaded.set(strategy.path, strategy.element)),
delay(100),
shareReplay({ bufferSize: 1, refCount: true }),
);
}
let urlOrUrls = strategyOrUrl;
const content = (retryDelayOrContent as string) || '';
const type = retryTimesOrType as 'script' | 'style';
if (!urlOrUrls && !content) {
return throwError('Should pass url or content');
} else if (!urlOrUrls && content) {
urlOrUrls = [null];
}
if (!Array.isArray(urlOrUrls)) {
urlOrUrls = [urlOrUrls];
}
return new Observable(subscriber => {
(urlOrUrls as string[]).forEach((url, index) => {
const key = url ? url.slice(url.lastIndexOf('/') + 1) : uuid();
if (this.loadedLibraries[key]) {
subscriber.next();
subscriber.complete();
return;
}
this.loadedLibraries[key] = new ReplaySubject();
let library;
if (type === 'script') {
library = document.createElement('script');
library.type = 'text/javascript';
if (url) {
(library as HTMLScriptElement).src = url;
}
(library as HTMLScriptElement).text = content;
} else if (url) {
library = document.createElement('link');
library.type = 'text/css';
(library as HTMLLinkElement).rel = 'stylesheet';
if (url) {
(library as HTMLLinkElement).href = url;
}
} else {
library = document.createElement('style');
(library as HTMLStyleElement).textContent = content;
}
library.onload = () => {
this.loadedLibraries[key].next();
this.loadedLibraries[key].complete();
if (index === urlOrUrls.length - 1) {
subscriber.next();
subscriber.complete();
}
};
document.querySelector(targetQuery).insertAdjacentElement(position, library);
});
});
),
tap(() => this.loaded.set(strategy.path, strategy.element)),
delay(100),
shareReplay({ bufferSize: 1, refCount: true }),
);
}
remove(path: string): boolean {

94
npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts

@ -1,6 +1,5 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { of, throwError } from 'rxjs';
import { catchError, switchMap } from 'rxjs/operators';
import { switchMap } from 'rxjs/operators';
import { LazyLoadService } from '../services/lazy-load.service';
import { ScriptLoadingStrategy } from '../strategies';
@ -84,94 +83,3 @@ describe('LazyLoadService', () => {
});
});
});
describe('LazyLoadService (Deprecated)', () => {
let spectator: SpectatorService<LazyLoadService>;
let service: LazyLoadService;
const scriptElement = document.createElement('script');
const linkElement = document.createElement('link');
const styleElement = document.createElement('style');
const cloneDocument = { ...document };
const createService = createServiceFactory({ service: LazyLoadService });
beforeEach(() => {
spectator = createService();
service = spectator.service;
});
afterEach(() => (document = { ...cloneDocument }));
test('should load script with content just one time', done => {
const spy = jest.spyOn(document, 'createElement');
spy.mockReturnValue(scriptElement);
service.load('https://abp.io', 'script', 'test').subscribe(res => {
expect(
document.querySelector('script[src="https://abp.io"][type="text/javascript"]').textContent,
).toMatch('test');
});
scriptElement.onload(null);
service.load('https://abp.io', 'script', 'test').subscribe(res => {
expect(
document.querySelectorAll('script[src="https://abp.io"][type="text/javascript"]'),
).toHaveLength(1);
done();
});
});
test('should load style element', done => {
const spy = jest.spyOn(document, 'createElement');
spy.mockReturnValue(styleElement);
const content = '* { color: black; }';
service.load(null, 'style', content).subscribe(res => {
expect(document.querySelector('style').textContent).toMatch(content);
done();
});
styleElement.onload(null);
});
describe('style with url', () => {
beforeEach(() => {
const spy = jest.spyOn(document, 'createElement');
spy.mockReturnValue(linkElement);
});
test('should load an link element', done => {
service.load('https://abp.io', 'style').subscribe(res => {
expect(
document.querySelector('link[type="text/css"][rel="stylesheet"][href="https://abp.io"]'),
).toBeTruthy();
done();
});
linkElement.onload(null);
});
test('should load link elements', done => {
service.load(['https://abp.io', 'https://volosoft.com'], 'style').subscribe(res => {
expect(document.querySelector('link[href="https://volosoft.com"]')).toBeTruthy();
done();
});
linkElement.onload(null);
});
});
test('should throw error when required parameters are null', done => {
service
.load(null, 'style')
.pipe(
catchError(err => {
expect(err).toBeTruthy();
done();
return of(null);
}),
)
.subscribe();
});
});

Loading…
Cancel
Save