Browse Source

feat(core): add loading strategies

pull/3453/head
Arman Ozak 6 years ago
parent
commit
79b0806718
  1. 1
      npm/ng-packs/packages/core/src/lib/strategies/index.ts
  2. 68
      npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts
  3. 90
      npm/ng-packs/packages/core/src/lib/tests/loading.strategy.spec.ts

1
npm/ng-packs/packages/core/src/lib/strategies/index.ts

@ -1,2 +1,3 @@
export * from './cross-origin.strategy';
export * from './dom.strategy';
export * from './loading.strategy';

68
npm/ng-packs/packages/core/src/lib/strategies/loading.strategy.ts

@ -0,0 +1,68 @@
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { fromLazyLoad } from '../utils';
import { CrossOriginStrategy, CROSS_ORIGIN_STRATEGY } from './cross-origin.strategy';
import { DomStrategy, DOM_STRATEGY } from './dom.strategy';
export abstract class LoadingStrategy<T extends HTMLScriptElement | HTMLLinkElement = any> {
constructor(
public path: string,
protected domStrategy: DomStrategy = DOM_STRATEGY.AppendToHead(),
protected crossOriginStrategy: CrossOriginStrategy = CROSS_ORIGIN_STRATEGY.Anonymous(),
) {}
abstract createElement(): T;
createStream<T extends Event>(): Observable<T> {
return of(null).pipe(
switchMap(() =>
fromLazyLoad<T>(this.createElement(), this.domStrategy, this.crossOriginStrategy),
),
);
}
}
export class ScriptLoadingStrategy extends LoadingStrategy<HTMLScriptElement> {
constructor(src: string, domStrategy?: DomStrategy, crossOriginStrategy?: CrossOriginStrategy) {
super(src, domStrategy, crossOriginStrategy);
}
createElement(): HTMLScriptElement {
const element = document.createElement('script');
element.src = this.path;
return element;
}
}
export class StyleLoadingStrategy extends LoadingStrategy<HTMLLinkElement> {
constructor(href: string, domStrategy?: DomStrategy, crossOriginStrategy?: CrossOriginStrategy) {
super(href, domStrategy, crossOriginStrategy);
}
createElement(): HTMLLinkElement {
const element = document.createElement('link');
element.rel = 'stylesheet';
element.href = this.path;
return element;
}
}
export const LOADING_STRATEGY = {
AppendAnonymousScriptToBody(src: string) {
return new ScriptLoadingStrategy(src, DOM_STRATEGY.AppendToBody());
},
AppendAnonymousScriptToHead(src: string) {
return new ScriptLoadingStrategy(src);
},
AppendAnonymousStyleToHead(src: string) {
return new StyleLoadingStrategy(src);
},
PrependAnonymousScriptToHead(src: string) {
return new ScriptLoadingStrategy(src, DOM_STRATEGY.PrependToHead());
},
PrependAnonymousStyleToHead(src: string) {
return new StyleLoadingStrategy(src, DOM_STRATEGY.PrependToHead());
},
};

90
npm/ng-packs/packages/core/src/lib/tests/loading.strategy.spec.ts

@ -0,0 +1,90 @@
import {
CROSS_ORIGIN_STRATEGY,
DOM_STRATEGY,
LOADING_STRATEGY,
ScriptLoadingStrategy,
StyleLoadingStrategy,
} from '../strategies';
const path = 'http://example.com/';
describe('ScriptLoadingStrategy', () => {
describe('#createElement', () => {
it('should return a script element with src attribute', () => {
const strategy = new ScriptLoadingStrategy(path);
const element = strategy.createElement();
expect(element.tagName).toBe('SCRIPT');
expect(element.src).toBe(path);
});
});
describe('#createStream', () => {
it('should use given dom and cross-origin strategies', done => {
const domStrategy = DOM_STRATEGY.PrependToHead();
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials();
domStrategy.insertElement = jest.fn((el: HTMLScriptElement) => {
setTimeout(() => {
el.onload(new CustomEvent('success', { detail: el.crossOrigin }));
}, 0);
}) as any;
const strategy = new ScriptLoadingStrategy(path, domStrategy, crossOriginStrategy);
strategy.createStream<CustomEvent>().subscribe(event => {
expect(event.detail).toBe('use-credentials');
done();
});
});
});
});
describe('StyleLoadingStrategy', () => {
describe('#createElement', () => {
it('should return a style element with href and rel attributes', () => {
const strategy = new StyleLoadingStrategy(path);
const element = strategy.createElement();
expect(element.tagName).toBe('LINK');
expect(element.href).toBe(path);
expect(element.rel).toBe('stylesheet');
});
});
describe('#createStream', () => {
it('should use given dom and cross-origin strategies', done => {
const domStrategy = DOM_STRATEGY.PrependToHead();
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials();
domStrategy.insertElement = jest.fn((el: HTMLLinkElement) => {
setTimeout(() => {
el.onload(new CustomEvent('success', { detail: el.crossOrigin }));
}, 0);
}) as any;
const strategy = new StyleLoadingStrategy(path, domStrategy, crossOriginStrategy);
strategy.createStream<CustomEvent>().subscribe(event => {
expect(event.detail).toBe('use-credentials');
done();
});
});
});
});
describe('LOADING_STRATEGY', () => {
test.each`
name | Strategy | domStrategy
${'AppendAnonymousScriptToBody'} | ${ScriptLoadingStrategy} | ${'AppendToBody'}
${'AppendAnonymousScriptToHead'} | ${ScriptLoadingStrategy} | ${'AppendToHead'}
${'AppendAnonymousStyleToHead'} | ${StyleLoadingStrategy} | ${'AppendToHead'}
${'PrependAnonymousScriptToHead'} | ${ScriptLoadingStrategy} | ${'PrependToHead'}
${'PrependAnonymousStyleToHead'} | ${StyleLoadingStrategy} | ${'PrependToHead'}
`(
'should successfully map $name to $Strategy.name with $domStrategy dom strategy',
({ name, Strategy, domStrategy }) => {
expect(LOADING_STRATEGY[name](path)).toEqual(new Strategy(path, DOM_STRATEGY[domStrategy]()));
},
);
});
Loading…
Cancel
Save