fixed the racecondition of the composite services renderer

This commit is contained in:
Samuel Andert 2023-07-27 10:51:52 +02:00
parent 460deb3be1
commit e2ea57e89f
4 changed files with 77 additions and 73 deletions

View File

@ -6,7 +6,7 @@
import { createMessage } from '$lib/services/messages/messages'; import { createMessage } from '$lib/services/messages/messages';
import { createLitSession } from '$lib/services/createLitSession/createLitSession'; import { createLitSession } from '$lib/services/createLitSession/createLitSession';
const redirectUri = 'http://localhost:5173/login'; const redirectUri = 'http://localhost:5173/login/';
export let services; export let services;

View File

@ -3,6 +3,7 @@
export let store; export let store;
let isStoreLoaded = false; let isStoreLoaded = false;
$: console.log('store: ' + JSON.stringify($store));
$: if (services && services.helloEarthAlert) { $: if (services && services.helloEarthAlert) {
// services.helloEarthAlert.alertMe(); // services.helloEarthAlert.alertMe();

View File

@ -6,6 +6,14 @@
import { dataStore } from '$lib/core/dataLoader'; import { dataStore } from '$lib/core/dataLoader';
import { createCompositeStore, getCompositeStore } from '$lib/core/compositeStores'; import { createCompositeStore, getCompositeStore } from '$lib/core/compositeStores';
interface ICompositeLayout {
areas: string;
columns?: string;
rows?: string;
gap?: string;
tailwindClasses?: string;
}
interface IComposite { interface IComposite {
layout?: ICompositeLayout; layout?: ICompositeLayout;
id: string; id: string;
@ -15,14 +23,7 @@
map?: Record<string, string>; map?: Record<string, string>;
store?: Record<string, any>; store?: Record<string, any>;
children?: IComposite[]; children?: IComposite[];
} servicesLoaded?: boolean;
interface ICompositeLayout {
areas: string;
columns?: string;
rows?: string;
gap?: string;
tailwindClasses?: string;
} }
export let composite: IComposite; export let composite: IComposite;
@ -30,33 +31,22 @@
let layoutStyle = ''; let layoutStyle = '';
$: { $: {
// Create layout style reactively
layoutStyle = computeLayoutStyle(composite?.layout); layoutStyle = computeLayoutStyle(composite?.layout);
// Load services reactively initializeAndLoadServices(composite);
if (composite?.services) { initializeCompositeState(composite);
for (const serviceName of composite.services) { mapAndSubscribe(composite);
if (!loadedServices[serviceName]) {
// Note: We're ignoring async operation here, you might want to handle it if needed
loadService(serviceName).then((service) => {
loadedServices[serviceName] = service;
});
}
}
}
// Initialize composite state reactively
if (composite?.children) { if (composite?.children) {
composite.children.forEach((child) => { composite.children.forEach((child) => {
initializeCompositeState(child); initializeAndLoadServices(child);
mapAndSubscribe(child); mapAndSubscribe(child);
}); });
} }
} }
function computeLayoutStyle(layout?: ICompositeLayout) { function computeLayoutStyle(layout?: ICompositeLayout): string {
if (!layout) return ''; if (!layout) return '';
return ` return `
grid-template-areas: ${layout.areas}; grid-template-areas: ${layout.areas};
${layout.gap ? `gap: ${layout.gap};` : ''} ${layout.gap ? `gap: ${layout.gap};` : ''}
@ -65,6 +55,27 @@
`; `;
} }
function initializeAndLoadServices(component: IComposite) {
if (!component) return;
if (component.services) {
let servicePromises = component.services.map((serviceName) =>
loadedServices[serviceName]
? Promise.resolve(loadedServices[serviceName])
: loadService(serviceName)
);
Promise.all(servicePromises).then((loaded) => {
loaded.forEach((service, index) => {
loadedServices[component.services[index]] = service;
});
component.servicesLoaded = true;
});
} else {
component.servicesLoaded = true;
}
}
function initializeCompositeState(child: IComposite) { function initializeCompositeState(child: IComposite) {
if (child.id) { if (child.id) {
child.store = createCompositeStore(child.id, child.store || {}); child.store = createCompositeStore(child.id, child.store || {});
@ -78,8 +89,6 @@
let unsubscribers = []; let unsubscribers = [];
function mapAndSubscribe(component: IComposite) { function mapAndSubscribe(component: IComposite) {
console.log('Mapping and subscribing for:', component.id);
if (component.map) { if (component.map) {
const localStore = getCompositeStore(component.id); const localStore = getCompositeStore(component.id);
@ -91,15 +100,14 @@
if (externalKey in store) { if (externalKey in store) {
if (store[externalKey] && typeof store[externalKey].subscribe === 'function') { if (store[externalKey] && typeof store[externalKey].subscribe === 'function') {
let innerUnsub = store[externalKey].subscribe((value) => { let innerUnsub = store[externalKey].subscribe((value) => {
localStore.update((storeValue) => { localStore.update((storeValue) => ({ ...storeValue, [localKey]: value }));
return { ...storeValue, [localKey]: value };
});
}); });
unsubscribers.push(innerUnsub); unsubscribers.push(innerUnsub);
} else { } else {
localStore.update((storeValue) => { localStore.update((storeValue) => ({
return { ...storeValue, [localKey]: store[externalKey] }; ...storeValue,
}); [localKey]: store[externalKey]
}));
} }
} }
}); });
@ -110,9 +118,10 @@
if (externalStore) { if (externalStore) {
const unsubscribe = externalStore.subscribe((externalState) => { const unsubscribe = externalStore.subscribe((externalState) => {
if (externalState && externalKey in externalState) { if (externalState && externalKey in externalState) {
localStore.update((storeValue) => { localStore.update((storeValue) => ({
return { ...storeValue, [localKey]: externalState[externalKey] }; ...storeValue,
}); [localKey]: externalState[externalKey]
}));
} }
}); });
@ -127,7 +136,6 @@
} }
} }
// Call all unsubscribe methods when the component is destroyed.
onDestroy(() => { onDestroy(() => {
unsubscribers.forEach((unsub) => unsub()); unsubscribers.forEach((unsub) => unsub());
}); });
@ -148,27 +156,14 @@
return null; return null;
} }
async function getServiceProps(component: IComposite) {
const loadedServices = {};
if (component.services) {
for (const serviceName of component.services) {
const loadedService = await loadService(serviceName);
if (loadedService) {
loadedServices[serviceName] = loadedService;
}
}
}
return loadedServices;
}
async function loadComponentAndService(component: IComposite) { async function loadComponentAndService(component: IComposite) {
return await Promise.all([getComponent(component.component), getServiceProps(component)]); return await getComponent(component.component);
} }
</script> </script>
<div class={`grid w-full h-full ${composite?.layout?.tailwindClasses || ''}`} style={layoutStyle}> <div class={`grid w-full h-full ${composite?.layout?.tailwindClasses || ''}`} style={layoutStyle}>
{#if composite && 'component' in composite} {#if composite?.servicesLoaded}
{#await loadComponentAndService(composite) then [Component]} {#await loadComponentAndService(composite) then Component}
{#if Component} {#if Component}
<svelte:component <svelte:component
this={Component} this={Component}
@ -176,7 +171,7 @@
store={getCompositeStore(composite.id)} store={getCompositeStore(composite.id)}
services={loadedServices} services={loadedServices}
/> />
{:else if composite.component} {:else}
<p>Component {composite.component} not found.</p> <p>Component {composite.component} not found.</p>
{/if} {/if}
{/await} {/await}
@ -185,7 +180,8 @@
{#if composite?.children} {#if composite?.children}
{#each composite.children as child (child.id)} {#each composite.children as child (child.id)}
<div class="w-full h-full overflow-hidden" style={`grid-area: ${child.slot}`}> <div class="w-full h-full overflow-hidden" style={`grid-area: ${child.slot}`}>
{#await loadComponentAndService(child) then [ChildComponent]} {#if child.servicesLoaded}
{#await loadComponentAndService(child) then ChildComponent}
{#if ChildComponent} {#if ChildComponent}
<svelte:component <svelte:component
this={ChildComponent} this={ChildComponent}
@ -196,10 +192,13 @@
{#if child.children && child.children.length} {#if child.children && child.children.length}
<Composite composite={child} /> <Composite composite={child} />
{/if} {/if}
{:else if child.component} {:else}
<p>Component {child.component} not found.</p> <p>Component {child.component} not found.</p>
{/if} {/if}
{/await} {/await}
{:else}
<p>Loading services for child {child.id}...</p>
{/if}
</div> </div>
{/each} {/each}
{/if} {/if}

View File

@ -10,6 +10,10 @@
import { Drawer, drawerStore } from '@skeletonlabs/skeleton'; import { Drawer, drawerStore } from '@skeletonlabs/skeleton';
import Composite from '$lib/core/Composite.svelte'; import Composite from '$lib/core/Composite.svelte';
const providerData = {
walletConnectId: import.meta.env.VITE_WALLETCONNECT_ID
};
onMount(() => { onMount(() => {
initChainProvider(providerData); initChainProvider(providerData);
}); });