diff --git a/packages/vike-solid/helpers/clientOnly.tsx b/packages/vike-solid/helpers/clientOnly.tsx index 63a5aa2..c282465 100644 --- a/packages/vike-solid/helpers/clientOnly.tsx +++ b/packages/vike-solid/helpers/clientOnly.tsx @@ -2,6 +2,7 @@ import { type Component, type ComponentProps, type JSX, + type Setter, createMemo, createSignal, onMount, @@ -16,22 +17,34 @@ import { isServer } from "solid-js/web"; * Load and render a component only on the client-side. * @see {@link https://vike.dev/clientOnly} */ -export function clientOnly>(fn: () => Promise<{ default: T } | T>) { +export function clientOnly>( + fn: () => Promise<{ default: T } | T>, + options: { lazy?: boolean } = {}, +) { if (isServer) return (props: ComponentProps & { fallback?: JSX.Element }) => <>{props.fallback}; const [comp, setComp] = createSignal(); - fn().then((m) => setComp(() => ("default" in m ? m.default : m))); + if (!options.lazy) { + load(fn, setComp); + } // eslint-disable-next-line solid/reactivity return (props: ComponentProps) => { let Comp: T | undefined; let m: boolean; const [, rest] = splitProps(props, ["fallback"]); + if (options.lazy) { + load(fn, setComp); + } if ((Comp = comp()) && !sharedConfig.context) return Comp(rest); const [mounted, setMounted] = createSignal(!sharedConfig.context); onMount(() => setMounted(true)); // eslint-disable-next-line solid/reactivity return createMemo( () => ((Comp = comp()), (m = mounted()), untrack(() => (Comp && m ? Comp(rest) : props.fallback))), - ); + ) as unknown as JSX.Element; }; } + +function load(fn: () => Promise<{ default: T } | T>, setComp: Setter) { + fn().then((m) => setComp(() => ("default" in (m as object) ? (m as any).default : m))); +}