import { render as renderCommon, RenderOptions } from './render'; import { bootstrap as bootstrapCommon, Importer } from './bootstrap'; import { state } from './state'; import { isInNode } from './is-in-node'; import { type Component, type JSXElement } from 'solid-js'; import type Solid from 'solid-js'; let renderFn: (element: () => JSXElement) => void; const assertAndRender = (element: () => JSXElement) => { if (!renderFn) { throw new Error( 'App is not bootstrapped, did you forget to call `bootstrap({ /* ... */ })`?' ); } return renderFn(element); }; export async function render( elementToRender: (app: JSXElement) => JSXElement = state.browserState ?.renderElement.value, options: RenderOptions = {} ) { let functionToRender: () => JSXElement = () => null; if (!isInNode) { functionToRender = () => elementToRender(state.browserState?.renderElement.value); } return renderCommon( { __isRenderable: true, thing: functionToRender }, options, async (e) => { const rendered = assertAndRender(e.thing); await new Promise((r) => setTimeout(r, 0)); return rendered; } ); } type BootstrapArgs = Importer & { element: () => JSXElement; render: (e: () => JSXElement) => void; }; export const bootstrap = async (args: BootstrapArgs): Promise => { renderFn = args.render; state.browserState = { retryAttempt: 0, renderElement: { __type: 'renderElement', value: args.element }, }; return bootstrapCommon({ ...args, defaultRender: () => { return assertAndRender(args.element); }, }); }; export const Bootstrap: Component< { children: JSXElement; /** * Due to Solid singleton expectations, we need to pass the Solid namespace to Bootstrap * * ```tsx * import { * createSignal, * createMemo, * createRenderEffect * } from 'solid-js'; * * // ... * * ; /** Note that using this in SSR mode this will cause the page to start with the loading component before the page is ready. */ loading?: JSXElement; } & Importer > = (props) => { const Solid = props.Solid; const initial = () => props.loading ?? props.children; const [child, setChild] = Solid.createSignal(initial); Solid.createRenderEffect(() => { bootstrap({ ...props, element: () => props.children, render: (element) => setChild(() => element), }); }); return Solid.createMemo( () => child() ?? props.children ) as unknown as JSXElement; };