diff options
| author | Adam <[email protected]> | 2026-01-07 08:41:16 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-01-08 17:48:15 -0600 |
| commit | 374275eeb691006fa8f422d6267aa694ab38a992 (patch) | |
| tree | 9159db2dabb0ba2e10e82b7efb3cd4fbabf024d0 /packages/app/src/utils | |
| parent | faa848cfb13df4e435dc236fe895032ea6f26dde (diff) | |
| download | opencode-374275eeb691006fa8f422d6267aa694ab38a992.tar.gz opencode-374275eeb691006fa8f422d6267aa694ab38a992.zip | |
feat(app): chunk message loading, lazy load diffs
Diffstat (limited to 'packages/app/src/utils')
| -rw-r--r-- | packages/app/src/utils/perf.ts | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/packages/app/src/utils/perf.ts b/packages/app/src/utils/perf.ts new file mode 100644 index 000000000..0ecbc33ff --- /dev/null +++ b/packages/app/src/utils/perf.ts @@ -0,0 +1,135 @@ +type Nav = { + id: string + dir?: string + from?: string + to: string + trigger?: string + start: number + marks: Record<string, number> + logged: boolean + timer?: ReturnType<typeof setTimeout> +} + +const dev = import.meta.env.DEV + +const key = (dir: string | undefined, to: string) => `${dir ?? ""}:${to}` + +const now = () => performance.now() + +const uid = () => crypto.randomUUID?.() ?? Math.random().toString(16).slice(2) + +const navs = new Map<string, Nav>() +const pending = new Map<string, string>() +const active = new Map<string, string>() + +const required = [ + "session:params", + "session:data-ready", + "session:first-turn-mounted", + "storage:prompt-ready", + "storage:terminal-ready", + "storage:file-view-ready", +] + +function flush(id: string, reason: "complete" | "timeout") { + if (!dev) return + const nav = navs.get(id) + if (!nav) return + if (nav.logged) return + + nav.logged = true + if (nav.timer) clearTimeout(nav.timer) + + const baseName = nav.marks["navigate:start"] !== undefined ? "navigate:start" : "session:params" + const base = nav.marks[baseName] ?? nav.start + + const ms = Object.fromEntries( + Object.entries(nav.marks) + .slice() + .sort(([a], [b]) => a.localeCompare(b)) + .map(([name, t]) => [name, Math.round((t - base) * 100) / 100]), + ) + + console.log( + "perf.session-nav " + + JSON.stringify({ + type: "perf.session-nav.v0", + id: nav.id, + dir: nav.dir, + from: nav.from, + to: nav.to, + trigger: nav.trigger, + base: baseName, + reason, + ms, + }), + ) + + navs.delete(id) +} + +function maybeFlush(id: string) { + if (!dev) return + const nav = navs.get(id) + if (!nav) return + if (nav.logged) return + if (!required.every((name) => nav.marks[name] !== undefined)) return + flush(id, "complete") +} + +function ensure(id: string, data: Omit<Nav, "marks" | "logged" | "timer">) { + const existing = navs.get(id) + if (existing) return existing + + const nav: Nav = { + ...data, + marks: {}, + logged: false, + } + nav.timer = setTimeout(() => flush(id, "timeout"), 5000) + navs.set(id, nav) + return nav +} + +export function navStart(input: { dir?: string; from?: string; to: string; trigger?: string }) { + if (!dev) return + + const id = uid() + const start = now() + const nav = ensure(id, { ...input, id, start }) + nav.marks["navigate:start"] = start + + pending.set(key(input.dir, input.to), id) + return id +} + +export function navParams(input: { dir?: string; from?: string; to: string }) { + if (!dev) return + + const k = key(input.dir, input.to) + const pendingId = pending.get(k) + if (pendingId) pending.delete(k) + const id = pendingId ?? uid() + + const start = now() + const nav = ensure(id, { ...input, id, start, trigger: pendingId ? "key" : "route" }) + nav.marks["session:params"] = start + + active.set(k, id) + maybeFlush(id) + return id +} + +export function navMark(input: { dir?: string; to: string; name: string }) { + if (!dev) return + + const id = active.get(key(input.dir, input.to)) + if (!id) return + + const nav = navs.get(id) + if (!nav) return + if (nav.marks[input.name] !== undefined) return + + nav.marks[input.name] = now() + maybeFlush(id) +} |
