Files
WRNexusJS/packages/compiler/test/island-bundle.test.ts
T
ClintchizandClaude Opus 5 06df9d66ae feat(compiler): bundle islands with a shared React chunk
splitting:true keeps React in one shared chunk so a page with several
islands does not ship react-dom repeatedly.

Island .tsx is compiled against React's JSX runtime via a Bun onLoad
plugin. The repo's root tsconfig sets jsxImportSource to @wrnexus/core,
so islands would otherwise compile to the HTML-string renderer and never
mount. A @jsxImportSource pragma only affects the file carrying it, so
injecting one into the generated entry is not enough — the injection has
to happen per source file. App-authored islands stay plain .tsx.

The JSX test asserts built output rather than generated entry text,
because the entry-text assertion passed while the mechanism did not work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:22:58 +05:30

62 lines
2.4 KiB
TypeScript

import { afterAll, expect, test } from "bun:test";
import { mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { assertReactAvailable, buildIslands, generateIslandEntry } from "../src/island-bundle.ts";
const created: string[] = [];
afterAll(() => {
for (const dir of created) rmSync(dir, { recursive: true, force: true });
});
test("generates an entry that re-exports the island component", () => {
const entry = generateIslandEntry({ name: "Chart", sourcePath: "/app/Chart.tsx" });
expect(entry).toContain("/app/Chart.tsx");
expect(entry).toContain("Chart");
expect(entry).not.toContain("react-dom/server");
});
test("island .tsx compiles against React's JSX runtime, not WRNexus's", async () => {
// The root tsconfig points jsxImportSource at @wrnexus/core, so an island
// would otherwise compile to WRNexus's HTML-string renderer and never mount.
// A pragma applies only to the file carrying it, so this asserts the built
// output rather than the generated entry text.
// The fixture must live inside the repo: Bun resolves `react` from the
// importing file's location, exactly as a real island resolves it from the
// app that installed react.
const root = mkdtempSync(join(process.cwd(), ".island-jsx-test-"));
created.push(root);
const source = join(root, "Chart.tsx");
writeFileSync(
source,
`export default function Chart({ title }: { title: string }) {
return <div className="chart">{title}</div>;
}`,
);
const outDir = join(root, "out");
await buildIslands({ islands: [{ name: "Chart", sourcePath: source }], outDir });
const built = readdirSync(outDir)
.filter((file) => file.endsWith(".js"))
.map((file) => readFileSync(join(outDir, file), "utf8"))
.join("\n");
expect(built).not.toContain("wrnexus");
expect(built).toMatch(/react\/jsx|jsxDEV|jsx_runtime/);
});
test("reports WRN-ISLAND-REACT-MISSING when react is not installed", () => {
const root = mkdtempSync(join(tmpdir(), "wrnexus-noreact-"));
writeFileSync(join(root, "package.json"), JSON.stringify({ name: "app" }));
const diagnostic = assertReactAvailable(root);
expect(diagnostic?.code).toBe("WRN-ISLAND-REACT-MISSING");
expect(diagnostic?.message).toContain("bun add react react-dom");
});
test("returns null when react resolves", () => {
expect(assertReactAvailable(process.cwd())).toBeNull();
});