Skip to content

ui/dashboard: migrate svelte 5 legacy mode to runes mode #977

@oskarszoon

Description

@oskarszoon

Background

PR #968 bumped ui/dashboard from Svelte v4 to Svelte v5 at the minimum-to-compile depth — closes 12 Dependabot alerts for the svelte/kit/devalue CVE cluster. To keep the diff surgical and security-driven, the migration uses Svelte 5's legacy/compat mode for every component. No runes-mode conversion was performed.

This issue tracks the deferred cleanup work so the deprecation warnings don't get lost in production console logs.

Scope

88 .svelte components under ui/dashboard/src/ still use Svelte 4 syntax in legacy mode:

Pattern Svelte 5 runes equivalent
export let foo let { foo } = $props()
$: derived = expr const derived = $derived(expr)
$: { sideEffect() } $effect(() => { sideEffect() })
on:click={fn} onclick={fn}
<slot /> / <slot name="x" /> {@render children?.()} / {@render x?.()}
$$slots, $$props, $$restProps $props() destructure
<svelte:component this={X}> Direct dynamic component (<X> works in v5)
Reactive store auto-subscribe ($store) Still works in v5; lower priority

Plus implicit removals:

  • createEventDispatcher → callback props
  • Component instantiation API changes (already required mount/hydrate in some entry points)

Why not now

  • Each pattern conversion touches semantics, not just syntax — a single bad migration can break interactivity in ways that don't surface at build time, only at runtime.
  • 88 components × ~5 syntax patterns = large diff with high regression risk.
  • No CVE pressure: legacy mode is supported through Svelte 5's lifetime and the security patches are already applied.

Acceptance

  • All components opt into runes mode (via <svelte:options runes={true}> or equivalent global compiler option).
  • No deprecation warnings emitted by svelte-check or in the runtime console.
  • Existing playwright integration tests pass.
  • Manual smoke pass on home, network, viewer, settings, p2p, admin routes.

Suggested phases

  1. Global compiler flag flip — turn on compilerOptions.runes: true in svelte.config.js, see how many files now warn or fail. Triage by depth.
  2. Leaf components first — props-only components with no reactive statements convert in 1-2 lines each.
  3. Stateful components$: to $derived / $effect, watch for side-effect ordering changes.
  4. Slots → snippets — biggest mechanical conversion, last because cross-component contract change.

Tooling: the sv migrate svelte-5 CLI helper is the canonical path (already available; was not used in #968 because it requires interactive consent and we wanted a small, mechanical diff).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    dependenciesPull requests that update a dependency file

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions