perf: optimize fleetbase.config.json loading with localStorage caching

- Added 1-hour localStorage cache for runtime config
- Reduces 750ms+ HTTP request to instant cache lookup
- Cache automatically expires and refreshes
- Includes cache clear utility function
- Uses browser cache as fallback
- Performance logging with debug()
- Excluded JSON files from fingerprinting

Expected improvement: 783ms → <5ms (99.4% faster)
This commit is contained in:
roncodes
2025-11-28 04:37:29 -05:00
parent 5726eb974f
commit affa141c9d
2 changed files with 108 additions and 6 deletions

View File

@@ -17,6 +17,13 @@ const RUNTIME_CONFIG_MAP = {
EXTENSIONS: 'APP.extensions',
};
/**
* Cache key for localStorage
*/
const CACHE_KEY = 'fleetbase_runtime_config';
const CACHE_VERSION_KEY = 'fleetbase_runtime_config_version';
const CACHE_TTL = 1000 * 60 * 60; // 1 hour
/**
* Coerce and sanitize runtime config values based on key.
*
@@ -59,26 +66,115 @@ export function applyRuntimeConfig(rawConfig = {}) {
}
/**
* Load and apply runtime config.
* Get cached config from localStorage
*
* @returns {Object|null} Cached config or null
*/
function getCachedConfig() {
try {
const cached = localStorage.getItem(CACHE_KEY);
const cachedVersion = localStorage.getItem(CACHE_VERSION_KEY);
if (!cached || !cachedVersion) {
return null;
}
const cacheData = JSON.parse(cached);
const cacheAge = Date.now() - cacheData.timestamp;
// Check if cache is still valid (within TTL)
if (cacheAge > CACHE_TTL) {
debug('[runtime-config] Cache expired');
return null;
}
debug(`[runtime-config] Using cached config (age: ${Math.round(cacheAge / 1000)}s)`);
return cacheData.config;
} catch (e) {
debug(`[runtime-config] Failed to read cache: ${e.message}`);
return null;
}
}
/**
* Save config to localStorage cache
*
* @param {Object} config Config object
*/
function setCachedConfig(config) {
try {
const cacheData = {
config,
timestamp: Date.now()
};
localStorage.setItem(CACHE_KEY, JSON.stringify(cacheData));
localStorage.setItem(CACHE_VERSION_KEY, '1');
debug('[runtime-config] Config cached to localStorage');
} catch (e) {
debug(`[runtime-config] Failed to cache config: ${e.message}`);
}
}
/**
* Clear cached config
*
* @export
*/
export function clearRuntimeConfigCache() {
try {
localStorage.removeItem(CACHE_KEY);
localStorage.removeItem(CACHE_VERSION_KEY);
debug('[runtime-config] Cache cleared');
} catch (e) {
debug(`[runtime-config] Failed to clear cache: ${e.message}`);
}
}
/**
* Load and apply runtime config with localStorage caching.
*
* Strategy:
* 1. Check localStorage cache first (instant, no HTTP request)
* 2. If cache hit and valid, use it immediately
* 3. If cache miss, fetch from server and cache the result
* 4. Cache is valid for 1 hour
*
* @export
* @return {void}
* @return {Promise<void>}
*/
export default async function loadRuntimeConfig() {
if (config.APP.disableRuntimeConfig) {
return;
}
// Try cache first
const cachedConfig = getCachedConfig();
if (cachedConfig) {
applyRuntimeConfig(cachedConfig);
return;
}
// Cache miss - fetch from server
try {
const response = await fetch(`/fleetbase.config.json?_t=${Date.now()}`, { cache: 'no-cache' });
const startTime = performance.now();
const response = await fetch(`/fleetbase.config.json`, {
cache: 'default' // Use browser cache if available
});
if (!response.ok) {
debug('No fleetbase.config.json found, using built-in config defaults');
debug('[runtime-config] No fleetbase.config.json found, using built-in config defaults');
return;
}
const runtimeConfig = await response.json();
const endTime = performance.now();
debug(`[runtime-config] Fetched from server in ${(endTime - startTime).toFixed(2)}ms`);
// Apply and cache
applyRuntimeConfig(runtimeConfig);
setCachedConfig(runtimeConfig);
} catch (e) {
debug(`Failed to load runtime config : ${e.message}`);
debug(`[runtime-config] Failed to load runtime config: ${e.message}`);
}
}

View File

@@ -25,7 +25,13 @@ module.exports = function (defaults) {
storeConfigInMeta: false,
fingerprint: {
exclude: ['leaflet/', 'leaflet-images/', 'socketcluster-client.min.js'],
exclude: [
'leaflet/',
'leaflet-images/',
'socketcluster-client.min.js',
'fleetbase.config.json',
'extensions.json'
],
},
liveReload: {