Added dynamic dataLoader importing and fixing race conditions

This commit is contained in:
Samuel Andert 2023-07-26 18:28:31 +02:00
parent a3761140bd
commit 371e42e4ee
6 changed files with 112 additions and 106 deletions

View File

@ -26,33 +26,43 @@
}
export let composite: IComposite;
let loadedServices: Record<string, any> = {};
let layoutStyle = '';
// Reactive loading mechanism for services based on composite changes
$: if (composite?.services) {
composite.services.forEach(async (serviceName) => {
if (!loadedServices[serviceName]) {
loadedServices[serviceName] = await loadService(serviceName);
$: {
// 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;
});
}
}
});
}
// Initialize composite state reactively
if (composite?.children) {
composite.children.forEach((child) => {
initializeCompositeState(child);
mapAndSubscribe(child);
});
}
}
$: layoutStyle = composite?.layout
? `
grid-template-areas: ${composite.layout.areas};
${composite.layout.gap ? `gap: ${composite.layout.gap};` : ''}
${composite.layout.columns ? `grid-template-columns: ${composite.layout.columns};` : ''}
${composite.layout.rows ? `grid-template-rows: ${composite.layout.rows};` : ''}
`
: '';
function computeLayoutStyle(layout?: ICompositeLayout) {
if (!layout) return '';
// Reactive statement to watch changes in the composite prop
$: if (composite?.children) {
composite.children.forEach((child) => {
initializeCompositeState(child);
mapAndSubscribe(child);
});
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};` : ''}
`;
}
function initializeCompositeState(child: IComposite) {
@ -65,6 +75,8 @@
}
}
let unsubscribers = [];
function mapAndSubscribe(component: IComposite) {
console.log('Mapping and subscribing for:', component.id);
@ -77,14 +89,13 @@
if (externalID === 'data') {
const unsubscribe = dataStore.subscribe((store) => {
if (externalKey in store) {
// Check if the data item is a Svelte store
if (store[externalKey] && typeof store[externalKey].subscribe === 'function') {
let innerUnsub = store[externalKey].subscribe((value) => {
localStore.update((storeValue) => {
return { ...storeValue, [localKey]: value };
});
});
onDestroy(innerUnsub);
unsubscribers.push(innerUnsub);
} else {
localStore.update((storeValue) => {
return { ...storeValue, [localKey]: store[externalKey] };
@ -93,7 +104,7 @@
}
});
onDestroy(unsubscribe);
unsubscribers.push(unsubscribe);
} else {
const externalStore = getCompositeStore(externalID);
if (externalStore) {
@ -105,7 +116,7 @@
}
});
onDestroy(unsubscribe);
unsubscribers.push(unsubscribe);
}
}
}
@ -116,6 +127,11 @@
}
}
// Call all unsubscribe methods when the component is destroyed.
onDestroy(() => {
unsubscribers.forEach((unsub) => unsub());
});
async function getComponent(componentName: string) {
if (components[componentName]) {
const module = await components[componentName]();

View File

@ -1,11 +1,30 @@
// dataLoader.ts
import { writable } from 'svelte/store';
import { queryMessagesData } from '$lib/data/queryMessages';
import { queryTodosData } from '$lib/data/queryTodos';
import dataSources from 'virtual:data-sources-list'; // Import the generated list
// The store that holds the data sets
export const dataStore = writable({
queryMessages: queryMessagesData,
queryTodos: queryTodosData
export const dataStore = writable({});
// Dynamically import the data modules and assign them to the store
dataSources.forEach(src => {
import(`/src/lib/data/${src}.ts`).then(module => {
// Here, explicitly extract the required data or function from the module
const moduleData = module[src] || module.default;
dataStore.update(store => ({ ...store, [src]: moduleData }));
});
});
// // dataLoader.ts
// import { writable } from 'svelte/store';
// import { queryMessages } from '$lib/data/queryMessages';
// import { queryTodos } from '$lib/data/queryTodos';
// // The store that holds the data sets
// export const dataStore = writable({
// queryMessages: queryMessages,
// queryTodos: queryTodos
// });

View File

@ -35,4 +35,4 @@ messages.subscribe(currentMessages => {
setToLocalStorage('chat-messages', currentMessages);
});
export const queryMessagesData = messages;
export const queryMessages = messages;

View File

@ -1,7 +1,7 @@
// $lib/data/queryTodos.ts
import { writable } from 'svelte/store';
export const queryTodosData = writable([
export const queryTodos = writable([
{
id: "id1",
text: "todo 1"

View File

@ -1,6 +1,6 @@
// $lib/services/messages.ts
import { queryMessagesData } from '$lib/data/queryMessages';
import { queryMessages } from '$lib/data/queryMessages';
// The createMessage function now accepts a messageData parameter.
export function createMessage(messageData) {
@ -15,78 +15,9 @@ export function createMessage(messageData) {
// We use the $ prefix to get the value out of a Svelte store
// and then set the new value back into the store.
queryMessagesData.update(oldMessages => [...oldMessages, newMessageObj]);
queryMessages.update(oldMessages => [...oldMessages, newMessageObj]);
}
export function clearMessages() {
queryMessagesData.set([]);
queryMessages.set([]);
}
// import { writable } from 'svelte/store';
// // Helper function to determine if we're running on the client side (browser) or server side.
// function isClientSide() {
// return typeof window !== "undefined";
// }
// // Safely get item from localStorage
// function getFromLocalStorage(key, defaultValue) {
// if (isClientSide()) {
// return localStorage.getItem(key)
// ? JSON.parse(localStorage.getItem(key))
// : defaultValue;
// }
// return defaultValue;
// }
// // Safely set item to localStorage
// function setToLocalStorage(key, value) {
// if (isClientSide()) {
// localStorage.setItem(key, JSON.stringify(value));
// }
// }
// // Define the updated Message interface
// export interface Message {
// text: string;
// timestamp: string;
// sender: string;
// type: string;
// composite?: object | null; // New field
// }
// // Load messages from localStorage or set an empty array if not available
// const initialMessages = getFromLocalStorage('chat-messages', []);
// // Convert the array to a writable store
// export const messages = writable(initialMessages);
// // Subscribe to messages store to watch for changes and save them to localStorage
// messages.subscribe(currentMessages => {
// setToLocalStorage('chat-messages', currentMessages);
// });
// export function createMessage(messageData) {
// const currentDate = new Date().toLocaleString();
// const newMessageObj = {
// text: messageData.text,
// timestamp: currentDate,
// sender: messageData.sender,
// type: messageData.type,
// composite: messageData.composite || null // New field
// };
// messages.update(oldMessages => [...oldMessages, newMessageObj]);
// }
// export function clearMessages() {
// messages.set([]);
// }
// // Dummy messages
// export const messagesList: Message[] = [
// { text: "Hello there!", timestamp: new Date().toLocaleString(), sender: "John", type: "text" },
// { text: "How are you?", timestamp: new Date().toLocaleString(), sender: "Alice", type: "text" },
// // Add more dummy messages here with the timestamp and sender properties
// ];

View File

@ -34,6 +34,22 @@ function getRecursiveServiceFiles(dir) {
return files;
}
function getRecursiveDataFiles(dir) {
const dirents = fs.readdirSync(dir, { withFileTypes: true });
const files = Array.from(dirents).flatMap((dirent) => {
const res = resolve(dir, dirent.name);
if (dirent.isDirectory()) {
return getRecursiveDataFiles(res);
} else if (res.endsWith('.ts')) {
return [res];
} else {
return [];
}
});
return files;
}
export default defineConfig({
plugins: [
sveltekit(),
@ -84,6 +100,30 @@ export default defineConfig({
}
return null;
}
},
{
name: 'data-sources-resolver',
resolveId(source) {
if (source === 'virtual:data-sources-list') return source;
return null;
},
load(id) {
if (id === 'virtual:data-sources-list') {
const dataDir = resolve(__dirname, 'src/lib/data');
const dataFiles = getRecursiveServiceFiles(dataDir); // Use the same function as before
const dataSources = dataFiles.map(file =>
file
.replace(dataDir, '')
.replace(/\.ts$/, '')
.replace(/\\/g, '/') // Fix Windows path separators
.slice(1) // Remove leading "/"
);
return `export default ${JSON.stringify(dataSources)};`;
}
return null;
}
}
],
test: {