74 lines
2.6 KiB
JavaScript
74 lines
2.6 KiB
JavaScript
|
/*
|
||
|
Copyright (c) 2018 uupaa and 2019 Google LLC
|
||
|
|
||
|
Use of this source code is governed by an MIT-style
|
||
|
license that can be found in the LICENSE file or at
|
||
|
https://opensource.org/licenses/MIT.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Creates a global function (defaulting to `self.__import__()`) that can
|
||
|
* dynamically import modules. In browsers that support native dynamic
|
||
|
* `import()`, the function defers to using that, otherwise a small polyfill
|
||
|
* is used that creates a new module script and resolves once the module
|
||
|
* is loaded.
|
||
|
*
|
||
|
* @param {Object} [options]
|
||
|
* @param {string} [options.modulePath='.'] A path that relative import URLs
|
||
|
* are resolved from. This is needed since this polyfill creates script
|
||
|
* elements, and relative imports inside script elements will resolve
|
||
|
* relative to the page URL. Set this option to have URLs resolve relative
|
||
|
* to a different path (typically the location of your deployed modules
|
||
|
* directory).
|
||
|
* @param {string} [importFunctionName='__import__'] The name to use for the
|
||
|
* global import function this polyfill will create. Since `import` is
|
||
|
* a keyword in JavaScript, it's not possible to polyfill dynamic import
|
||
|
* by creating a global function named `import()`. Thus, a different
|
||
|
* name must be used.
|
||
|
*/
|
||
|
export function initialize({
|
||
|
modulePath = '.',
|
||
|
importFunctionName = '__import__',
|
||
|
} = {}) {
|
||
|
try {
|
||
|
self[importFunctionName] = new Function('u', `return import(u)`);
|
||
|
} catch (error) {
|
||
|
const baseURL = new URL(modulePath, location);
|
||
|
const cleanup = (script) => {
|
||
|
URL.revokeObjectURL(script.src);
|
||
|
script.remove();
|
||
|
};
|
||
|
|
||
|
self[importFunctionName] = (url) => new Promise((resolve, reject) => {
|
||
|
const absURL = new URL(url, baseURL);
|
||
|
|
||
|
// If the module has already been imported, resolve immediately.
|
||
|
if (self[importFunctionName].moduleMap[absURL]) {
|
||
|
return resolve(self[importFunctionName].moduleMap[absURL]);
|
||
|
}
|
||
|
|
||
|
const moduleBlob = new Blob([
|
||
|
`import * as m from '${absURL}';`,
|
||
|
`${importFunctionName}.moduleMap['${absURL}']=m;`,
|
||
|
], {type: 'text/javascript'});
|
||
|
|
||
|
const script = Object.assign(document.createElement('script'), {
|
||
|
type: 'module',
|
||
|
src: URL.createObjectURL(moduleBlob),
|
||
|
onerror() {
|
||
|
reject(new Error(`Failed to import: ${url}`));
|
||
|
cleanup(script);
|
||
|
},
|
||
|
onload() {
|
||
|
resolve(self[importFunctionName].moduleMap[absURL]);
|
||
|
cleanup(script);
|
||
|
},
|
||
|
});
|
||
|
|
||
|
document.head.appendChild(script);
|
||
|
});
|
||
|
|
||
|
self[importFunctionName].moduleMap = {};
|
||
|
}
|
||
|
}
|