@jakobcooldown/react-csr-sdk
Version:
Mockery SDK for dynamic bundle loading in web applications
146 lines (145 loc) • 5.71 kB
JavaScript
;
/**
* Mockery Bundle Loader
*
* This script should be included in HTML BEFORE any React bundle scripts.
* It checks localStorage for a custom bundle URL and loads it, or falls back to default.
*
* Usage in HTML:
* <script src="mockery-bundle-loader.js"></script>
* <script data-mockery-default-bundle src="./assets/index-abc123.js"></script>
*/
(function () {
'use strict';
const STORAGE_KEY = 'mockery_bundle_url';
const DEBUG_KEY = 'mockery_debug';
function log(message, ...args) {
if (localStorage.getItem(DEBUG_KEY) === 'true') {
console.log('[Mockery Bundle Loader]', message, ...args);
}
}
function loadScript(src, onLoad, onError) {
log('Loading script:', src);
const script = document.createElement('script');
script.src = src;
script.type = 'module';
script.crossOrigin = 'anonymous';
script.onload = function () {
log('Script loaded successfully:', src);
onLoad && onLoad();
};
script.onerror = function (error) {
log('Script failed to load:', src, error);
onError && onError(error);
};
document.head.appendChild(script);
return script;
}
function getDefaultBundleUrl() {
// Look for script tag with data-mockery-default-bundle attribute
const defaultScript = document.querySelector('script[data-mockery-default-bundle]');
if (defaultScript && defaultScript.src) {
return defaultScript.src;
}
// Fallback: look for common bundle patterns
const scripts = document.querySelectorAll('script[src]');
for (const script of scripts) {
const src = script.src;
if (src.includes('index-') || src.includes('main-') || src.includes('app-')) {
return src;
}
}
return undefined;
}
function preventDefaultBundleLoad() {
// Prevent default bundle scripts from loading by removing them
const defaultScript = document.querySelector('script[data-mockery-default-bundle]');
if (defaultScript) {
log('Preventing default bundle load:', defaultScript.src);
defaultScript.remove();
}
// Also remove any script that might be the default bundle
const scripts = document.querySelectorAll('script[src]');
scripts.forEach(script => {
const src = script.src;
if (src && (src.includes('index-') || src.includes('main-') || src.includes('app-'))) {
log('Removing potential default bundle script:', src);
script.remove();
}
});
}
function initializeBundleLoader() {
log('Initializing bundle loader');
try {
const customBundleUrl = localStorage.getItem(STORAGE_KEY) || undefined;
const defaultBundleUrl = getDefaultBundleUrl();
log('Custom bundle URL:', customBundleUrl);
log('Default bundle URL:', defaultBundleUrl);
if (customBundleUrl) {
// Load custom bundle instead of default
preventDefaultBundleLoad();
loadScript(customBundleUrl, null, function (error) {
log('Custom bundle failed, falling back to default');
if (defaultBundleUrl) {
loadScript(defaultBundleUrl);
}
});
}
else {
// Let default bundle load normally
log('No custom bundle set, using default');
}
// Expose global utilities for setting bundle URL
window.mockery = window.mockery || {};
window.mockery.setCustomBundle = function (bundleUrl) {
const currentBundle = localStorage.getItem(STORAGE_KEY) || undefined;
// Exit early if bundle URL is unchanged
if (bundleUrl === currentBundle) {
return;
}
log('Setting custom bundle:', bundleUrl);
if (bundleUrl) {
localStorage.setItem(STORAGE_KEY, bundleUrl);
}
else {
localStorage.removeItem(STORAGE_KEY);
}
};
window.mockery.getCustomBundle = function () {
return localStorage.getItem(STORAGE_KEY) || undefined;
};
window.mockery.clearCustomBundle = function () {
log('Clearing custom bundle');
localStorage.removeItem(STORAGE_KEY);
};
window.mockery.reloadWithBundle = function (bundleUrl) {
log('Reloading with bundle:', bundleUrl);
if (bundleUrl) {
localStorage.setItem(STORAGE_KEY, bundleUrl);
}
else {
localStorage.removeItem(STORAGE_KEY);
}
window.location.reload();
};
window.mockery.setDebug = function (enabled) {
if (enabled) {
localStorage.setItem(DEBUG_KEY, 'true');
}
else {
localStorage.removeItem(DEBUG_KEY);
}
};
}
catch (error) {
log('Error during initialization:', error);
}
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeBundleLoader);
}
else {
initializeBundleLoader();
}
})();