release: WRNexusJS 0.5.0

This commit is contained in:
2026-07-29 12:51:10 +05:30
parent 76c768099d
commit 6afe32f63f
456 changed files with 40879 additions and 8850 deletions
+8
View File
@@ -8,3 +8,11 @@ test("HMR client syncs fresh HTML over the websocket", () => {
expect(HMR_CLIENT_JS).not.toContain("fetch(location.href");
expect(HMR_CLIENT_JS).not.toContain("location.reload()");
});
test("HMR replaces hydrated components when their server signature changes", () => {
expect(HMR_CLIENT_JS).toContain('from.getAttribute("data-wrn-hydration")');
expect(HMR_CLIENT_JS).toContain('from.getAttribute("data-wrn-behavior")');
expect(HMR_CLIENT_JS).toContain('from.getAttribute("data-scope")');
expect(HMR_CLIENT_JS).toContain("window.__wrnexusDisposeBehaviors(from)");
expect(HMR_CLIENT_JS).toContain("from.replaceWith(to.cloneNode(true))");
});
@@ -0,0 +1,82 @@
import { afterAll, expect, test } from "bun:test";
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
import { get } from "node:http";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { definePlugin } from "@wrnexus/plugin";
import { startServer } from "../src/index.ts";
const root = mkdtempSync(join(tmpdir(), "wrnexus-plugin-config-"));
const appDir = join(root, "app");
const routeFile = join(root, "config-probe.ts");
const runtimeKey = `@wrnexus/dev-server:test:plugin-config:${crypto.randomUUID()}`;
mkdirSync(appDir, { recursive: true });
writeFileSync(join(root, "package.json"), JSON.stringify({ name: "plugin-config-lifecycle-test" }));
writeFileSync(
routeFile,
`
export function GET() {
return Response.json({
value: globalThis[Symbol.for(${JSON.stringify(runtimeKey)})],
});
}
`,
);
afterAll(() => {
delete (globalThis as Record<PropertyKey, unknown>)[Symbol.for(runtimeKey)];
rmSync(root, { recursive: true, force: true });
});
function getJson(url: string): Promise<{ status: number | undefined; body: unknown }> {
return new Promise((resolve, reject) => {
const request = get(url, (response) => {
const chunks: Buffer[] = [];
response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
response.on("end", () => {
try {
resolve({
status: response.statusCode,
body: JSON.parse(Buffer.concat(chunks).toString("utf8")),
});
} catch (error) {
reject(error);
}
});
});
request.on("error", reject);
});
}
test("startServer configures plugins once with the complete application config", async () => {
let configureCalls = 0;
const plugin = definePlugin({
name: "plugin-config-lifecycle-test",
configure(config) {
configureCalls += 1;
(globalThis as Record<PropertyKey, unknown>)[Symbol.for(runtimeKey)] =
config.lifecycleSentinel;
},
routeEntries: [{ kind: "api", path: "/api/config-probe", entry: routeFile }],
});
const server = await startServer({
appDir,
appConfig: { lifecycleSentinel: "configured" },
plugins: plugin,
hostname: "127.0.0.1",
port: 0,
mode: "development",
hmr: false,
});
try {
const response = await getJson(`${server.url}/api/config-probe`);
expect(response.status).toBe(200);
expect(response.body).toEqual({ value: "configured" });
expect(configureCalls).toBe(1);
} finally {
server.stop();
}
});
@@ -0,0 +1,23 @@
import { expect, test } from "bun:test";
import { createDevAssetServer } from "../src/assets.ts";
test("UI CSS is read from its live source after an HMR change", async () => {
let css = ".wire-card { color: red; }";
const assets = createDevAssetServer(
process.cwd(),
"development",
undefined,
undefined,
() => css,
);
const first = await assets.serve("/__wrnexus/ui.css");
expect(await first?.text()).toContain("color: red");
css = ".wire-card { color: blue; }";
assets.invalidateCss();
const second = await assets.serve("/__wrnexus/ui.css");
expect(await second?.text()).toContain("color: blue");
expect(second?.headers.get("cache-control")).toBe("no-cache");
});