feat(compiler): classify island routes as static-interactive

A route mounting an island ships JavaScript, so reporting it as zero-JS
static would make the framework's performance accounting wrong.

Adds a separate needsIslandRuntime flag rather than reusing
needsClientRuntime: an island needs the island runtime, not WRNexus's
reactive runtime, and conflating them would ship the wrong bundle.

analyzeRuntimeRequirements takes island presence as an optional second
argument, so existing callers are unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 15:30:19 +05:30
co-authored by Claude Opus 5
parent a184f1a3be
commit 01a3b3b4e9
2 changed files with 78 additions and 1 deletions
@@ -0,0 +1,56 @@
import { expect, test } from "bun:test";
import { parse } from "@wrnexus/syntax";
import { analyzeRuntimeRequirements, routeNeedsIslands } from "../src/analysis.ts";
test("a route with an island import needs client JavaScript", () => {
expect(
routeNeedsIslands([
{ declaration: { source: "./a" } as any, resolved: "/app/a.ts" },
{ declaration: { source: "./Chart" } as any, resolved: "/app/Chart.tsx", kind: "island" },
]),
).toBe(true);
});
test("a route with no island imports stays zero-JS", () => {
expect(routeNeedsIslands([{ declaration: { source: "./a" } as any, resolved: "/app/a.ts" }])).toBe(
false,
);
});
test("an empty import list stays zero-JS", () => {
expect(routeNeedsIslands([])).toBe(false);
});
test("an unresolved import does not count as an island", () => {
expect(
routeNeedsIslands([
{
declaration: { source: "./missing" } as any,
diagnostic: { code: "WRN-IMPORT-NOT-FOUND", message: "nope", severity: "warning" },
},
]),
).toBe(false);
});
test("an island promotes a static route to static-interactive", () => {
const source = `page Home { view { <div>hello</div> } }`;
const ast = parse(source);
const plain = analyzeRuntimeRequirements(ast);
expect(plain.kind).toBe("static");
expect(plain.needsIslandRuntime).toBe(false);
const withIsland = analyzeRuntimeRequirements(ast, { hasIslands: true });
expect(withIsland.kind).toBe("static-interactive");
expect(withIsland.needsIslandRuntime).toBe(true);
expect(withIsland.reasons).toContain("react island");
});
test("an island does not turn on the WRNexus reactive runtime", () => {
const ast = parse(`page Home { view { <div>hello</div> } }`);
const withIsland = analyzeRuntimeRequirements(ast, { hasIslands: true });
// Islands ship the island runtime, not WRNexus's own client runtime.
expect(withIsland.needsClientRuntime).toBe(false);
expect(withIsland.needsIslandRuntime).toBe(true);
});