/// /// import { hydrate, mount } from 'svelte'; import type { Component } from 'svelte'; import { parse as devalueParse } from 'devalue'; import { isDev, logger } from 'mochi-framework'; import './IslandFailure'; import { islandFailureStub } from './islandFailureStub'; import { observeVisible } from './sharedVisibilityObserver'; import { isLoadedCss, markLoadedCss } from './sharedCssTracker'; const componentRegistry: Record = {}; export function registerComponent(name: string, component: Component) { componentRegistry[name] = component; } class HydratableIsland extends HTMLElement { _hydrated = false; connectedCallback() { const name = this.getAttribute('component-name'); const hydrateOn = this.getAttribute('hydrate-on'); logger.log('connectedCallback', { name, hydrateOn, attributes: [...this.attributes].map((a) => a.name + '=' + a.value), }); if (this._hydrated) { return; } if (hydrateOn === 'visible') { const optionsRaw = this.getAttribute('hydrate-options'); const options = optionsRaw ? JSON.parse(optionsRaw) : {}; // Observe firstElementChild because display:contents gives this element no layout box const target = this.firstElementChild || this; observeVisible(target, options.rootMargin || '0px', () => this._doHydrate()); } else { // Eager islands: load component JS immediately, then hydrate this._doHydrate(); } } async _doHydrate() { if (this._hydrated) { return; } this._hydrated = true; const name = this.getAttribute('component-name'); try { await this._doHydrateInner(name); } catch (err) { // Defensive belt — `transformError` on `hydrate()` covers errors raised // by the boundary; this catches synchronous throws from the bundle import, // CSS load, or `hydrate()` itself before the boundary takes effect. const e = err instanceof Error ? err : new Error(String(err)); logger.error(`Island "${name}" failed to hydrate:`, e); this.innerHTML = islandFailureStub(name ?? '', isDev ? e.message : undefined); } } async _doHydrateInner(name: string | null) { if (!name) { return; } // Page islands carry a `props-ref` pointing at a `