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 { createLitSession } from '$lib/services/createLitSession/createLitSession';
const redirectUri = 'http://localhost:5173/login';
const redirectUri = 'http://localhost:5173/login/';
export let services;

View File

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

View File

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

View File

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