Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Importing Closure Library into Browser-Native ES6 Modules
/**
* @fileinfo
*
* This ES6 module attempts to load Closure-managed dependencies from native ES6 modules
* in web browsers (as supported today in Safari, fall 2017 in Chrome, and behind feature
* flags in Edge and Firefox).
*
* To use: just import this into a natively-loaded ES6 module that will be using
*
* Normally, you can only run goog.require() synchronously before the document has finished
* loading, because it uses document.write() to inject required scripts. This module changes
* that logic to instead load packages asynchronously at any time. Since ES6 modules can only
* be loaded asynchronously, this allows Closure packages to be loaded by them.
*
* Because scripts are loaded asynchronously, you cannot use goog.require()'d packages
* immediately in the file's root scope. For example, this will not work:
*
* goog.require('my.SuperClass');
* export default MyClass extends my.SuperClass { } // Error: undeclared variable "my"
*
* Wait until all required scripts are loaded (including scripts required by modules imported
* by your module) by importing this module's default export and passing it a callback:
*
* import whenScriptsLoaded from "./devLoader.js";
* goog.require("my.app");
*
* whenScriptsLoaded(() => {
* my.app.init();
* });
*
* This file can only be run in native module mode. Either load it using
* <script type="module" src="devLoader.js"></script>, or by importing it
* from another script that was itself loaded with type="module".
*
*/
let lastScriptLoaded = Promise.resolve();
let numPendingScripts = 0;
if (!COMPILED) {
/**
* @param {!string} src
* @param {string=} opt_sourceText
*/
goog.global.CLOSURE_IMPORT_SCRIPT = function(src, opt_sourceText) {
numPendingScripts++;
lastScriptLoaded = lastScriptLoaded
.then(() => new Promise(resolve => {
const script = document.createElement("script");
if (opt_sourceText) {
script.textContent = opt_sourceText;
setTimeout(resolve, 10);
} else {
script.src = src;
script.addEventListener("load", () => {
resolve();
});
script.addEventListener("error", () => {
resolve();
});
}
document.head.appendChild(script);
numPendingScripts--;
}));
}
}
export default function whenScriptsLoaded(callback) {
if (COMPILED) {
callback();
} else {
const _areWeThereYet = () => {
if (!numPendingScripts) {
callback();
} else {
lastScriptLoaded.then(() => {
setTimeout(_areWeThereYet, 100);
});
}
}
_areWeThereYet();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment