@memberjunction/react-runtime
Version:
Platform-agnostic React component runtime for MemberJunction. Provides core compilation, registry, and execution capabilities for React components in any JavaScript environment.
214 lines • 9.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.LibraryLoader = void 0;
const standard_libraries_1 = require("./standard-libraries");
const core_libraries_1 = require("./core-libraries");
const resource_manager_1 = require("./resource-manager");
const LIBRARY_LOADER_COMPONENT_ID = 'mj-react-runtime-library-loader-singleton';
class LibraryLoader {
static async loadAllLibraries(config, additionalLibraries) {
if (config) {
standard_libraries_1.StandardLibraryManager.setConfiguration(config);
}
if (additionalLibraries && additionalLibraries.length > 0) {
const currentConfig = standard_libraries_1.StandardLibraryManager.getConfiguration();
const mergedConfig = {
libraries: [...currentConfig.libraries, ...additionalLibraries],
metadata: {
...currentConfig.metadata,
lastUpdated: new Date().toISOString()
}
};
standard_libraries_1.StandardLibraryManager.setConfiguration(mergedConfig);
}
return this.loadLibrariesFromConfig();
}
static async loadLibrariesFromConfig(options) {
const coreLibraries = (0, core_libraries_1.getCoreRuntimeLibraries)();
const corePromises = coreLibraries.map(lib => this.loadScript(lib.cdnUrl, lib.globalVariable));
const coreResults = await Promise.all(corePromises);
const React = coreResults.find((_, i) => coreLibraries[i].globalVariable === 'React');
const ReactDOM = coreResults.find((_, i) => coreLibraries[i].globalVariable === 'ReactDOM');
const Babel = coreResults.find((_, i) => coreLibraries[i].globalVariable === 'Babel');
if (typeof window !== 'undefined') {
if (React && !window.React) {
window.React = React;
console.log('✓ Exposed React as window.React for UMD compatibility');
}
if (ReactDOM && !window.ReactDOM) {
window.ReactDOM = ReactDOM;
console.log('✓ Exposed ReactDOM as window.ReactDOM for UMD compatibility');
}
if (!window.PropTypes) {
window.PropTypes = {};
console.log('✓ Exposed empty PropTypes as window.PropTypes for UMD compatibility');
}
}
const config = standard_libraries_1.StandardLibraryManager.getConfiguration();
const enabledLibraries = standard_libraries_1.StandardLibraryManager.getEnabledLibraries();
let pluginLibraries = enabledLibraries.filter(lib => !(0, core_libraries_1.isCoreRuntimeLibrary)(lib.id));
if (options) {
if (options.categories) {
pluginLibraries = pluginLibraries.filter(lib => options.categories.includes(lib.category));
}
if (options.excludeRuntimeOnly) {
pluginLibraries = pluginLibraries.filter(lib => !lib.isRuntimeOnly);
}
}
pluginLibraries.forEach(lib => {
if (lib.cdnCssUrl) {
this.loadCSS(lib.cdnCssUrl);
}
});
const pluginPromises = pluginLibraries.map(lib => this.loadScript(lib.cdnUrl, lib.globalVariable));
const pluginResults = await Promise.all(pluginPromises);
const libraries = {};
pluginLibraries.forEach((lib, index) => {
libraries[lib.globalVariable] = pluginResults[index];
});
return {
React: React || window.React,
ReactDOM: ReactDOM || window.ReactDOM,
Babel: Babel || window.Babel,
libraries
};
}
static async loadLibraries(options) {
const { loadCore = true, loadUI = true, loadCSS = true, customLibraries = [] } = options;
const categoriesToLoad = ['runtime'];
if (loadCore) {
categoriesToLoad.push('utility', 'charting');
}
if (loadUI) {
categoriesToLoad.push('ui');
}
const result = await this.loadLibrariesFromConfig({
categories: categoriesToLoad
});
if (customLibraries.length > 0) {
const customPromises = customLibraries.map(({ url, globalName }) => this.loadScript(url, globalName));
const customResults = await Promise.all(customPromises);
customLibraries.forEach(({ globalName }, index) => {
result.libraries[globalName] = customResults[index];
});
}
return result;
}
static async loadScript(url, globalName) {
const existing = this.loadedResources.get(url);
if (existing) {
return existing.promise;
}
const promise = new Promise((resolve, reject) => {
const existingGlobal = window[globalName];
if (existingGlobal) {
resolve(existingGlobal);
return;
}
const existingScript = document.querySelector(`script[src="${url}"]`);
if (existingScript) {
this.waitForScriptLoad(existingScript, globalName, resolve, reject);
return;
}
const script = document.createElement('script');
script.src = url;
script.async = true;
script.crossOrigin = 'anonymous';
const cleanup = () => {
script.removeEventListener('load', onLoad);
script.removeEventListener('error', onError);
};
const onLoad = () => {
cleanup();
const global = window[globalName];
if (global) {
resolve(global);
}
else {
const timeoutId = resource_manager_1.resourceManager.setTimeout(LIBRARY_LOADER_COMPONENT_ID, () => {
const delayedGlobal = window[globalName];
if (delayedGlobal) {
resolve(delayedGlobal);
}
else {
reject(new Error(`${globalName} not found after script load`));
}
}, 100, { url, globalName });
}
};
const onError = () => {
cleanup();
reject(new Error(`Failed to load script: ${url}`));
};
script.addEventListener('load', onLoad);
script.addEventListener('error', onError);
document.head.appendChild(script);
resource_manager_1.resourceManager.registerDOMElement(LIBRARY_LOADER_COMPONENT_ID, script);
});
this.loadedResources.set(url, {
element: document.querySelector(`script[src="${url}"]`),
promise
});
return promise;
}
static loadCSS(url) {
if (this.loadedResources.has(url)) {
return;
}
const existingLink = document.querySelector(`link[href="${url}"]`);
if (existingLink) {
return;
}
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
document.head.appendChild(link);
resource_manager_1.resourceManager.registerDOMElement(LIBRARY_LOADER_COMPONENT_ID, link);
this.loadedResources.set(url, {
element: link,
promise: Promise.resolve()
});
}
static waitForScriptLoad(script, globalName, resolve, reject) {
const checkGlobal = () => {
const global = window[globalName];
if (global) {
resolve(global);
}
else {
resource_manager_1.resourceManager.setTimeout(LIBRARY_LOADER_COMPONENT_ID, () => {
const delayedGlobal = window[globalName];
if (delayedGlobal) {
resolve(delayedGlobal);
}
else {
reject(new Error(`${globalName} not found after script load`));
}
}, 100, { context: 'waitForScriptLoad', globalName });
}
};
if (script.complete || script.readyState === 'complete') {
checkGlobal();
return;
}
const loadHandler = () => {
checkGlobal();
};
resource_manager_1.resourceManager.addEventListener(LIBRARY_LOADER_COMPONENT_ID, script, 'load', loadHandler, { once: true });
}
static getLoadedResources() {
return this.loadedResources;
}
static clearCache() {
this.loadedResources.forEach((resource, url) => {
if (resource.element && resource.element.parentNode) {
resource.element.parentNode.removeChild(resource.element);
}
});
this.loadedResources.clear();
resource_manager_1.resourceManager.cleanupComponent(LIBRARY_LOADER_COMPONENT_ID);
}
}
exports.LibraryLoader = LibraryLoader;
LibraryLoader.loadedResources = new Map();
//# sourceMappingURL=library-loader.js.map