mf-dynamic-remote-component
Version:
Library for loading in dynamic remote components when utilizing webpack Module Federation
116 lines (101 loc) • 3.43 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function remoteModuleIdentifier({path, module, scope}) {
return [path, module, scope].join('');
}
/**
*
* @param {Object} remoteModule contains the config with path to load the remote container
* @summary Appends a dynamic script element pointing to the remote container
* @return {Promise}
*/
function getDynamicScript(remoteModule) {
const id = remoteModuleIdentifier(remoteModule);
const existingElement = document.getElementById(id);
if (existingElement) {
if (window[remoteModule.scope]) {
return Promise.resolve(true);
}
return new Promise((resolve) => {
existingElement.onload = (e) => {
resolve(true);
};
});
}
const element = document.createElement('script');
element.src = remoteModule.path;
element.type = 'text/javascript';
element.async = true;
element.id = id;
document.head.appendChild(element);
return new Promise((resolve, reject) => {
element.onload = () => {
resolve(true);
};
element.onerror = () => {
// eslint-disable-next-line no-console
console.error(`Dynamic Script Error: ${remoteModule.path}`);
reject(new Error(`Dynamic Script Error: ${remoteModule.path}`));
};
});
}
/* eslint-disable no-undef */
// https://webpack.js.org/concepts/module-federation/#dynamic-remote-containers
/**
* @param {String} path remote container scope path
* @param {String} scope container scope
* @param {*} module provided module to fetch from container
* @return {Module} the remote module
*/
async function loadComponent(path, scope, module) {
try {
// Initializes the shared scope.
// Fills known provided modules from this build and all remotes
await __webpack_init_sharing__('default');
const container = window[scope]; // or get the container somewhere else
// Initialize the container, it may provide shared modules
// eslint-disable-next-line camelcase
await container.init(__webpack_share_scopes__.default);
const factory = await window[scope].get(module);
const Module = factory();
return Module;
} catch (e) {
throw new Error(`Error loading remote module.
Please check the url: ${path}, scope: ${scope} and module: ${module}
-----------------------------------------------
${e}`);
}
}
const loadingPromise = (remoteModule) =>
new Promise(async (resolve, reject) => {
try {
await getDynamicScript(remoteModule);
const _module = await loadComponent(
remoteModule.path,
remoteModule.scope,
remoteModule.module,
);
resolve(_module);
} catch (e) {
console.log(`mf-dynamic-remote-component: error getting remote ${e}`);
reject(e);
}
});
/**
*
* @param {Object} remoteModule remote module config containing path, scope and module
* @return {Promise} promise that resolves to module
*/
function RemoteComponent(remoteModule) {
window.remoteMFStore = window.remoteMFStore || {};
const id = remoteModuleIdentifier(remoteModule);
const existingModule = window.remoteMFStore[id];
if (existingModule) {
return existingModule;
}
window.remoteMFStore[id] = loadingPromise(remoteModule);
return window.remoteMFStore[id];
}
exports.RemoteComponent = RemoteComponent;
exports.getDynamicScript = getDynamicScript;
exports.loadComponent = loadComponent;