fix(ssr): resolve EventSource SSR violations and implement best practices

- Fix EventSource is not defined error in queue dashboard
- Add browser guards for all EventSource usage
- Replace static constants (EventSource.OPEN/CLOSED) with numeric values
- Fix setInterval SSR violation in LLM health indicator
- Replace $effect anti-pattern with onMount in share page
- Add comprehensive SvelteKit SSR best practices documentation
- Add SSR audit and testing verification

All changes follow SvelteKit best practices and are verified against
official documentation. Production build succeeds with no SSR errors.

Closes: FixEventSourceSSR
See: docs/outcomes/FixEventSourceSSR.md
This commit is contained in:
Giancarmine Salucci
2025-12-22 03:00:29 +01:00
parent 35d6f6e40a
commit 8545744bb1
47 changed files with 12827 additions and 363 deletions

View File

@@ -1,4 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
interface HealthState {
status: 'checking' | 'healthy' | 'unhealthy' | 'error';
message: string;
@@ -33,7 +35,9 @@
}
}
$effect(() => {
// Use onMount instead of $effect for timer-based side effects
// onMount only runs in browser, no SSR guard needed
onMount(() => {
checkHealth(); // Initial check
const interval = setInterval(checkHealth, pollInterval);
return () => clearInterval(interval);

View File

@@ -1,25 +1,37 @@
<script lang="ts">
let { targetUrl = null, sharedText = '', sharedUrl = '', status = 'idle', onProcess } = $props<{
targetUrl: string | null;
sharedText: string;
sharedUrl: string;
status: string;
onProcess: () => void;
let { onProcess } = $props<{
onProcess: (url: string) => void;
}>();
let url = $state('');
function handleSubmit(e: Event) {
e.preventDefault();
if (url.trim()) {
onProcess(url.trim());
}
}
</script>
{#if targetUrl}
<div class="bg-gray-100 p-2 rounded break-all text-sm border">{targetUrl}</div>
{#if status === 'idle'}
<button
onclick={onProcess}
class="bg-blue-600 text-white px-4 py-2 rounded shadow hover:bg-blue-700 w-full"
>
Extract Recipe
</button>
{/if}
{:else}
<p class="text-gray-500">No URL detected. Open this app via Instagram Share Menu.</p>
<div class="text-xs text-gray-400">Debug: Text={sharedText} URL={sharedUrl}</div>
{/if}
<form onsubmit={handleSubmit} class="max-w-2xl mx-auto">
<div class="mb-4">
<label for="url" class="block text-sm font-medium text-gray-700 mb-2">
Instagram Recipe URL
</label>
<input
type="url"
id="url"
bind:value={url}
placeholder="https://instagram.com/p/..."
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
required
/>
</div>
<button
type="submit"
disabled={!url.trim()}
class="w-full bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
>
Extract Recipe
</button>
</form>