UNPKG

thebe-core

Version:

Typescript based core functionality for Thebe

74 lines (61 loc) 2.42 kB
/** * Inspired by https://github.com/jupyterlab/jupyterlab-plugin-playground/blob/main/src/requirejs.ts */ const REQUIREJS_CDN_URL = 'https://cdn.jsdelivr.net/npm/'; const REQUIREJS_URL = 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js'; export interface IRequireJS { readonly require: Require; readonly define: RequireDefine; } async function fetchAndLoadInFrame(baseUrl: string): Promise<IRequireJS> { if (typeof document === 'undefined') throw new Error('Cannot load requirejs outside of the browser'); const res = await fetch(REQUIREJS_URL); if (!res.ok) { throw new Error(`Could not fetch requirejs ${res.status} ${res.statusText}`); } const requireJsSource = await res.text(); return new Promise((resolve, reject) => { const iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.onload = () => { const contentWindow = iframe.contentWindow; if (!contentWindow) return reject('Cannot load in isolated: no contentWindow, origin error?'); contentWindow.window.eval(requireJsSource); const requirejs: IRequireJS = { require: (contentWindow.window as any).require, define: (contentWindow.window as any).define, }; if (!requirejs.require || !requirejs.define) return reject( 'Require.js loading did not result in `require` and `define` objects attachment to window', ); requirejs.require.config({ baseUrl }); resolve(requirejs); iframe.onload = null; }; document.body.appendChild(iframe); }); } export class RequireJsLoader { requested: boolean; readonly baseUrl: string; readonly ready: Promise<IRequireJS>; requirejs?: IRequireJS; private resolveFn: (value: IRequireJS | PromiseLike<IRequireJS>) => void; constructor(baseUrl?: string) { this.baseUrl = baseUrl ?? REQUIREJS_CDN_URL; this.requested = false; this.resolveFn = () => ({}); this.ready = new Promise<IRequireJS>((resolve) => (this.resolveFn = resolve)); } async load(postLoadFn?: (require: Require, define: RequireDefine) => Promise<void> | void) { if (!this.requested) { this.requested = true; this.requirejs = await fetchAndLoadInFrame(this.baseUrl); await postLoadFn?.(this.requirejs.require, this.requirejs.define); this.resolveFn(this.requirejs); } return this.ready; } }