|
| 1 | +// Author: ScriptedAlchemy <[email protected]> |
| 2 | +// Author: Johannes Raggam <[email protected]> |
| 3 | + |
| 4 | +// From: |
| 5 | +// https://twitter.com/ScriptedAlchemy/status/1505135006158532612 |
| 6 | +// https://gist.github.com/ScriptedAlchemy/3a24008ef60adc47fad1af7d3299a063 |
| 7 | +// https://github.com/module-federation/module-federation-examples/blob/master/dynamic-system-host/app1/src/utils/getOrLoadRemote.js |
| 8 | + |
| 9 | +/** |
| 10 | + * Load remote module / bundle. |
| 11 | + * |
| 12 | + * Usage: get_container("bundle-name-xyz", "default", "http://theRemote.com") |
| 13 | + * |
| 14 | + * |
| 15 | + * @param {string} remote - the remote global name |
| 16 | + * @param {string} share_scope - the scope key |
| 17 | + * @param {string} remote_fallback_url - fallback url for remote module |
| 18 | + * @returns {Promise<object>} - Federated Module Container |
| 19 | + */ |
| 20 | +export default function get_container( |
| 21 | + remote, |
| 22 | + share_scope = "default", |
| 23 | + remote_fallback_url = undefined |
| 24 | +) { |
| 25 | + new Promise((resolve, reject) => { |
| 26 | + if (!window[remote]) { |
| 27 | + // Remote not yet globally available. |
| 28 | + |
| 29 | + // onload hook when Module Federated resource is loaded. |
| 30 | + const onload = async () => { |
| 31 | + // When remote is loaded, initialize it if it wasn't already. |
| 32 | + if (!window[remote].__initialized) { |
| 33 | + await window[remote].init(__webpack_share_scopes__[share_scope]); // eslint-disable-line no-undef |
| 34 | + // Mark remote as initialized. |
| 35 | + window[remote].__initialized = true; |
| 36 | + } |
| 37 | + // Resolve promise so marking remote as loaded. |
| 38 | + resolve(window[remote]); |
| 39 | + }; |
| 40 | + |
| 41 | + // Search dom to see if the remote exists as script tag. |
| 42 | + // It might still be loading (async). |
| 43 | + const existing_remote = document.querySelector(`[data-webpack="${remote}"]`); |
| 44 | + |
| 45 | + if (existing_remote) { |
| 46 | + // If remote exists but was not loaded, hook into its onload |
| 47 | + // and wait for it to be ready. |
| 48 | + existing_remote.onload = onload; |
| 49 | + existing_remote.onerror = reject; |
| 50 | + } else if (remote_fallback_url) { |
| 51 | + // Inject remote if a fallback exists and call the same onload |
| 52 | + // function |
| 53 | + const script = document.createElement("script"); |
| 54 | + script.type = "text/javascript"; |
| 55 | + // Mark as data-webpack so runtime can track it internally. |
| 56 | + script.setAttribute("data-webpack", `${remote}`); |
| 57 | + script.async = true; |
| 58 | + script.onerror = reject; |
| 59 | + script.onload = onload; |
| 60 | + script.src = remote_fallback_url; |
| 61 | + document.getElementsByTagName("head")[0].appendChild(script); |
| 62 | + } else { |
| 63 | + // No remote and no fallback exist, reject. |
| 64 | + reject(`Cannot Find Remote ${remote} to inject`); |
| 65 | + } |
| 66 | + } else { |
| 67 | + // Remote already instantiated, resolve |
| 68 | + resolve(window[remote]); |
| 69 | + } |
| 70 | + }); |
| 71 | +} |
0 commit comments