Make workspace tab switching faster (#1251)
* Avoid workspace shell renders when toggling sidebar * Avoid rerendering inactive workspace screens * Avoid rerendering unchanged sidebar rows * Keep sidebar selection state in the list * Speed up workspace tab switching
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { chromium } from "playwright";
|
||||
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");
|
||||
|
||||
const baseUrl = process.env.PASEO_PROFILE_APP_URL ?? "http://localhost:19010";
|
||||
const serverId = requiredEnv("PASEO_PROFILE_SERVER_ID");
|
||||
const workspaceId = requiredEnv("PASEO_PROFILE_WORKSPACE_ID");
|
||||
const agentId = requiredEnv("PASEO_PROFILE_AGENT_ID");
|
||||
const switchCount = Number(process.env.PASEO_PROFILE_SWITCH_COUNT ?? 6);
|
||||
const switchWaitMs = Number(process.env.PASEO_PROFILE_SWITCH_WAIT_MS ?? 250);
|
||||
const idleWaitMs = Number(process.env.PASEO_PROFILE_IDLE_WAIT_MS ?? 0);
|
||||
const dumpCommits = process.env.PASEO_PROFILE_DUMP_COMMITS === "1";
|
||||
|
||||
function requiredEnv(name) {
|
||||
const value = process.env[name]?.trim();
|
||||
if (!value) {
|
||||
throw new Error(`${name} is required`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function createTerminal() {
|
||||
const output = execFileSync(
|
||||
"npm",
|
||||
[
|
||||
"run",
|
||||
"cli",
|
||||
"--",
|
||||
"terminal",
|
||||
"create",
|
||||
"--cwd",
|
||||
workspaceId,
|
||||
"--name",
|
||||
"Tab Switch Profile",
|
||||
"--json",
|
||||
],
|
||||
{ cwd: repoRoot, encoding: "utf8" },
|
||||
);
|
||||
const match = output.match(/\{[\s\S]*\}/);
|
||||
if (!match) {
|
||||
throw new Error(`Could not parse terminal create output: ${output}`);
|
||||
}
|
||||
return JSON.parse(match[0]).id;
|
||||
}
|
||||
|
||||
function killTerminal(terminalId) {
|
||||
execFileSync("npm", ["run", "cli", "--", "terminal", "kill", terminalId], {
|
||||
cwd: repoRoot,
|
||||
encoding: "utf8",
|
||||
});
|
||||
}
|
||||
|
||||
const createdTerminalId = process.env.PASEO_PROFILE_TERMINAL_ID ? null : createTerminal();
|
||||
const terminalId = process.env.PASEO_PROFILE_TERMINAL_ID ?? createdTerminalId;
|
||||
const workspaceSegment = `b64_${Buffer.from(workspaceId, "utf8").toString("base64url")}`;
|
||||
const workspaceUrl = `${baseUrl}/h/${serverId}/workspace/${workspaceSegment}`;
|
||||
|
||||
function tabTestId(kind, id) {
|
||||
return `workspace-tab-${kind}_${id}`;
|
||||
}
|
||||
|
||||
function summarize(samples) {
|
||||
const byId = new Map();
|
||||
for (const sample of samples) {
|
||||
const current = byId.get(sample.id) ?? {
|
||||
renders: 0,
|
||||
actualDuration: 0,
|
||||
baseDuration: 0,
|
||||
};
|
||||
current.renders += 1;
|
||||
current.actualDuration += sample.actualDuration;
|
||||
current.baseDuration += sample.baseDuration;
|
||||
byId.set(sample.id, current);
|
||||
}
|
||||
return [...byId.entries()]
|
||||
.map(([id, value]) => Object.assign({ id }, value))
|
||||
.sort((left, right) => right.actualDuration - left.actualDuration);
|
||||
}
|
||||
|
||||
function summarizeCommits(samples) {
|
||||
const byCommit = new Map();
|
||||
for (const sample of samples) {
|
||||
const key = String(sample.commitTime);
|
||||
const current = byCommit.get(key) ?? {
|
||||
commitTime: sample.commitTime,
|
||||
totalActualDuration: 0,
|
||||
samples: [],
|
||||
};
|
||||
current.totalActualDuration += sample.actualDuration;
|
||||
current.samples.push({
|
||||
id: sample.id,
|
||||
actualDuration: sample.actualDuration,
|
||||
baseDuration: sample.baseDuration,
|
||||
});
|
||||
byCommit.set(key, current);
|
||||
}
|
||||
|
||||
return [...byCommit.values()].sort((left, right) => left.commitTime - right.commitTime);
|
||||
}
|
||||
|
||||
async function openIntent(page, value) {
|
||||
const url = `${workspaceUrl}?renderProfile=1&open=${encodeURIComponent(value)}`;
|
||||
await page.goto(url, { waitUntil: "domcontentloaded" });
|
||||
await page.getByTestId("workspace-tabs-row").waitFor({ timeout: 60_000 });
|
||||
}
|
||||
|
||||
async function clickTab(page, testId) {
|
||||
await page.getByTestId(testId).click();
|
||||
await page.waitForTimeout(switchWaitMs);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
|
||||
|
||||
try {
|
||||
await openIntent(page, `agent:${agentId}`);
|
||||
await openIntent(page, `terminal:${terminalId}`);
|
||||
|
||||
const agentTab = tabTestId("agent", agentId);
|
||||
const terminalTab = tabTestId("terminal", terminalId);
|
||||
await page.getByTestId(agentTab).waitFor({ timeout: 60_000 });
|
||||
await page.getByTestId(terminalTab).waitFor({ timeout: 60_000 });
|
||||
|
||||
await clickTab(page, agentTab);
|
||||
await clickTab(page, terminalTab);
|
||||
await page.waitForTimeout(500);
|
||||
await page.evaluate(() => globalThis.__PASEO_RESET_RENDER_PROFILE__?.());
|
||||
|
||||
if (idleWaitMs > 0) {
|
||||
await page.waitForTimeout(idleWaitMs);
|
||||
}
|
||||
|
||||
for (let index = 0; index < switchCount; index += 1) {
|
||||
await clickTab(page, agentTab);
|
||||
await clickTab(page, terminalTab);
|
||||
}
|
||||
|
||||
const samples = await page.evaluate(() => globalThis.__PASEO_RENDER_PROFILE__ ?? []);
|
||||
const reasons = await page.evaluate(() => globalThis.__PASEO_RENDER_PROFILE_REASONS__ ?? {});
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
{
|
||||
appUrl: baseUrl,
|
||||
serverId,
|
||||
workspaceId,
|
||||
agentId,
|
||||
terminalId,
|
||||
switchCount,
|
||||
switchWaitMs,
|
||||
idleWaitMs,
|
||||
samples: samples.length,
|
||||
summary: summarize(samples),
|
||||
reasons,
|
||||
commits: dumpCommits ? summarizeCommits(samples) : undefined,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
await browser.close();
|
||||
if (createdTerminalId) {
|
||||
killTerminal(createdTerminalId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await main();
|
||||
Reference in New Issue
Block a user