Skip to content

Commit a7050d5

Browse files
authored
Merge pull request #227 from pathsim/fix/performance-and-memory-issues
Fix/performance and memory issues
2 parents 034f2b0 + 45fb321 commit a7050d5

8 files changed

Lines changed: 52 additions & 13 deletions

src/lib/components/ResizablePanel.svelte

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { onDestroy } from 'svelte';
23
import { fly } from 'svelte/transition';
34
import { cubicOut } from 'svelte/easing';
45
import { untrack } from 'svelte';
@@ -115,6 +116,9 @@
115116
}
116117
});
117118
119+
// Track active resize cleanup for component destroy
120+
let activeCleanup: (() => void) | null = null;
121+
118122
function startResize(edge: 'left' | 'right' | 'top' | 'bottom') {
119123
return (event: MouseEvent) => {
120124
event.preventDefault();
@@ -146,19 +150,29 @@
146150
}
147151
}
148152
149-
function onMouseUp() {
150-
isResizing = false;
151-
resizeEdge = null;
153+
function cleanup() {
152154
document.removeEventListener('mousemove', onMouseMove);
153155
document.removeEventListener('mouseup', onMouseUp);
154156
document.body.classList.remove('resizing-ew', 'resizing-ns');
157+
activeCleanup = null;
155158
}
156159
160+
function onMouseUp() {
161+
isResizing = false;
162+
resizeEdge = null;
163+
cleanup();
164+
}
165+
166+
activeCleanup = cleanup;
157167
document.addEventListener('mousemove', onMouseMove);
158168
document.addEventListener('mouseup', onMouseUp);
159169
document.body.classList.add((edge === 'left' || edge === 'right') ? 'resizing-ew' : 'resizing-ns');
160170
};
161171
}
172+
173+
onDestroy(() => {
174+
activeCleanup?.();
175+
});
162176
</script>
163177

164178
<!-- svelte-ignore a11y_no_static_element_interactions, a11y_no_noninteractive_element_interactions -->

