From 453fb4992e9333be607322af1c2c2870ad93135d Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Wed, 18 Feb 2026 16:45:59 -0800 Subject: [PATCH] Keep diff panel mounted and reuse worker pool across layouts - Keep the diff viewer alive when hidden to avoid remount churn - Share diff worker pool setup via a dedicated provider - Add `keepMounted` support to `SheetPopup` for sheet-mode persistence --- apps/web/src/App.tsx | 97 ++++++---- apps/web/src/components/DiffPanel.tsx | 267 +++++++++++++------------- apps/web/src/components/ui/sheet.tsx | 4 +- 3 files changed, 198 insertions(+), 170 deletions(-) diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 13058c114e267669e256fd4fee8dbb84f7f00e16..598b6a9604dca6171598a6268de518f940940477 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,5 +1,5 @@ import { QueryClient, QueryClientProvider, useQueryClient } from "@tanstack/react-query"; -import { Suspense, lazy, useEffect, useRef } from "react"; +import { Activity, Suspense, lazy, useEffect, useRef, useState } from "react"; import ChatView from "./components/ChatView"; import Sidebar from "./components/Sidebar"; @@ -15,8 +15,44 @@ import { Sheet, SheetPopup } from "./components/ui/sheet"; import { invalidateGitQueries } from "./lib/gitReactQuery"; const DiffPanel = lazy(() => import("./components/DiffPanel")); +const DiffWorkerPoolProvider = lazy(() => + import("./components/DiffPanel").then((module) => ({ + default: module.DiffWorkerPoolProvider, + })), +); const DIFF_INLINE_LAYOUT_MEDIA_QUERY = "(max-width: 1180px)"; +const DiffPanelWrapper = (props: { children: React.ReactNode; sheet: boolean }) => { + const { state, dispatch } = useStore(); + if (props.sheet) { + return ( + { + if (!open) { + dispatch({ type: "CLOSE_DIFF" }); + } + }} + > + + {props.children} + + + ); + } + + return ( + + ); +}; + function EventRouter() { const api = useNativeApi(); const { dispatch } = useStore(); @@ -181,9 +217,20 @@ function DesktopProjectBootstrap() { function Layout() { const api = useNativeApi(); - const { state, dispatch } = useStore(); + const { state } = useStore(); const shouldUseDiffSheet = useMediaQuery(DIFF_INLINE_LAYOUT_MEDIA_QUERY); + const diffLoadingFallback = + !state.diffOpen || shouldUseDiffSheet ? ( +
+ Loading diff viewer... +
+ ) : ( + + ); + if (!api) { return (
@@ -201,43 +248,15 @@ function Layout() { - {state.diffOpen && !shouldUseDiffSheet && ( - - Loading diff viewer... - - } - > - - - )} - {state.diffOpen && shouldUseDiffSheet && ( - { - if (!open) { - dispatch({ type: "CLOSE_DIFF" }); - } - }} - > - - - Loading diff viewer... -
- } - > - - - - - )} + + + + + + + + + ); } diff --git a/apps/web/src/components/DiffPanel.tsx b/apps/web/src/components/DiffPanel.tsx index c1bdc862aa8fb4599ad3af794f3cf4bd12cfea00..c8ce00f7df1337a3b0ffc03e29cbcd738ea02b3f 100644 --- a/apps/web/src/components/DiffPanel.tsx +++ b/apps/web/src/components/DiffPanel.tsx @@ -2,7 +2,7 @@ import { parsePatchFiles } from "@pierre/diffs"; import { FileDiff, type FileDiffMetadata, WorkerPoolContextProvider } from "@pierre/diffs/react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { Columns2Icon, Rows3Icon } from "lucide-react"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { type ReactNode, useEffect, useMemo, useRef, useState } from "react"; import { checkpointDiffQueryOptions, providerQueryKeys } from "~/lib/providerReactQuery"; import { cn } from "~/lib/utils"; import { isElectron } from "../env"; @@ -65,6 +65,29 @@ interface DiffPanelProps { mode?: "inline" | "sheet"; } +export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { + const workerPoolSize = useMemo(() => { + const cores = typeof navigator === "undefined" ? 4 : Math.max(1, navigator.hardwareConcurrency || 4); + return Math.max(2, Math.min(6, Math.floor(cores / 2))); + }, []); + + return ( + + new Worker(new URL("../workers/diffs.worker.ts", import.meta.url), { type: "module" }), + poolSize: workerPoolSize, + totalASTLRUCacheSize: 240, + }} + highlighterOptions={{ + tokenizeMaxLineLength: 1_000, + }} + > + {children} + + ); +} + export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { const api = useNativeApi(); const { resolvedTheme } = useTheme(); @@ -289,151 +312,135 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { }; const shouldUseDragRegion = isElectron && mode === "inline"; - const workerPoolSize = useMemo(() => { - const cores = typeof navigator === "undefined" ? 4 : Math.max(1, navigator.hardwareConcurrency || 4); - return Math.max(2, Math.min(6, Math.floor(cores / 2))); - }, []); return ( - - new Worker(new URL("../workers/diffs.worker.ts", import.meta.url), { type: "module" }), - poolSize: workerPoolSize, - totalASTLRUCacheSize: 240, - }} - highlighterOptions={{ - tokenizeMaxLineLength: 1_000, - }} + ); } diff --git a/apps/web/src/components/ui/sheet.tsx b/apps/web/src/components/ui/sheet.tsx index c5ca5101bbaa8df4e40042a98c3c7129b1b7eae1..0a27f5697df2e34aa9bb77bf7a54d850cd3e380b 100644 --- a/apps/web/src/components/ui/sheet.tsx +++ b/apps/web/src/components/ui/sheet.tsx @@ -60,16 +60,18 @@ function SheetPopup({ className, children, showCloseButton = true, + keepMounted = false, side = "right", variant = "default", ...props }: SheetPrimitive.Popup.Props & { showCloseButton?: boolean; + keepMounted?: boolean; side?: "right" | "left" | "top" | "bottom"; variant?: "default" | "inset"; }) { return ( - +