Created
August 25, 2017 02:55
-
-
Save rconnamacher/a0945c48463ad443712969e450bb0a99 to your computer and use it in GitHub Desktop.
Importing Closure Library into Browser-Native ES6 Modules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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