feat: add Value.Equal bail-out check before reconciliation

Add TypeBox Value.Equal deep-comparison as first optimization layer
in reconcileProps. When a fiber's cached node is deep-equal to the
next node, skip prepareUpdate, commitUpdate, and children
reconciliation entirely. New cachedNode field on Fiber stores the
last reconciled node for comparison.
This commit is contained in:
2026-05-18 17:25:02 +00:00
parent 1e0abb0900
commit 23db3775ad
8 changed files with 283 additions and 41 deletions

View File

@@ -1,6 +1,15 @@
import { describe, it, expect, expectTypeOf } from "vitest";
import type { Fiber, Effect } from "../src/host/fiber.js";
const baseFiber: Omit<Fiber<string>, "instance" | "tag" | "props" | "key"> = {
children: [],
parent: null,
effect: null,
signalDisposers: [],
prevProps: null,
cachedNode: null,
};
describe("Fiber<I> interface", () => {
it("has all required fields", () => {
const fiber: Fiber<string> = {
@@ -8,11 +17,7 @@ describe("Fiber<I> interface", () => {
tag: "div",
props: { class: "test" },
key: "a",
children: [],
parent: null,
effect: null,
signalDisposers: [],
prevProps: null,
...baseFiber,
};
expect(fiber.instance).toBe("inst-1");
expect(fiber.tag).toBe("div");
@@ -23,6 +28,7 @@ describe("Fiber<I> interface", () => {
expect(fiber.effect).toBeNull();
expect(fiber.signalDisposers).toEqual([]);
expect(fiber.prevProps).toBeNull();
expect(fiber.cachedNode).toBeNull();
});
it("supports key as undefined", () => {
@@ -31,11 +37,7 @@ describe("Fiber<I> interface", () => {
tag: "span",
props: {},
key: undefined,
children: [],
parent: null,
effect: null,
signalDisposers: [],
prevProps: null,
...baseFiber,
};
expect(fiber.key).toBeUndefined();
});
@@ -46,22 +48,15 @@ describe("Fiber<I> interface", () => {
tag: "div",
props: {},
key: undefined,
children: [],
parent: null,
effect: null,
signalDisposers: [],
prevProps: null,
...baseFiber,
};
const child: Fiber<string> = {
instance: "child-inst",
tag: "span",
props: {},
key: "child-1",
children: [],
...baseFiber,
parent,
effect: null,
signalDisposers: [],
prevProps: null,
};
parent.children.push(child);
expect(child.parent).toBe(parent);
@@ -75,11 +70,8 @@ describe("Fiber<I> interface", () => {
tag: "div",
props: {},
key: undefined,
children: [],
parent: null,
effect: null,
...baseFiber,
signalDisposers: [() => disposed.push("a"), () => disposed.push("b")],
prevProps: null,
};
fiber.signalDisposers.forEach((d) => d());
expect(disposed).toEqual(["a", "b"]);
@@ -104,11 +96,7 @@ describe("Effect<I> union type", () => {
tag: "span",
props: {},
key: undefined,
children: [],
parent: null,
effect: null,
signalDisposers: [],
prevProps: null,
...baseFiber,
};
const effect: Effect<string> = { type: "insert", before };
expect(effect.type).toBe("insert");
@@ -121,11 +109,7 @@ describe("Effect<I> union type", () => {
tag: "span",
props: {},
key: undefined,
children: [],
parent: null,
effect: null,
signalDisposers: [],
prevProps: null,
...baseFiber,
};
const effect: Effect<string> = { type: "move", before };
expect(effect.type).toBe("move");
@@ -148,10 +132,8 @@ describe("Effect<I> union type", () => {
tag: "div",
props: {},
key: undefined,
children: [],
parent: null,
...baseFiber,
effect: { type: "update", payload: "x" },
signalDisposers: [],
prevProps: {},
};
expect(fiber.effect!.type).toBe("update");
@@ -179,11 +161,7 @@ describe("Fiber re-export from barrel", () => {
tag: "div",
props: {},
key: undefined,
children: [],
parent: null,
effect: null,
signalDisposers: [],
prevProps: null,
...baseFiber,
};
const _effect: _EffectCheck = { type: "remove" };
expect(_fiber.instance).toBe("inst");