🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

@internetarchive/lazy-loader-service

Package Overview
Dependencies
Maintainers
13
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@internetarchive/lazy-loader-service - npm Package Compare versions

Comparing version
0.2.0-alpha.1
to
0.2.0-alpha.2
+6
-1
dist/src/lazy-loader-service.js

@@ -88,3 +88,8 @@ import { __awaiter } from "tslib";

else {
this.emitter.emit('scriptLoadFailed', options.src, error);
// only emit a failure event from the last attempt, which has not been retried.
// otherwise you get failure events from each script tag, when we're really
// only interested that the entire chain failed
if (!hasBeenRetried) {
this.emitter.emit('scriptLoadFailed', options.src, error);
}
originalOnError === null || originalOnError === void 0 ? void 0 : originalOnError(error);

@@ -91,0 +96,0 @@ reject(error);

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"lazy-loader-service.js","sourceRoot":"","sources":["../../src/lazy-loader-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { createNanoEvents, Unsubscribe } from 'nanoevents';\nimport type { BundleType } from './bundle-type';\nimport {\n LazyLoaderServiceEvents,\n LazyLoaderServiceInterface,\n} from './lazy-loader-service-interface';\nimport { promisedSleep } from './promised-sleep';\n\nexport interface LazyLoaderServiceOptions {\n /**\n * The HTMLElement in which we put the script tags, defaults to document.head\n */\n container?: HTMLElement;\n\n /**\n * The number of retries we should attempt\n */\n retryCount?: number;\n\n /**\n * The retry interval in seconds\n */\n retryInterval?: number;\n}\n\nexport class LazyLoaderService implements LazyLoaderServiceInterface {\n // the HTMLElement in which we put the script tags, defaults to document.head\n private container: HTMLElement;\n\n // the number of retries we should attempt\n private retryCount: number;\n\n // the retry interval in seconds\n private retryInterval: number;\n\n // the emitter for consumers to listen for events like retrying a load\n private emitter = createNanoEvents<LazyLoaderServiceEvents>();\n\n /**\n * LazyLoaderService constructor\n *\n * @param options LazyLoaderServiceOptions\n */\n constructor(options?: LazyLoaderServiceOptions) {\n this.container = options?.container ?? document.head;\n this.retryCount = options?.retryCount ?? 2;\n this.retryInterval = options?.retryInterval ?? 1;\n }\n\n /** @inheritdoc */\n on<E extends keyof LazyLoaderServiceEvents>(\n event: E,\n callback: LazyLoaderServiceEvents[E]\n ): Unsubscribe {\n return this.emitter.on(event, callback);\n }\n\n /** @inheritdoc */\n async loadBundle(bundle: {\n module?: string;\n nomodule?: string;\n }): Promise<void> {\n let modulePromise: Promise<void> | undefined;\n let nomodulePromise: Promise<void> | undefined;\n\n /* istanbul ignore else */\n if (bundle.module) {\n modulePromise = this.loadScript({\n src: bundle.module,\n bundleType: 'module',\n });\n }\n\n /* istanbul ignore else */\n if (bundle.nomodule) {\n nomodulePromise = this.loadScript({\n src: bundle.nomodule,\n bundleType: 'nomodule',\n });\n }\n\n return Promise.race([modulePromise, nomodulePromise]);\n }\n\n /** @inheritdoc */\n async loadScript(options: {\n src: string;\n bundleType?: BundleType;\n attributes?: Record<string, string>;\n }): Promise<void> {\n return this.doLoad(options);\n }\n\n private async doLoad(options: {\n src: string;\n bundleType?: BundleType;\n attributes?: Record<string, string>;\n retryCount?: number;\n scriptBeingRetried?: HTMLScriptElement;\n }): Promise<void> {\n const retryCount = options.retryCount ?? 0;\n const scriptSelector = `script[src='${options.src}'][async][retryCount='${retryCount}']`;\n let script = this.container.querySelector(\n scriptSelector\n ) as HTMLScriptElement;\n if (!script) {\n script = this.getScriptTag(options);\n this.container.appendChild(script);\n }\n\n return new Promise((resolve, reject) => {\n // script has already been loaded, just resolve\n if (script.getAttribute('dynamicImportLoaded')) {\n resolve();\n return;\n }\n\n const scriptBeingRetried = options.scriptBeingRetried;\n\n // If multiple requests get made for this script, just stack the `onload`s\n // and `onerror`s and all the callbacks will be called in-order of being received.\n // If we are retrying the load, we use the `onload` / `onerror` from the script being retried\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const originalOnLoad: ((event: Event) => any) | null | undefined =\n script.onload || scriptBeingRetried?.onload;\n\n script.onload = (event): void => {\n originalOnLoad?.(event);\n script.setAttribute('dynamicImportLoaded', 'true');\n resolve();\n };\n\n const originalOnError: OnErrorEventHandler | null | undefined =\n script.onerror || scriptBeingRetried?.onerror;\n\n script.onerror = async (error): Promise<void> => {\n const hasBeenRetried = script.getAttribute('hasBeenRetried');\n if (retryCount < this.retryCount && !hasBeenRetried) {\n script.setAttribute('hasBeenRetried', 'true');\n await promisedSleep(this.retryInterval * 1000);\n const newRetryCount = retryCount + 1;\n this.emitter.emit('scriptLoadRetried', options.src, newRetryCount);\n this.doLoad({\n ...options,\n retryCount: newRetryCount,\n scriptBeingRetried: script,\n });\n } else {\n this.emitter.emit('scriptLoadFailed', options.src, error);\n originalOnError?.(error);\n reject(error);\n }\n };\n });\n }\n\n /**\n * Generate a script tag with all of the proper attributes\n *\n * @param options\n * @returns\n */\n private getScriptTag(options: {\n src: string;\n retryCount?: number;\n bundleType?: BundleType;\n attributes?: Record<string, string>;\n }): HTMLScriptElement {\n const fixedSrc = options.src.replace(\"'\", '\"');\n const script = document.createElement('script') as HTMLScriptElement;\n const retryCount = options.retryCount ?? 0;\n script.setAttribute('src', fixedSrc);\n script.setAttribute('retryCount', retryCount.toString());\n script.async = true;\n\n const attributes = options.attributes ?? {};\n Object.keys(attributes).forEach(key => {\n script.setAttribute(key, attributes[key]);\n });\n\n switch (options.bundleType) {\n case 'module':\n script.setAttribute('type', options.bundleType);\n break;\n // cannot be tested because modern browsers ignore `nomodule`\n /* istanbul ignore next */\n case 'nomodule':\n script.setAttribute(options.bundleType, '');\n break;\n default:\n break;\n }\n\n return script;\n }\n}\n"]}
{"version":3,"file":"lazy-loader-service.js","sourceRoot":"","sources":["../../src/lazy-loader-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { createNanoEvents, Unsubscribe } from 'nanoevents';\nimport type { BundleType } from './bundle-type';\nimport {\n LazyLoaderServiceEvents,\n LazyLoaderServiceInterface,\n} from './lazy-loader-service-interface';\nimport { promisedSleep } from './promised-sleep';\n\nexport interface LazyLoaderServiceOptions {\n /**\n * The HTMLElement in which we put the script tags, defaults to document.head\n */\n container?: HTMLElement;\n\n /**\n * The number of retries we should attempt\n */\n retryCount?: number;\n\n /**\n * The retry interval in seconds\n */\n retryInterval?: number;\n}\n\nexport class LazyLoaderService implements LazyLoaderServiceInterface {\n // the HTMLElement in which we put the script tags, defaults to document.head\n private container: HTMLElement;\n\n // the number of retries we should attempt\n private retryCount: number;\n\n // the retry interval in seconds\n private retryInterval: number;\n\n // the emitter for consumers to listen for events like retrying a load\n private emitter = createNanoEvents<LazyLoaderServiceEvents>();\n\n /**\n * LazyLoaderService constructor\n *\n * @param options LazyLoaderServiceOptions\n */\n constructor(options?: LazyLoaderServiceOptions) {\n this.container = options?.container ?? document.head;\n this.retryCount = options?.retryCount ?? 2;\n this.retryInterval = options?.retryInterval ?? 1;\n }\n\n /** @inheritdoc */\n on<E extends keyof LazyLoaderServiceEvents>(\n event: E,\n callback: LazyLoaderServiceEvents[E]\n ): Unsubscribe {\n return this.emitter.on(event, callback);\n }\n\n /** @inheritdoc */\n async loadBundle(bundle: {\n module?: string;\n nomodule?: string;\n }): Promise<void> {\n let modulePromise: Promise<void> | undefined;\n let nomodulePromise: Promise<void> | undefined;\n\n /* istanbul ignore else */\n if (bundle.module) {\n modulePromise = this.loadScript({\n src: bundle.module,\n bundleType: 'module',\n });\n }\n\n /* istanbul ignore else */\n if (bundle.nomodule) {\n nomodulePromise = this.loadScript({\n src: bundle.nomodule,\n bundleType: 'nomodule',\n });\n }\n\n return Promise.race([modulePromise, nomodulePromise]);\n }\n\n /** @inheritdoc */\n async loadScript(options: {\n src: string;\n bundleType?: BundleType;\n attributes?: Record<string, string>;\n }): Promise<void> {\n return this.doLoad(options);\n }\n\n private async doLoad(options: {\n src: string;\n bundleType?: BundleType;\n attributes?: Record<string, string>;\n retryCount?: number;\n scriptBeingRetried?: HTMLScriptElement;\n }): Promise<void> {\n const retryCount = options.retryCount ?? 0;\n const scriptSelector = `script[src='${options.src}'][async][retryCount='${retryCount}']`;\n let script = this.container.querySelector(\n scriptSelector\n ) as HTMLScriptElement;\n if (!script) {\n script = this.getScriptTag(options);\n this.container.appendChild(script);\n }\n\n return new Promise((resolve, reject) => {\n // script has already been loaded, just resolve\n if (script.getAttribute('dynamicImportLoaded')) {\n resolve();\n return;\n }\n\n const scriptBeingRetried = options.scriptBeingRetried;\n\n // If multiple requests get made for this script, just stack the `onload`s\n // and `onerror`s and all the callbacks will be called in-order of being received.\n // If we are retrying the load, we use the `onload` / `onerror` from the script being retried\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const originalOnLoad: ((event: Event) => any) | null | undefined =\n script.onload || scriptBeingRetried?.onload;\n\n script.onload = (event): void => {\n originalOnLoad?.(event);\n script.setAttribute('dynamicImportLoaded', 'true');\n resolve();\n };\n\n const originalOnError: OnErrorEventHandler | null | undefined =\n script.onerror || scriptBeingRetried?.onerror;\n\n script.onerror = async (error): Promise<void> => {\n const hasBeenRetried = script.getAttribute('hasBeenRetried');\n if (retryCount < this.retryCount && !hasBeenRetried) {\n script.setAttribute('hasBeenRetried', 'true');\n await promisedSleep(this.retryInterval * 1000);\n const newRetryCount = retryCount + 1;\n this.emitter.emit('scriptLoadRetried', options.src, newRetryCount);\n this.doLoad({\n ...options,\n retryCount: newRetryCount,\n scriptBeingRetried: script,\n });\n } else {\n // only emit a failure event from the last attempt, which has not been retried.\n // otherwise you get failure events from each script tag, when we're really\n // only interested that the entire chain failed\n if (!hasBeenRetried) {\n this.emitter.emit('scriptLoadFailed', options.src, error);\n }\n originalOnError?.(error);\n reject(error);\n }\n };\n });\n }\n\n /**\n * Generate a script tag with all of the proper attributes\n *\n * @param options\n * @returns\n */\n private getScriptTag(options: {\n src: string;\n retryCount?: number;\n bundleType?: BundleType;\n attributes?: Record<string, string>;\n }): HTMLScriptElement {\n const fixedSrc = options.src.replace(\"'\", '\"');\n const script = document.createElement('script') as HTMLScriptElement;\n const retryCount = options.retryCount ?? 0;\n script.setAttribute('src', fixedSrc);\n script.setAttribute('retryCount', retryCount.toString());\n script.async = true;\n\n const attributes = options.attributes ?? {};\n Object.keys(attributes).forEach(key => {\n script.setAttribute(key, attributes[key]);\n });\n\n switch (options.bundleType) {\n case 'module':\n script.setAttribute('type', options.bundleType);\n break;\n // cannot be tested because modern browsers ignore `nomodule`\n /* istanbul ignore next */\n case 'nomodule':\n script.setAttribute(options.bundleType, '');\n break;\n default:\n break;\n }\n\n return script;\n }\n}\n"]}

