Skip to content

Commit

Permalink
refactor(core): CHECKOUT-4455 Stop resolving promise with load event
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Previously, when a script is loaded, we return the
associated event object inside a promise object to the caller. With this
change, we return an empty promise object instead. This change is
necessary because we can't guarantee that scripts can be loaded in the
same way across different browsers. For example, some browsers don't
support `rel="preload"`, so as a fallback, we have to preload scripts
using regular XHR calls. In that case, we don't have an event object to
return to the caller. We could potentially mock the event object to keep
the return values consistent. But considering it is not a very useful
thing to return, we've decided to make a breaking change and return
nothing instead.
  • Loading branch information
davidchin committed Oct 3, 2019
1 parent 0fc52e7 commit 670fd2c
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 33 deletions.
4 changes: 2 additions & 2 deletions src/script-loader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe('ScriptLoader', () => {
const output = await loader.loadScript('https://code.jquery.com/jquery-3.2.1.min.js');

expect(output)
.toBeInstanceOf(Event);
.toBeUndefined();
});

it('does not load same script twice', async () => {
Expand Down Expand Up @@ -229,7 +229,7 @@ describe('ScriptLoader', () => {
const output = await loader.preloadScript('https://cdn.foobar.com/foo.min.js');

expect(output)
.toBeInstanceOf(Event);
.toBeUndefined();
});
});
});
34 changes: 18 additions & 16 deletions src/script-loader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RequestSender, Response } from '@bigcommerce/request-sender';
import { RequestSender } from '@bigcommerce/request-sender';

import BrowserSupport from './browser-support';

Expand All @@ -11,8 +11,8 @@ export interface PreloadScriptOptions {
}

