renderFlight

tcmts.cli.flight.renderFlight · #o7nn7cbk · term · runs on the server

uses node:url

Render server component fn with props as Flight does (useFlight loads both): its tree, streamed as it's ready (write, text). An error inside it goes to onError, whose answer is the error's digest, what the browser is told of it in production. Done when all of it is written, or signal aborts.

import type { Codebase } from "#codebase/tcmts/cli/codebase";
import { flightServerFile } from "#codebase/tcmts/cli/flight";
import { Writable } from "node:stream";
import { StringDecoder } from "node:string_decoder";
import { pathToFileURL } from "node:url";

export async function renderFlight(
  cb: Codebase,
  fn: (props: never) => unknown,
  props: unknown,
  opts: { write(text: string): void; onError(e: unknown): string | undefined; signal: AbortSignal },
): Promise<void> {
  const flight = (await import(pathToFileURL(flightServerFile(cb)).href)) as {
    createElement(type: unknown, props: unknown): unknown;
    renderToPipeableStream(
      model: unknown,
      options: { onError(e: unknown): string | undefined; environmentName: string },
    ): { pipe(to: Writable): void; abort(reason?: unknown): void };
  };
  const text = new StringDecoder("utf8");
  await new Promise<void>((done, fail) => {
    const sink = new Writable({
      write(chunk: Buffer, _e, next) {
        const t = text.write(chunk);
        if (t) opts.write(t);
        next();
      },
      final(next) {
        const t = text.end();
        if (t) opts.write(t);
        done();
        next();
      },
    });
    sink.on("error", fail);
    const stream = flight.renderToPipeableStream(flight.createElement(fn, props ?? {}), {
      onError: opts.onError,
      environmentName: "Server",
    });
    if (opts.signal.aborted) stream.abort(opts.signal.reason);
    else
      opts.signal.addEventListener("abort", () => stream.abort(opts.signal.reason), { once: true });
    stream.pipe(sink);
  });
}

uses

used by