src/lib/components/dialogs/BlockPropertiesDialog.svelte

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { onDestroy } from 'svelte';
23
import { fade, scale } from 'svelte/transition';
34
import { cubicOut } from 'svelte/easing';
45
import { graphStore } from '$lib/stores/graph';
@@ -24,7 +25,7 @@
2425
let nodeId = $state<string | null>(null);
2526
let node = $state<NodeInstance | null>(null);
2627
27-
nodeDialogStore.subscribe((id) => {
28+
const unsubscribeDialog = nodeDialogStore.subscribe((id) => {
2829
nodeId = id;
2930
if (id) {
3031
node = graphStore.getNode(id) || null;
@@ -34,12 +35,17 @@
3435
});
3536
3637
// Keep node updated when params change
37-
graphStore.nodesArray.subscribe((nodes) => {
38+
const unsubscribeNodes = graphStore.nodesArray.subscribe((nodes) => {
3839
if (nodeId) {
3940
node = nodes.find(n => n.id === nodeId) || null;
4041
}
4142
});
4243
44+
onDestroy(() => {
45+
unsubscribeDialog();
46+
unsubscribeNodes();
47+
});
48+
4349
// Get type definition
4450
const typeDef = $derived(node ? nodeRegistry.get(node.type) : null);
4551

src/lib/components/dialogs/CodePreviewDialog.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
let copied = $state(false);
2525
2626
// Subscribe to theme changes
27-
themeStore.subscribe((theme) => {
27+
const unsubscribeTheme = themeStore.subscribe((theme) => {
2828
currentTheme = theme;
2929
if (editorView && cmModules && editorContainer) {
3030
recreateEditor();
@@ -115,6 +115,7 @@
115115
}
116116
117117
onDestroy(() => {
118+
unsubscribeTheme();
118119
destroyEditor();
119120
});
120121
</script>

src/lib/components/dialogs/EventPropertiesDialog.svelte

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { onDestroy } from 'svelte';
23
import { fade, scale } from 'svelte/transition';
34
import { cubicOut } from 'svelte/easing';
45
import { get } from 'svelte/store';
@@ -22,7 +23,7 @@
2223
let eventId = $state<string | null>(null);
2324
let event = $state<EventInstance | null>(null);
2425
25-
eventDialogStore.subscribe((id) => {
26+
const unsubscribeDialog = eventDialogStore.subscribe((id) => {
2627
eventId = id;
2728
if (id) {
2829
event = eventStore.getEvent(id) || null;
@@ -32,12 +33,17 @@
3233
});
3334
3435
// Keep event updated when params change
35-
eventStore.eventsArray.subscribe((events) => {
36+
const unsubscribeEvents = eventStore.eventsArray.subscribe((events) => {
3637
if (eventId) {
3738
event = events.find(e => e.id === eventId) || null;
3839
}
3940
});
4041
42+
onDestroy(() => {
43+
unsubscribeDialog();
44+
unsubscribeEvents();
45+
});
46+
4147
// Get type definition
4248
const typeDef = $derived(event ? eventRegistry.get(event.type) : null);
4349

src/lib/components/dialogs/ExportDialog.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
let currentTheme = $state<Theme>('dark');
2828
2929
// Subscribe to theme changes
30-
themeStore.subscribe((theme) => {
30+
const unsubscribeTheme = themeStore.subscribe((theme) => {
3131
currentTheme = theme;
3232
if (editorView && cmModules && editorContainer) {
3333
recreateEditor();
@@ -125,6 +125,7 @@
125125
}
126126
127127
onDestroy(() => {
128+
unsubscribeTheme();
128129
destroyEditor();
129130
});
130131
</script>

src/lib/components/dialogs/PlotOptionsDialog.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { onDestroy } from 'svelte';
23
import { fade, scale } from 'svelte/transition';
34
import { cubicOut } from 'svelte/easing';
45
import Icon from '$lib/components/icons/Icon.svelte';
@@ -37,6 +38,10 @@
3738
settings = s;
3839
});
3940
41+
onDestroy(() => {
42+
unsubscribe();
43+
});
44+
4045
function handleKeydown(event: KeyboardEvent) {
4146
if (event.key === 'Escape') {
4247
onClose();

src/lib/components/dialogs/SearchDialog.svelte

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { onDestroy } from 'svelte';
23
import { fade, scale } from 'svelte/transition';
34
import { cubicOut } from 'svelte/easing';
45
import { graphStore, type SearchableNode } from '$lib/stores/graph';
@@ -21,10 +22,14 @@
2122
let currentPath = $state<string[]>([]);
2223
2324
// Subscribe to current path for prioritizing current view
24-
graphStore.currentPath.subscribe((path) => {
25+
const unsubscribePath = graphStore.currentPath.subscribe((path) => {
2526
currentPath = path;
2627
});
2728
29+
onDestroy(() => {
30+
unsubscribePath();
31+
});
32+
2833
// Refresh node list when dialog opens
2934
$effect(() => {
3035
if (open) {

src/routes/+page.svelte

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -705,19 +705,20 @@
705705
// Prevent concurrent simulation runs (synchronous check for rapid key presses)
706706
if (simRunning || isRunStarting || pyodideLoading) return;
707707
708+
// Set flag before any async operations to prevent race conditions
709+
isRunStarting = true;
710+
708711
// Auto-initialize if not ready
709712
if (!pyodideReady) {
710713
try {
711714
await initPyodide();
712715
} catch (error) {
713716
console.error('Failed to initialize Pyodide:', error);
717+
isRunStarting = false;
714718
return;
715719
}
716720
}
717721
718-
// Set flag synchronously to prevent race conditions during validation
719-
isRunStarting = true;
720-
721722
try {
722723
// Run simulation
723724
const { nodes, connections } = graphStore.toJSON();

0 commit comments

Comments
 (0)