import { createApp, h, nextTick } from "vue"; import { bench, describe } from "vitest"; import * as next from "../src"; import * as base from "./.baseline"; import { component } from "./harness"; type Impl = typeof next; const all = { baseline: base as unknown as Impl, rewrite: next }; const impls = process.env.ONLY ? { [process.env.ONLY]: all[process.env.ONLY as keyof typeof all] } : all; const motion = next.defineOriginChoreography({ name: "bench", effects: ({ progress }) => ({ frame: { transform: `translateY(${progress}px)` }, source: { transform: `translateX(${-progress * 100}px)`, opacity: 1 - progress, }, target: { transform: `translateX(${(1 - progress) * 100}px)`, style: { filter: "none" }, }, }), }); /** Long enough for both implementations to reach steady-state JIT. */ const options = { time: 4000, warmupTime: 1500, warmupIterations: 2000 }; const views = Array.from({ length: 12 }, (_, i) => next.originView(component(`V${i}`), undefined, { key: `v${i}` }), ); /** A scene with `depth` simultaneously live, chained operations. */ async function liveChain(M: Impl, depth: number) { const scene = M.createOriginScene({ initial: views[0]! }); const handles: next.OriginOperationHandle[] = []; let origin = scene.nodes.value[0]!.key; for (let i = 1; i <= depth; i += 1) { const handle = await scene.begin(origin, M.forward(views[i]!, motion)); handle.update(0.5); handles.push(handle); origin = handle.targetKey; } return { scene, handles }; } for (const depth of [3, 10]) { describe(`styleForNode, every node, ${depth} live chained operations`, async () => { for (const [name, M] of Object.entries(impls)) { const { scene, handles } = await liveChain(M, depth); let p = 0; bench( name, () => { p = (p + 0.013) % 1; handles[0]!.update(p); for (const node of scene.nodes.value) scene.styleForNode(node.key); }, options, ); } }); } describe("push → back cycle (begin + finish, no animation)", () => { for (const [name, M] of Object.entries(impls)) { const scene = M.createOriginScene({ initial: views[0]! }); const root = scene.nodes.value[0]!.key; bench( name, async () => { const push = await scene.begin(root, M.forward(views[1]!, motion)); await push.finish({ commit: true, animate: false }); const pop = await scene.begin(push.targetKey, M.back(motion)); await pop.finish({ commit: true, animate: false }); }, options, ); } }); describe("rendered frame: update progress + Vue re-render, 6 live operations", async () => { for (const [name, M] of Object.entries(impls)) { const { scene, handles } = await liveChain(M, 6); const host = document.createElement("div"); document.body.append(host); createApp({ render: () => h(M.OriginScene, { scene }) }).mount(host); await nextTick(); let p = 0; bench( name, async () => { p = (p + 0.013) % 1; for (const handle of handles) handle.update(p); await nextTick(); }, options, ); } });