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>
62 lines
2.4 KiB
TypeScript
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();
|
|
});
|