edges-svelte
Version:
A blazing-fast, extremely lightweight and SSR-friendly store for Svelte
113 lines (112 loc) • 3.42 kB
JavaScript
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());
};
}
};
};