UNPKG

edges-svelte

Version:

A blazing-fast, extremely lightweight and SSR-friendly store for Svelte

113 lines (112 loc) 3.42 kB
import RequestContext from '../context/Context.js'; import { uneval } from 'devalue'; import { browser } from '$app/environment'; import { derived, writable } from 'svelte/store'; const RequestStores = new WeakMap(); export const stateSerialize = () => { const map = getRequestContext(); if (map) { const entries = Array.from(map).map(([key, value]) => [uneval(key), uneval(value)]); return `<script> window.__SAFE_SSR_STATE__ = new Map(); ${entries.map(([key, value]) => `window.__SAFE_SSR_STATE__.set(${key}, ${value})`).join(';')} </script>`; } return ''; }; const getRequestContext = () => { const sym = RequestContext.current().symbol; if (sym) { return RequestStores.get(sym) ?? RequestStores.set(sym, new Map()).get(sym); } }; const getBrowserState = (key, initial) => { const state = window.__SAFE_SSR_STATE__?.get(key); if (state) return state; return initial; }; export const createRawState = (key, initial) => { if (browser) { let state = $state(getBrowserState(key, initial())); return { get value() { return state; }, set value(val) { state = val; } }; } const map = getRequestContext(); return { get value() { if (!map) return initial(); if (!map.has(key)) map.set(key, structuredClone(initial())); return map.get(key); }, set value(val) { if (map) { map.set(key, val); } } }; }; export const createState = (key, initial) => { if (browser) { return writable(getBrowserState(key, initial())); } const map = getRequestContext(); if (!map) throw new Error('No RequestContext available'); if (!map.has(key)) map.set(key, structuredClone(initial())); //const subscribers: Set<(val: T) => void> = new Set(); return { subscribe(run) { run(map.get(key)); //subscribers.add(run); return () => { }; }, set(val) { map.set(key, val); //subscribers.forEach((fn) => fn(val)); }, update(updater) { const oldVal = map.get(key); const newVal = updater(oldVal); map.set(key, newVal); //subscribers.forEach((fn) => fn(newVal)); } }; }; export const createDerivedState = (stores, deriveFn) => { if (browser) { return derived(stores, deriveFn); } return { subscribe(run) { const values = new Array(stores.length); let initializedCount = 0; let isInitialized = false; const checkAndRun = () => { if (initializedCount >= stores.length && !isInitialized) { isInitialized = true; run(deriveFn(values)); } }; const unsubscribers = stores.map((store, i) => store.subscribe((value) => { values[i] = value; if (initializedCount < stores.length) { initializedCount++; } checkAndRun(); })); return () => { unsubscribers.forEach((unsub) => unsub()); }; } }; };