export default class ScriptLoader {
private _scripts: { [key: string]: Promise<Event> } = {};
private _preloadedScripts: { [key: string]: Promise<Event | Response> } = {};
private _scripts: { [key: string]: Promise<void> } = {};
private _preloadedScripts: { [key: string]: Promise<void> } = {};

/**
* @internal
Expand All @@ -22,14 +22,14 @@ export default class ScriptLoader {
private _requestSender: RequestSender
) {}

loadScript(src: string, options?: LoadScriptOptions): Promise<Event> {
loadScript(src: string, options?: LoadScriptOptions): Promise<void> {
if (!this._scripts[src]) {
this._scripts[src] = new Promise((resolve, reject) => {
const script = document.createElement('script') as LegacyHTMLScriptElement;
const { async = false } = options || {};

script.onload = event => resolve(event);
script.onreadystatechange = event => resolve(event);
script.onload = () => resolve();
script.onreadystatechange = () => resolve();
script.onerror = event => {
delete this._scripts[src];
reject(event);
Expand All @@ -44,11 +44,12 @@ export default class ScriptLoader {
return this._scripts[src];
}

loadScripts(urls: string[], options?: LoadScriptOptions): Promise<Event[]> {
return Promise.all(urls.map(url => this.loadScript(url, options)));
loadScripts(urls: string[], options?: LoadScriptOptions): Promise<void> {
return Promise.all(urls.map(url => this.loadScript(url, options)))
.then(() => undefined);
}

preloadScript(url: string, options?: PreloadScriptOptions): Promise<Event | Response> {
preloadScript(url: string, options?: PreloadScriptOptions): Promise<void> {
if (!this._preloadedScripts[url]) {
this._preloadedScripts[url] = new Promise((resolve, reject) => {
const { prefetch = false } = options || {};
Expand All @@ -61,13 +62,13 @@ export default class ScriptLoader {
preloadedScript.rel = rel;
preloadedScript.href = url;

preloadedScript.onload = event => {
resolve(event);
preloadedScript.onload = () => {
resolve();
};

preloadedScript.onerror = event => {
preloadedScript.onerror = () => {
delete this._preloadedScripts[url];
reject(event);
reject();
};

document.head.appendChild(preloadedScript);
Expand All @@ -76,7 +77,7 @@ export default class ScriptLoader {
credentials: false,
headers: { Accept: 'application/javascript' },
})
.then(resolve)
.then(() => resolve())
.catch(reject);
}
});
Expand All @@ -85,8 +86,9 @@ export default class ScriptLoader {
return this._preloadedScripts[url];
}

preloadScripts(urls: string[], options?: PreloadScriptOptions): Promise<Array<Event | Response>> {
return Promise.all(urls.map(url => this.preloadScript(url, options)));
preloadScripts(urls: string[], options?: PreloadScriptOptions): Promise<void> {
return Promise.all(urls.map(url => this.preloadScript(url, options)))
.then(() => undefined);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/stylesheet-loader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('StylesheetLoader', () => {
const output = await loader.loadStylesheet('https://foo.bar/hello-world.css');

expect(output)
.toBeInstanceOf(Event);
.toBeUndefined();
});

it('does not load same stylesheet twice', async () => {
Expand Down Expand Up @@ -166,7 +166,7 @@ describe('StylesheetLoader', () => {
const output = await loader.preloadStylesheet('https://foo.bar/hello-world.css');

expect(output)
.toBeInstanceOf(Event);
.toBeUndefined();
});
});
});
28 changes: 15 additions & 13 deletions src/stylesheet-loader.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RequestSender, Response } from '@bigcommerce/request-sender';
import { RequestSender } from '@bigcommerce/request-sender';

import BrowserSupport from './browser-support';

Expand All @@ -11,8 +11,8 @@ export interface PreloadStylesheetOptions {
}

export default class StylesheetLoader {
private _stylesheets: { [key: string]: Promise<Event> } = {};
private _preloadedStylesheets: { [key: string]: Promise<Event | Response> } = {};
private _stylesheets: { [key: string]: Promise<void> } = {};
private _preloadedStylesheets: { [key: string]: Promise<void> } = {};

/**
* @internal
Expand All @@ -22,13 +22,13 @@ export default class StylesheetLoader {
private _requestSender: RequestSender
) {}

loadStylesheet(src: string, options?: LoadStylesheetOptions): Promise<Event> {
loadStylesheet(src: string, options?: LoadStylesheetOptions): Promise<void> {
if (!this._stylesheets[src]) {
this._stylesheets[src] = new Promise((resolve, reject) => {
const stylesheet = document.createElement('link');
const { prepend = false } = options || {};

stylesheet.onload = event => resolve(event);
stylesheet.onload = () => resolve();
stylesheet.onerror = event => {
delete this._stylesheets[src];
reject(event);
Expand All @@ -47,11 +47,12 @@ export default class StylesheetLoader {
return this._stylesheets[src];
}

loadStylesheets(urls: string[], options?: LoadStylesheetOptions): Promise<Event[]> {
return Promise.all(urls.map(url => this.loadStylesheet(url, options)));
loadStylesheets(urls: string[], options?: LoadStylesheetOptions): Promise<void> {
return Promise.all(urls.map(url => this.loadStylesheet(url, options)))
.then(() => undefined);
}

preloadStylesheet(url: string, options?: PreloadStylesheetOptions): Promise<Event | Response> {
preloadStylesheet(url: string, options?: PreloadStylesheetOptions): Promise<void> {
if (!this._preloadedStylesheets[url]) {
this._preloadedStylesheets[url] = new Promise((resolve, reject) => {
const { prefetch = false } = options || {};
Expand All @@ -64,8 +65,8 @@ export default class StylesheetLoader {
preloadedStylesheet.rel = prefetch ? 'prefetch' : 'preload';
preloadedStylesheet.href = url;

preloadedStylesheet.onload = event => {
resolve(event);
preloadedStylesheet.onload = () => {
resolve();
};

preloadedStylesheet.onerror = event => {
Expand All @@ -79,7 +80,7 @@ export default class StylesheetLoader {
credentials: false,
headers: { Accept: 'text/css' },
})
.then(resolve)
.then(() => resolve())
.catch(reject);
}
});
Expand All @@ -88,7 +89,8 @@ export default class StylesheetLoader {
return this._preloadedStylesheets[url];
}

preloadStylesheets(urls: string[], options?: PreloadStylesheetOptions): Promise<Array<Event | Response>> {
return Promise.all(urls.map(url => this.preloadStylesheet(url, options)));
preloadStylesheets(urls: string[], options?: PreloadStylesheetOptions): Promise<void> {
return Promise.all(urls.map(url => this.preloadStylesheet(url, options)))
.then(() => undefined);
}
}

0 comments on commit 670fd2c

Please sign in to comment.