UNPKG

1.76 kBPlain TextView Raw
1import {ExtendedWindow} from '@shopify/useful-types';
2
3const cache = new Map<string, Promise<any>>();
4
5export default function load<
6 Imported = any,
7 CustomWindow extends Window = Window
8>(
9 source: string,
10 getImport: (window: CustomWindow) => Imported,
11 nonce: string,
12): Promise<Imported> {
13 if (typeof window === 'undefined') {
14 return Promise.reject(
15 new Error('You can’t import a remote module from the server'),
16 );
17 }
18
19 const cachedModule = cache.get(source);
20
21 if (cachedModule != null) {
22 return cachedModule;
23 }
24
25 const scriptTag = scriptTagFor(source, nonce);
26 appendScriptTag(scriptTag);
27
28 const promise = new Promise<Imported>((resolve, reject) => {
29 function scriptTagOnLoad() {
30 scriptTag.removeEventListener('load', scriptTagOnLoad);
31 scriptTag.removeEventListener('error', scriptTagOnError);
32 resolve(getImport(window as ExtendedWindow<CustomWindow>));
33 }
34
35 function scriptTagOnError() {
36 scriptTag.removeEventListener('load', scriptTagOnLoad);
37 scriptTag.removeEventListener('error', scriptTagOnError);
38 reject(new Error('Script tag failed to load remote source'));
39 }
40
41 scriptTag.addEventListener('load', scriptTagOnLoad);
42 scriptTag.addEventListener('error', scriptTagOnError);
43 });
44
45 cache.set(source, promise);
46 return promise;
47}
48
49export function clearCache() {
50 cache.clear();
51}
52
53function scriptTagFor(source: string, nonce: string) {
54 const node = document.createElement('script');
55 node.setAttribute('type', 'text/javascript');
56 node.setAttribute('src', source);
57
58 if (nonce.length > 0) {
59 node.setAttribute('nonce', nonce);
60 }
61
62 return node;
63}
64
65function appendScriptTag(scriptTag: HTMLScriptElement) {
66 document.head.appendChild(scriptTag);
67}
68
\No newline at end of file