@@ -159,2 +159,36 @@ import { __awaiter } from "tslib";

}));
it('Emits the expected number of retry events', () => __awaiter(void 0, void 0, void 0, function* () {
const container = (yield fixture(html ` <div></div> `));
const lazyLoader = new LazyLoaderService({
container,
retryCount: 4,
retryInterval: 0.01,
});
let retryEvents = 0;
lazyLoader.on('scriptLoadRetried', () => {
retryEvents += 1;
});
try {
yield lazyLoader.loadScript({ src: '/base/test/blahblah.js' });
}
catch (_a) { }
expect(retryEvents).to.equal(4);
}));
it('Only emits a single failure event if there are multiple retry attempts', () => __awaiter(void 0, void 0, void 0, function* () {
const container = (yield fixture(html ` <div></div> `));
const lazyLoader = new LazyLoaderService({
container,
retryCount: 4,
retryInterval: 0.01,
});
let failureEvents = 0;
lazyLoader.on('scriptLoadFailed', () => {
failureEvents += 1;
});
try {
yield lazyLoader.loadScript({ src: '/base/test/blahblah.js' });
}
catch (_b) { }
expect(failureEvents).to.equal(1);
}));
it('Retries the specified number of times', () => __awaiter(void 0, void 0, void 0, function* () {

@@ -170,3 +204,3 @@ const container = (yield fixture(html ` <div></div> `));

}
catch (_a) { }
catch (_c) { }
const scriptTags = container.querySelectorAll('script');

@@ -173,0 +207,0 @@ expect(scriptTags.length).to.equal(6);

@@ -1,1 +0,1 @@

{"version":3,"file":"lazy-loader-service.test.js","sourceRoot":"","sources":["../../test/lazy-loader-service.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html } from '@open-wc/testing';\nimport { LazyLoaderService } from '../src/lazy-loader-service';\n\nconst testServiceUrl = '/base/dist/test/test-service.js';\n\ndescribe('Lazy Loader Service', () => {\n it('Initialized by default with document.head', async () => {\n const lazyLoader = new LazyLoaderService();\n await lazyLoader.loadScript({ src: testServiceUrl });\n const scripts = document.head.querySelectorAll('script');\n expect(scripts.length).to.equal(1);\n });\n\n describe('loadBundle', () => {\n it('Can load bundles', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n await lazyLoader.loadBundle({\n module: testServiceUrl,\n nomodule: testServiceUrl,\n });\n\n const scripts = container.querySelectorAll('script');\n expect(scripts.length).to.equal(1);\n });\n });\n\n describe('loadScript', () => {\n it('Creates proper script tags in container', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n\n await lazyLoader.loadScript({ src: testServiceUrl });\n\n const scripts = container.querySelectorAll('script');\n expect(scripts.length).to.equal(1);\n });\n\n it('Only loads scripts once if called multiple times', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n\n await lazyLoader.loadScript({ src: testServiceUrl });\n await lazyLoader.loadScript({ src: testServiceUrl });\n await lazyLoader.loadScript({ src: testServiceUrl });\n\n const scripts = container.querySelectorAll('script');\n expect(scripts.length).to.equal(1);\n });\n\n it('Loaded script is usable', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n await lazyLoader.loadScript({ src: testServiceUrl });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = (window as any).testService.getResponse();\n expect(result).to.equal('someresponse');\n });\n\n it('Can pass in attributes', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n await lazyLoader.loadScript({\n src: testServiceUrl,\n attributes: { foo: 'bar' },\n });\n\n const script = container.querySelector('script');\n const fooAttribute = script?.getAttribute('foo');\n expect(fooAttribute).to.equal('bar');\n });\n\n it('Can load modules', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n await lazyLoader.loadScript({\n src: testServiceUrl,\n bundleType: 'module',\n });\n\n const script = container.querySelector('script');\n const typeAttribute = script?.getAttribute('type');\n expect(typeAttribute).to.equal('module');\n });\n\n // this is verifying that when a bunch of concurrent requests for a script get\n // made, that they all get their completion blocks called\n it('Calls multiple onloads if requested', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n\n const count = 25;\n\n const loads = new Array(count).fill(false);\n\n async function loadScript(number: number): Promise<void> {\n await lazyLoader.loadScript({ src: testServiceUrl });\n loads[number] = true;\n }\n\n const promises = [];\n for (let i = 0; i < count; i++) {\n const promise = loadScript(i);\n promises.push(promise);\n }\n\n return Promise.all(promises).then(() => {\n for (let i = 0; i < count; i++) {\n expect(loads[i]).to.equal(true);\n }\n });\n });\n\n // this is verifying that when a bunch of concurrent requests for a script get\n // made, that they all get their completion blocks called\n it('Calls multiple onerrors if requested', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryInterval: 0.1,\n });\n\n const count = 25;\n\n const loadFailed = new Array(count).fill(false);\n\n async function loadScript(number: number): Promise<void> {\n try {\n await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });\n } catch {\n // we're expecting a failure here so this is successful\n loadFailed[number] = true;\n }\n }\n\n const promises = [];\n for (let i = 0; i < count; i++) {\n const promise = loadScript(i);\n promises.push(promise);\n }\n\n return Promise.all(promises).then(() => {\n for (let i = 0; i < count; i++) {\n expect(loadFailed[i]).to.equal(true);\n }\n });\n });\n\n // This is verifying that we emit an event on retry and failure.\n // This allows the consumer to respond to these events with analytics handling\n // anything else.\n it('Emits an event when a retry occurs or fails', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryCount: 1,\n retryInterval: 0.01,\n });\n\n let testRetryCount = 0;\n lazyLoader.on('scriptLoadRetried', (src: string, retryCount: number) => {\n testRetryCount = retryCount;\n });\n\n let scriptLoadEventFired = false;\n let failedSrc: string | undefined;\n lazyLoader.on('scriptLoadFailed', (src: string) => {\n scriptLoadEventFired = true;\n failedSrc = src;\n });\n\n let retryFailed = false;\n try {\n await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });\n } catch (err) {\n retryFailed = true;\n }\n\n expect(testRetryCount).to.equal(1);\n expect(scriptLoadEventFired).to.be.true;\n expect(failedSrc).to.equal('/base/test/blahblah.js');\n expect(retryFailed).to.be.true;\n });\n\n it('Retries the specified number of times', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryCount: 5,\n retryInterval: 0.01,\n });\n\n try {\n await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });\n } catch {}\n\n const scriptTags = container.querySelectorAll('script');\n expect(scriptTags.length).to.equal(6);\n });\n\n /**\n * This is a special test that connects to a sidecar node server to test retrying a request.\n *\n * In `npm run test`, we run `test/test-server.js` while we're running our tests.\n * `test-server.js` has a very specific purpose:\n *\n * The very first request will always return an HTTP 404, the second request returns a HTTP 200,\n * then it shuts down.\n *\n * This lets us check that a failed request gets retried successfully.\n */\n it('Can retry a reqest', async () => {\n const serverUrl = 'http://localhost:5432/';\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryCount: 1,\n retryInterval: 0.01,\n });\n await lazyLoader.loadScript({ src: serverUrl });\n\n // verify we have two script tags with the expected url and a propery retryCount on each\n const scriptTags = container.querySelectorAll('script');\n scriptTags.forEach((tag, index) => {\n expect(tag.src).to.equal(serverUrl);\n expect(tag.getAttribute('retryCount'), `${index}`);\n });\n\n // verify the final load actually loaded the service\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = (window as any).otherService.getResponse();\n expect(result).to.equal('someotherresponse');\n });\n });\n});\n"]}
{"version":3,"file":"lazy-loader-service.test.js","sourceRoot":"","sources":["../../test/lazy-loader-service.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html } from '@open-wc/testing';\nimport { LazyLoaderService } from '../src/lazy-loader-service';\n\nconst testServiceUrl = '/base/dist/test/test-service.js';\n\ndescribe('Lazy Loader Service', () => {\n it('Initialized by default with document.head', async () => {\n const lazyLoader = new LazyLoaderService();\n await lazyLoader.loadScript({ src: testServiceUrl });\n const scripts = document.head.querySelectorAll('script');\n expect(scripts.length).to.equal(1);\n });\n\n describe('loadBundle', () => {\n it('Can load bundles', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n await lazyLoader.loadBundle({\n module: testServiceUrl,\n nomodule: testServiceUrl,\n });\n\n const scripts = container.querySelectorAll('script');\n expect(scripts.length).to.equal(1);\n });\n });\n\n describe('loadScript', () => {\n it('Creates proper script tags in container', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n\n await lazyLoader.loadScript({ src: testServiceUrl });\n\n const scripts = container.querySelectorAll('script');\n expect(scripts.length).to.equal(1);\n });\n\n it('Only loads scripts once if called multiple times', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n\n await lazyLoader.loadScript({ src: testServiceUrl });\n await lazyLoader.loadScript({ src: testServiceUrl });\n await lazyLoader.loadScript({ src: testServiceUrl });\n\n const scripts = container.querySelectorAll('script');\n expect(scripts.length).to.equal(1);\n });\n\n it('Loaded script is usable', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n await lazyLoader.loadScript({ src: testServiceUrl });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = (window as any).testService.getResponse();\n expect(result).to.equal('someresponse');\n });\n\n it('Can pass in attributes', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n await lazyLoader.loadScript({\n src: testServiceUrl,\n attributes: { foo: 'bar' },\n });\n\n const script = container.querySelector('script');\n const fooAttribute = script?.getAttribute('foo');\n expect(fooAttribute).to.equal('bar');\n });\n\n it('Can load modules', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n await lazyLoader.loadScript({\n src: testServiceUrl,\n bundleType: 'module',\n });\n\n const script = container.querySelector('script');\n const typeAttribute = script?.getAttribute('type');\n expect(typeAttribute).to.equal('module');\n });\n\n // this is verifying that when a bunch of concurrent requests for a script get\n // made, that they all get their completion blocks called\n it('Calls multiple onloads if requested', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({ container });\n\n const count = 25;\n\n const loads = new Array(count).fill(false);\n\n async function loadScript(number: number): Promise<void> {\n await lazyLoader.loadScript({ src: testServiceUrl });\n loads[number] = true;\n }\n\n const promises = [];\n for (let i = 0; i < count; i++) {\n const promise = loadScript(i);\n promises.push(promise);\n }\n\n return Promise.all(promises).then(() => {\n for (let i = 0; i < count; i++) {\n expect(loads[i]).to.equal(true);\n }\n });\n });\n\n // this is verifying that when a bunch of concurrent requests for a script get\n // made, that they all get their completion blocks called\n it('Calls multiple onerrors if requested', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryInterval: 0.1,\n });\n\n const count = 25;\n\n const loadFailed = new Array(count).fill(false);\n\n async function loadScript(number: number): Promise<void> {\n try {\n await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });\n } catch {\n // we're expecting a failure here so this is successful\n loadFailed[number] = true;\n }\n }\n\n const promises = [];\n for (let i = 0; i < count; i++) {\n const promise = loadScript(i);\n promises.push(promise);\n }\n\n return Promise.all(promises).then(() => {\n for (let i = 0; i < count; i++) {\n expect(loadFailed[i]).to.equal(true);\n }\n });\n });\n\n // This is verifying that we emit an event on retry and failure.\n // This allows the consumer to respond to these events with analytics handling\n // anything else.\n it('Emits an event when a retry occurs or fails', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryCount: 1,\n retryInterval: 0.01,\n });\n\n let testRetryCount = 0;\n lazyLoader.on('scriptLoadRetried', (src: string, retryCount: number) => {\n testRetryCount = retryCount;\n });\n\n let scriptLoadEventFired = false;\n let failedSrc: string | undefined;\n lazyLoader.on('scriptLoadFailed', (src: string) => {\n scriptLoadEventFired = true;\n failedSrc = src;\n });\n\n let retryFailed = false;\n try {\n await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });\n } catch (err) {\n retryFailed = true;\n }\n\n expect(testRetryCount).to.equal(1);\n expect(scriptLoadEventFired).to.be.true;\n expect(failedSrc).to.equal('/base/test/blahblah.js');\n expect(retryFailed).to.be.true;\n });\n\n it('Emits the expected number of retry events', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryCount: 4,\n retryInterval: 0.01,\n });\n\n let retryEvents = 0;\n lazyLoader.on('scriptLoadRetried', () => {\n retryEvents += 1;\n });\n\n try {\n await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });\n } catch {}\n\n expect(retryEvents).to.equal(4);\n });\n\n it('Only emits a single failure event if there are multiple retry attempts', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryCount: 4,\n retryInterval: 0.01,\n });\n\n let failureEvents = 0;\n lazyLoader.on('scriptLoadFailed', () => {\n failureEvents += 1;\n });\n\n try {\n await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });\n } catch {}\n\n expect(failureEvents).to.equal(1);\n });\n\n it('Retries the specified number of times', async () => {\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryCount: 5,\n retryInterval: 0.01,\n });\n\n try {\n await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });\n } catch {}\n\n const scriptTags = container.querySelectorAll('script');\n expect(scriptTags.length).to.equal(6);\n });\n\n /**\n * This is a special test that connects to a sidecar node server to test retrying a request.\n *\n * In `npm run test`, we run `test/test-server.js` while we're running our tests.\n * `test-server.js` has a very specific purpose:\n *\n * The very first request will always return an HTTP 404, the second request returns a HTTP 200,\n * then it shuts down.\n *\n * This lets us check that a failed request gets retried successfully.\n */\n it('Can retry a reqest', async () => {\n const serverUrl = 'http://localhost:5432/';\n const container = (await fixture(html` <div></div> `)) as HTMLElement;\n const lazyLoader = new LazyLoaderService({\n container,\n retryCount: 1,\n retryInterval: 0.01,\n });\n await lazyLoader.loadScript({ src: serverUrl });\n\n // verify we have two script tags with the expected url and a propery retryCount on each\n const scriptTags = container.querySelectorAll('script');\n scriptTags.forEach((tag, index) => {\n expect(tag.src).to.equal(serverUrl);\n expect(tag.getAttribute('retryCount'), `${index}`);\n });\n\n // verify the final load actually loaded the service\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = (window as any).otherService.getResponse();\n expect(result).to.equal('someotherresponse');\n });\n });\n});\n"]}
{
"name": "@internetarchive/lazy-loader-service",
"version": "0.2.0-alpha.1",
"version": "0.2.0-alpha.2",
"description": "A small library to lazy load javascript with a Promise",

@@ -5,0 +5,0 @@ "license": "AGPL-3.0-only",

@@ -150,3 +150,8 @@ import { createNanoEvents, Unsubscribe } from 'nanoevents';

} else {
this.emitter.emit('scriptLoadFailed', options.src, error);
// only emit a failure event from the last attempt, which has not been retried.
// otherwise you get failure events from each script tag, when we're really
// only interested that the entire chain failed
if (!hasBeenRetried) {
this.emitter.emit('scriptLoadFailed', options.src, error);
}
originalOnError?.(error);

@@ -153,0 +158,0 @@ reject(error);

@@ -186,2 +186,42 @@ import { expect, fixture, html } from '@open-wc/testing';

it('Emits the expected number of retry events', async () => {
const container = (await fixture(html` <div></div> `)) as HTMLElement;
const lazyLoader = new LazyLoaderService({
container,
retryCount: 4,
retryInterval: 0.01,
});
let retryEvents = 0;
lazyLoader.on('scriptLoadRetried', () => {
retryEvents += 1;
});
try {
await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });
} catch {}
expect(retryEvents).to.equal(4);
});
it('Only emits a single failure event if there are multiple retry attempts', async () => {
const container = (await fixture(html` <div></div> `)) as HTMLElement;
const lazyLoader = new LazyLoaderService({
container,
retryCount: 4,
retryInterval: 0.01,
});
let failureEvents = 0;
lazyLoader.on('scriptLoadFailed', () => {
failureEvents += 1;
});
try {
await lazyLoader.loadScript({ src: '/base/test/blahblah.js' });
} catch {}
expect(failureEvents).to.equal(1);
});
it('Retries the specified number of times', async () => {

@@ -188,0 +228,0 @@ const container = (await fixture(html` <div></div> `)) as HTMLElement;