rvx
Version:
A signal based rendering library
62 lines (58 loc) • 1.78 kB
text/typescript
import { ASYNC, AsyncContext } from "../async/async-context.js";
import { Context } from "../core/context.js";
import { ENV } from "../core/env.js";
import { capture } from "../core/lifecycle.js";
import type { Component } from "../core/types.js";
import { render, View } from "../core/view.js";
import { Node, WINDOW } from "./model.js";
function renderDetachedView(view: View) {
const { first, last } = view;
if (!(first instanceof Node)) {
throw new Error("root is not an rvx dom node");
}
if (first === last) {
return first.outerHTML;
} else {
return first.parentNode!.outerHTML;
}
}
/**
* Render a component to HTML using rvx dom.
*/
export function renderToString(component: Component): string;
export function renderToString<P>(component: Component<P>, props: P): string;
export function renderToString<P>(component: Component<P>, props?: P): string {
let html: string;
capture(() => {
ENV.inject(WINDOW, () => {
const view = render(component(props!));
html = renderDetachedView(view);
});
})();
return html!;
}
/**
* Render a component to HTML using rvx dom.
*
* This injects a new {@link AsyncContext} to wait for rendering to complete.
*/
export async function renderToStringAsync(component: Component): Promise<string>;
export async function renderToStringAsync<P>(component: Component<P>, props: P): Promise<string>;
export async function renderToStringAsync<P>(component: Component<P>, props?: P): Promise<string> {
const asyncCtx = new AsyncContext();
let view: View;
const dispose = capture(() => {
Context.inject([
ENV.with(WINDOW),
ASYNC.with(asyncCtx),
], () => {
view = render(component(props!));
});
});
try {
await asyncCtx.complete();
return renderDetachedView(view!);
} finally {
dispose();
}
}