perf(hydration): implement cache-first site discovery and SWR event loading
- Refactored lookup_site_domain_v3 to be cache-first, unblocking root layout. - Implemented Stale-While-Revalidate (SWR) pattern for load_ae_obj_id__event. - Added global hydration overlay and loading spinner to +layout.svelte. - Updated site domain whitelist to persist critical account/styling metadata in Dexie. - Refactored root load function to return immediately if cached site data is found.
This commit is contained in:
@@ -14,7 +14,7 @@ import { load_ae_obj_li__event_file } from '$lib/ae_events/ae_events__event_file
|
||||
|
||||
const ae_promises: key_val = {};
|
||||
|
||||
// Updated 2026-01-16
|
||||
// Updated 2026-01-26 (Stale-While-Revalidate Optimization)
|
||||
export async function load_ae_obj_id__event({
|
||||
api_cfg,
|
||||
event_id,
|
||||
@@ -39,16 +39,54 @@ export async function load_ae_obj_id__event({
|
||||
log_lvl?: number;
|
||||
}): Promise<ae_Event | null> {
|
||||
if (log_lvl) {
|
||||
console.log(`*** load_ae_obj_id__event() *** event_id=${event_id}`);
|
||||
console.log(`*** load_ae_obj_id__event() *** event_id=${event_id} (SWR Optimization)`);
|
||||
}
|
||||
|
||||
let cached_event: any = null;
|
||||
|
||||
// 1. FAST PATH: Return cached data immediately
|
||||
if (try_cache) {
|
||||
try {
|
||||
cached_event = await db_events.event.get(event_id);
|
||||
if (cached_event) {
|
||||
if (log_lvl) console.log('EVENT LOAD: Cache hit. Returning stale data immediately.');
|
||||
|
||||
// Trigger background refresh
|
||||
_refresh_event_v3_background({
|
||||
api_cfg, event_id, view, try_cache,
|
||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_template_li,
|
||||
log_lvl: 0
|
||||
});
|
||||
|
||||
// Still handle nested loads for the cached version to ensure UI richness
|
||||
return await _handle_nested_loads(cached_event, {
|
||||
api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_template_li, log_lvl
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.warn('EVENT LOAD: Cache read failed.', e);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. SLOW PATH: Wait for API if cache is empty or try_cache is false
|
||||
return await _refresh_event_v3_background({
|
||||
api_cfg, event_id, view, try_cache,
|
||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_template_li,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper to perform the actual API fetch and cache update for events
|
||||
*/
|
||||
async function _refresh_event_v3_background({
|
||||
api_cfg, event_id, view, try_cache,
|
||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_template_li,
|
||||
log_lvl
|
||||
}: any) {
|
||||
// Check if offline
|
||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||
if (log_lvl) console.log('Browser is offline. Skipping API and attempting cache load.');
|
||||
ae_promises.load__event_obj = await db_events.event.get(event_id);
|
||||
if (ae_promises.load__event_obj) {
|
||||
return await _handle_nested_loads(ae_promises.load__event_obj, { api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_template_li, log_lvl });
|
||||
}
|
||||
if (log_lvl) console.log('Browser is offline. Skipping API refresh.');
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -75,31 +113,15 @@ export async function load_ae_obj_id__event({
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
}
|
||||
ae_promises.load__event_obj = event_obj_get_result;
|
||||
} else {
|
||||
console.log('No results returned from API.');
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log('Attempting to load from local cache...');
|
||||
ae_promises.load__event_obj = await db_events.event.get(event_id);
|
||||
} else {
|
||||
ae_promises.load__event_obj = null;
|
||||
}
|
||||
|
||||
return await _handle_nested_loads(event_obj_get_result, {
|
||||
api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_template_li, log_lvl
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('API request failed.', error);
|
||||
if (try_cache) {
|
||||
if (log_lvl) console.log('Attempting to load from local cache after error...');
|
||||
ae_promises.load__event_obj = await db_events.event.get(event_id);
|
||||
} else {
|
||||
ae_promises.load__event_obj = null;
|
||||
}
|
||||
if (log_lvl) console.log('Event API refresh failed.', error);
|
||||
}
|
||||
|
||||
if (!ae_promises?.load__event_obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await _handle_nested_loads(ae_promises.load__event_obj, { api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_template_li, log_lvl });
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,48 +130,53 @@ export async function load_ae_obj_id__event({
|
||||
async function _handle_nested_loads(event_obj: any, { api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_template_li, log_lvl }: any) {
|
||||
const current_event_id = event_obj.event_id_random || event_obj.event_id || event_obj.id;
|
||||
|
||||
// Use Promise.all for concurrent nested loads to further reduce delay
|
||||
const tasks = [];
|
||||
|
||||
if (inc_device_li) {
|
||||
event_obj.event_device_obj_li = await load_ae_obj_li__event_device({
|
||||
tasks.push(load_ae_obj_li__event_device({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}).then(res => event_obj.event_device_obj_li = res));
|
||||
}
|
||||
if (inc_file_li) {
|
||||
event_obj.event_file_li = await load_ae_obj_li__event_file({
|
||||
tasks.push(load_ae_obj_li__event_file({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
enabled: 'all',
|
||||
limit: 100,
|
||||
log_lvl
|
||||
});
|
||||
}).then(res => event_obj.event_file_li = res));
|
||||
}
|
||||
if (inc_location_li) {
|
||||
event_obj.event_location_obj_li = await load_ae_obj_li__event_location({
|
||||
tasks.push(load_ae_obj_li__event_location({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}).then(res => event_obj.event_location_obj_li = res));
|
||||
}
|
||||
if (inc_session_li) {
|
||||
event_obj.event_session_obj_li = await load_ae_obj_li__event_session({
|
||||
tasks.push(load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}).then(res => event_obj.event_session_obj_li = res));
|
||||
}
|
||||
if (inc_template_li) {
|
||||
event_obj.event_badge_template_obj_li =
|
||||
await load_ae_obj_li__event_badge_template({
|
||||
api_cfg,
|
||||
event_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
tasks.push(load_ae_obj_li__event_badge_template({
|
||||
api_cfg,
|
||||
event_id: current_event_id,
|
||||
log_lvl
|
||||
}).then(res => event_obj.event_badge_template_obj_li = res));
|
||||
}
|
||||
|
||||
if (tasks.length > 0) await Promise.all(tasks);
|
||||
|
||||
return event_obj;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user