testLazyChunksLoadWithThePage

tcmts.cli.test.e2e.react.testLazyChunksLoadWithThePage · #calgz3sz · term

A lazy component's code (what only its import() reaches) is split out of the page's chunks, into chunks of its own, and a page whose server component renders it starts loading them with its HTML: server rendering puts them in the page, as React's Flight says.

import { CHROME, hydrated, withPage } from "#codebase/tcmts/cli/test/browser";
import { okIn, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness";
import { serve } from "#codebase/tcmts/cli/test/e2e/react";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";

export const testLazyChunksLoadWithThePage = async () => {
  await withChildren(async (keep) => {
    const dir = tempDir("react lazy");
    const tcm = (...args: string[]) => okIn(dir, ...args);
    tcm("init");
    fs.rmSync(path.join(dir, "scratch.ts"));
    fs.writeFileSync(
      path.join(dir, "lz.tsx"),
      `// tcm: namespace lz
import { lazy, Suspense } from "react";

export const Ago = lazy(async () => {
  const { default: ms } = await import("ms");
  return { default: ({ t }: { t: number }) => <b id="ago">{ms(t, { long: true })}</b> };
});

export async function Report() {
  return <section><Suspense fallback={<i>loading</i>}><Ago t={60000} /></Suspense></section>;
}

export function App() {
  return <main><Report /></main>;
}
`,
    );
    tcm("add", "lz.tsx");
    tcm("build", "lz.App");
    const url = await serve(keep, dir, "start", "lz.App");
    const html = await (await fetch(url, { headers: { accept: "text/html" } })).text();
    assert.match(html, /1 minute/, "rendered on the server");
    // the page's own chunks, and what else it loads: the lazy one's
    const own = new Set(
      [
        ...html.matchAll(
          /<link rel="modulepreload"[^>]*href="([^"]+)"|<script type="module"[^>]*src="([^"]+)"/g,
        ),
      ].map((m) => m[1] ?? m[2]),
    );
    const loaded = [...html.matchAll(/<script[^>]*src="([^"]+)"/g)]
      .map((m) => m[1]!)
      .filter((s) => !own.has(s));
    assert.equal(loaded.length, 1, html.slice(0, 1500));
    const chunk = await (await fetch(new URL(loaded[0]!, url))).text();
    assert.match(chunk, /minute/, "the chunk has ms in it");
    // (none of the page's own has ms's words, however the minifier quotes them)
    assert.ok(own.size > 0, html.slice(0, 1500));
    for (const s of own)
      assert.doesNotMatch(await (await fetch(new URL(s, url))).text(), /minute/, `${s} doesn't`);
    if (!CHROME) return console.log("skipped the browser: no Chrome");
    await withPage(url, async (p) => {
      assert.ok(await hydrated(p));
      assert.equal(
        await p.waitFor<string>(
          `document.querySelector("#ago")?.textContent ?? ""`,
          (t) => t === "1 minute",
        ),
        "1 minute",
      );
      assert.deepEqual(p.errors, []);
    });
  });
}

uses