diff options
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/desktop/src/pages/layout.tsx | 4 | ||||
| -rw-r--r-- | packages/desktop/src/pages/session.tsx | 9 | ||||
| -rw-r--r-- | packages/enterprise/src/routes/share/[shareID].tsx | 460 | ||||
| -rw-r--r-- | packages/ui/package.json | 1 | ||||
| -rw-r--r-- | packages/ui/src/components/diff-ssr.tsx | 23 | ||||
| -rw-r--r-- | packages/ui/src/components/diff.css | 2 | ||||
| -rw-r--r-- | packages/ui/src/components/session-review.css | 1 | ||||
| -rw-r--r-- | packages/ui/src/context/worker-pool.tsx | 10 | ||||
| -rw-r--r-- | packages/ui/src/custom-elements.d.ts | 5 | ||||
| -rw-r--r-- | packages/ui/src/pierre/worker.ts | 36 |
10 files changed, 298 insertions, 253 deletions
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 618b84840..540c5d778 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -613,7 +613,7 @@ export default function Layout(props: ParentProps) { classList={{ "relative @container w-12 pb-5 shrink-0 bg-background-base": true, "flex flex-col gap-5.5 items-start self-stretch justify-between": true, - "border-r border-border-weak-base": true, + "border-r border-border-weak-base contain-strict": true, }} style={{ width: layout.sidebar.opened() ? `${layout.sidebar.width()}px` : undefined }} > @@ -755,7 +755,7 @@ export default function Layout(props: ParentProps) { </Tooltip> </div> </div> - <main class="size-full overflow-x-hidden flex flex-col items-start">{props.children}</main> + <main class="size-full overflow-x-hidden flex flex-col items-start contain-strict">{props.children}</main> </div> <Toast.Region /> </div> diff --git a/packages/desktop/src/pages/session.tsx b/packages/desktop/src/pages/session.tsx index 3415d0c4e..7d1392c20 100644 --- a/packages/desktop/src/pages/session.tsx +++ b/packages/desktop/src/pages/session.tsx @@ -578,7 +578,10 @@ export default function Page() { </div> </Tabs.List> </div> - <Tabs.Content value="chat" class="@container select-text flex flex-col flex-1 min-h-0 overflow-y-hidden"> + <Tabs.Content + value="chat" + class="@container select-text flex flex-col flex-1 min-h-0 overflow-y-hidden contain-strict" + > <div classList={{ "w-full flex-1 min-h-0": true, @@ -661,7 +664,7 @@ export default function Page() { <Show when={layout.review.state() === "pane" && diffs().length}> <div classList={{ - "relative grow pt-3 flex-1 min-h-0 border-l border-border-weak-base": true, + "relative grow pt-3 flex-1 min-h-0 border-l border-border-weak-base contain-strict": true, }} > <SessionReview @@ -689,7 +692,7 @@ export default function Page() { </div> </Tabs.Content> <Show when={layout.review.state() === "tab" && diffs().length}> - <Tabs.Content value="review" class="select-text flex flex-col h-full overflow-hidden"> + <Tabs.Content value="review" class="select-text flex flex-col h-full overflow-hidden contain-strict"> <div classList={{ "relative pt-3 flex-1 min-h-0 overflow-hidden": true, diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx index 4f9f95c01..e2743344f 100644 --- a/packages/enterprise/src/routes/share/[shareID].tsx +++ b/packages/enterprise/src/routes/share/[shareID].tsx @@ -4,6 +4,7 @@ import { SessionReview } from "@opencode-ai/ui/session-review" import { DataProvider } from "@opencode-ai/ui/context" import { DiffComponentProvider } from "@opencode-ai/ui/context/diff" import { CodeComponentProvider } from "@opencode-ai/ui/context/code" +import { WorkerPoolProvider } from "@opencode-ai/ui/context/worker-pool" import { createAsync, query, useParams } from "@solidjs/router" import { createEffect, createMemo, ErrorBoundary, For, Match, Show, Switch } from "solid-js" import { Share } from "~/core/share" @@ -29,6 +30,13 @@ import { Base64 } from "js-base64" const ClientOnlyDiff = clientOnly(() => import("@opencode-ai/ui/diff").then((m) => ({ default: m.Diff }))) const ClientOnlyCode = clientOnly(() => import("@opencode-ai/ui/code").then((m) => ({ default: m.Code }))) +const ClientOnlyWorkerPoolProvider = clientOnly(() => + import("@opencode-ai/ui/pierre/worker").then((m) => ({ + default: (props: { children: any }) => ( + <WorkerPoolProvider pool={m.workerPool}>{props.children}</WorkerPoolProvider> + ), + })), +) const SessionDataMissingError = NamedError.create( "SessionDataMissingError", @@ -197,256 +205,260 @@ export default function () { <Meta name="description" content="opencode - The AI coding agent built for the terminal." /> <Meta property="og:image" content={ogImage()} /> <Meta name="twitter:image" content={ogImage()} /> - <DiffComponentProvider component={ClientOnlyDiff}> - <CodeComponentProvider component={ClientOnlyCode}> - <DataProvider data={data()} directory={info().directory}> - {iife(() => { - const [store, setStore] = createStore({ - messageId: undefined as string | undefined, - }) - const messages = createMemo(() => - data().sessionID - ? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort( - (a, b) => a.time.created - b.time.created, - ) - : [], - ) - const firstUserMessage = createMemo(() => messages().at(0)) - const activeMessage = createMemo( - () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), - ) - function setActiveMessage(message: UserMessage | undefined) { - if (message) { - setStore("messageId", message.id) - } else { - setStore("messageId", undefined) + <ClientOnlyWorkerPoolProvider> + <DiffComponentProvider component={ClientOnlyDiff}> + <CodeComponentProvider component={ClientOnlyCode}> + <DataProvider data={data()} directory={info().directory}> + {iife(() => { + const [store, setStore] = createStore({ + messageId: undefined as string | undefined, + }) + const messages = createMemo(() => + data().sessionID + ? (data().message[data().sessionID]?.filter((m) => m.role === "user") ?? []).sort( + (a, b) => a.time.created - b.time.created, + ) + : [], + ) + const firstUserMessage = createMemo(() => messages().at(0)) + const activeMessage = createMemo( + () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), + ) + function setActiveMessage(message: UserMessage | undefined) { + if (message) { + setStore("messageId", message.id) + } else { + setStore("messageId", undefined) + } } - } - const provider = createMemo(() => activeMessage()?.model?.providerID) - const modelID = createMemo(() => activeMessage()?.model?.modelID) - const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID())) - const diffs = createMemo(() => { - const diffs = data().session_diff[data().sessionID] ?? [] - const preloaded = data().session_diff_preload[data().sessionID] ?? [] - return diffs.map((diff) => ({ - ...diff, - preloaded: preloaded.find((d) => d.newFile.name === diff.file), - })) - }) - const splitDiffs = createMemo(() => { - const diffs = data().session_diff[data().sessionID] ?? [] - const preloaded = data().session_diff_preload_split[data().sessionID] ?? [] - return diffs.map((diff) => ({ - ...diff, - preloaded: preloaded.find((d) => d.newFile.name === diff.file), - })) - }) + const provider = createMemo(() => activeMessage()?.model?.providerID) + const modelID = createMemo(() => activeMessage()?.model?.modelID) + const model = createMemo(() => data().model[data().sessionID]?.find((m) => m.id === modelID())) + const diffs = createMemo(() => { + const diffs = data().session_diff[data().sessionID] ?? [] + const preloaded = data().session_diff_preload[data().sessionID] ?? [] + return diffs.map((diff) => ({ + ...diff, + preloaded: preloaded.find((d) => d.newFile.name === diff.file), + })) + }) + const splitDiffs = createMemo(() => { + const diffs = data().session_diff[data().sessionID] ?? [] + const preloaded = data().session_diff_preload_split[data().sessionID] ?? [] + return diffs.map((diff) => ({ + ...diff, + preloaded: preloaded.find((d) => d.newFile.name === diff.file), + })) + }) - const title = () => ( - <div class="flex flex-col gap-4"> - <div class="h-8 flex gap-4 items-center justify-start self-stretch"> - <div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base"> - <Mark class="shrink-0 w-3 my-0.5" /> - <div class="text-12-mono text-text-base">v{info().version}</div> - </div> - <div class="flex gap-2 items-center"> - <ProviderIcon - id={provider() as IconName} - class="size-3.5 shrink-0 text-icon-strong-base" - /> - <div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div> - </div> - <div class="text-12-regular text-text-weaker"> - {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} + const title = () => ( + <div class="flex flex-col gap-4"> + <div class="h-8 flex gap-4 items-center justify-start self-stretch"> + <div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base"> + <Mark class="shrink-0 w-3 my-0.5" /> + <div class="text-12-mono text-text-base">v{info().version}</div> + </div> + <div class="flex gap-2 items-center"> + <ProviderIcon + id={provider() as IconName} + class="size-3.5 shrink-0 text-icon-strong-base" + /> + <div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div> + </div> + <div class="text-12-regular text-text-weaker"> + {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} + </div> </div> + <div class="text-left text-16-medium text-text-strong">{info().title}</div> </div> - <div class="text-left text-16-medium text-text-strong">{info().title}</div> - </div> - ) + ) - const turns = () => ( - <div class="relative mt-2 pt-6 pb-8 min-w-0 w-full h-full overflow-y-auto no-scrollbar"> - <div class="px-4">{title()}</div> - <div class="flex flex-col gap-15 items-start justify-start mt-4"> - <For each={messages()}> - {(message) => ( - <SessionTurn - sessionID={data().sessionID} - messageID={message.id} - classes={{ - root: "min-w-0 w-full relative", - content: - "flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]", - container: "px-4", - }} - /> - )} - </For> - </div> - <div class="px-4 flex items-center justify-center pt-20 pb-8 shrink-0"> - <Logo class="w-58.5 opacity-12" /> + const turns = () => ( + <div class="relative mt-2 pt-6 pb-8 min-w-0 w-full h-full overflow-y-auto no-scrollbar"> + <div class="px-4">{title()}</div> + <div class="flex flex-col gap-15 items-start justify-start mt-4"> + <For each={messages()}> + {(message) => ( + <SessionTurn + sessionID={data().sessionID} + messageID={message.id} + classes={{ + root: "min-w-0 w-full relative", + content: + "flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]", + container: "px-4", + }} + /> + )} + </For> + </div> + <div class="px-4 flex items-center justify-center pt-20 pb-8 shrink-0"> + <Logo class="w-58.5 opacity-12" /> + </div> </div> - </div> - ) + ) - const wide = createMemo(() => diffs().length === 0) + const wide = createMemo(() => diffs().length === 0) - return ( - <div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col"> - <header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base"> - <div class=""> - <a href="https://opencode.ai"> - <Mark /> - </a> - </div> - <div class="flex gap-3 items-center"> - <IconButton - as={"a"} - href="https://github.com/sst/opencode" - target="_blank" - icon="github" - variant="ghost" - /> - <IconButton - as={"a"} - href="https://opencode.ai/discord" - target="_blank" - icon="discord" - variant="ghost" - /> - </div> - </header> - <div class="select-text flex flex-col flex-1 min-h-0"> - <div - classList={{ - "hidden w-full flex-1 min-h-0": true, - "md:flex": wide(), - "lg:flex": !wide(), - }} - > + return ( + <div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col"> + <header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base"> + <div class=""> + <a href="https://opencode.ai"> + <Mark /> + </a> + </div> + <div class="flex gap-3 items-center"> + <IconButton + as={"a"} + href="https://github.com/sst/opencode" + target="_blank" + icon="github" + variant="ghost" + /> + <IconButton + as={"a"} + href="https://opencode.ai/discord" + target="_blank" + icon="discord" + variant="ghost" + /> + </div> + </header> + <div class="select-text flex flex-col flex-1 min-h-0"> <div classList={{ - "@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full": true, - "mx-auto max-w-200": !wide(), + "hidden w-full flex-1 min-h-0": true, + "md:flex": wide(), + "lg:flex": !wide(), }} > <div classList={{ - "w-full flex justify-start items-start min-w-0": true, - "max-w-200 mx-auto px-6": wide(), - "pr-6 pl-18": !wide() && messages().length > 1, - "px-6": !wide() && messages().length === 1, + "@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full": true, + "mx-auto max-w-200": !wide(), }} > - {title()} - </div> - <div class="flex items-start justify-start h-full min-h-0"> - <SessionMessageRail - messages={messages()} - current={activeMessage()} - onMessageSelect={setActiveMessage} - wide={wide()} - /> - <SessionTurn - sessionID={data().sessionID} - messageID={store.messageId ?? firstUserMessage()!.id!} - classes={{ - root: "grow", - content: "flex flex-col justify-between", - container: - "w-full pb-20 " + - (wide() - ? "max-w-200 mx-auto px-6" - : messages().length > 1 - ? "pr-6 pl-18" - : "px-6"), + <div + classList={{ + "w-full flex justify-start items-start min-w-0": true, + "max-w-200 mx-auto px-6": wide(), + "pr-6 pl-18": !wide() && messages().length > 1, + "px-6": !wide() && messages().length === 1, }} > - <div classList={{ "w-full flex items-center justify-center pb-8 shrink-0": true }}> - <Logo class="w-58.5 opacity-12" /> - </div> - </SessionTurn> - </div> - </div> - <Show when={diffs().length > 0}> - <DiffComponentProvider component={SSRDiff}> - <div class="@container relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base"> - <SessionReview - class="@4xl:hidden" - diffs={diffs()} - classes={{ - root: "pb-20", - header: "px-6", - container: "px-6", - }} + {title()} + </div> + <div class="flex items-start justify-start h-full min-h-0"> + <SessionMessageRail + messages={messages()} + current={activeMessage()} + onMessageSelect={setActiveMessage} + wide={wide()} /> - <SessionReview - split - class="hidden @4xl:flex" - diffs={splitDiffs()} + <SessionTurn + sessionID={data().sessionID} + messageID={store.messageId ?? firstUserMessage()!.id!} classes={{ - root: "pb-20", - header: "px-6", - container: "px-6", + root: "grow", + content: "flex flex-col justify-between", + container: + "w-full pb-20 " + + (wide() + ? "max-w-200 mx-auto px-6" + : messages().length > 1 + ? "pr-6 pl-18" + : "px-6"), }} - /> + > + <div + classList={{ "w-full flex items-center justify-center pb-8 shrink-0": true }} + > + <Logo class="w-58.5 opacity-12" /> + </div> + </SessionTurn> </div> - </DiffComponentProvider> - </Show> - </div> - <Switch> - <Match when={diffs().length > 0}> - <Tabs classList={{ "md:hidden": wide(), "lg:hidden": !wide() }}> - <Tabs.List> - <Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}> - Session - </Tabs.Trigger> - <Tabs.Trigger + </div> + <Show when={diffs().length > 0}> + <DiffComponentProvider component={SSRDiff}> + <div class="@container relative grow pt-14 flex-1 min-h-0 border-l border-border-weak-base"> + <SessionReview + class="@4xl:hidden" + diffs={diffs()} + classes={{ + root: "pb-20", + header: "px-6", + container: "px-6", + }} + /> + <SessionReview + split + class="hidden @4xl:flex" + diffs={splitDiffs()} + classes={{ + root: "pb-20", + header: "px-6", + container: "px-6", + }} + /> + </div> + </DiffComponentProvider> + </Show> + </div> + <Switch> + <Match when={diffs().length > 0}> + <Tabs classList={{ "md:hidden": wide(), "lg:hidden": !wide() }}> + <Tabs.List> + <Tabs.Trigger value="session" class="w-1/2" classes={{ button: "w-full" }}> + Session + </Tabs.Trigger> + <Tabs.Trigger + value="review" + class="w-1/2 !border-r-0" + classes={{ button: "w-full" }} + > + {diffs().length} Files Changed + </Tabs.Trigger> + </Tabs.List> + <Tabs.Content value="session" class="!overflow-hidden"> + {turns()} + </Tabs.Content> + <Tabs.Content + forceMount value="review" - class="w-1/2 !border-r-0" - classes={{ button: "w-full" }} + class="!overflow-hidden hidden data-[selected]:block" > - {diffs().length} Files Changed - </Tabs.Trigger> - </Tabs.List> - <Tabs.Content value="session" class="!overflow-hidden"> - {turns()} - </Tabs.Content> - <Tabs.Content - forceMount - value="review" - class="!overflow-hidden hidden data-[selected]:block" + <div class="relative h-full pt-8 overflow-y-auto no-scrollbar"> + <DiffComponentProvider component={SSRDiff}> + <SessionReview + diffs={diffs()} + classes={{ + root: "pb-20", + header: "px-4", + container: "px-4", + }} + /> + </DiffComponentProvider> + </div> + </Tabs.Content> + </Tabs> + </Match> + <Match when={true}> + <div + classList={{ "!overflow-hidden": true, "md:hidden": wide(), "lg:hidden": !wide() }} > - <div class="relative h-full pt-8 overflow-y-auto no-scrollbar"> - <DiffComponentProvider component={SSRDiff}> - <SessionReview - diffs={diffs()} - classes={{ - root: "pb-20", - header: "px-4", - container: "px-4", - }} - /> - </DiffComponentProvider> - </div> - </Tabs.Content> - </Tabs> - </Match> - <Match when={true}> - <div - classList={{ "!overflow-hidden": true, "md:hidden": wide(), "lg:hidden": !wide() }} - > - {turns()} - </div> - </Match> - </Switch> + {turns()} + </div> + </Match> + </Switch> + </div> </div> - </div> - ) - })} - </DataProvider> - </CodeComponentProvider> - </DiffComponentProvider> + ) + })} + </DataProvider> + </CodeComponentProvider> + </DiffComponentProvider> + </ClientOnlyWorkerPoolProvider> </> ) }} diff --git a/packages/ui/package.json b/packages/ui/package.json index b2e7e331d..618dbf1f0 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -5,6 +5,7 @@ "exports": { "./*": "./src/components/*.tsx", "./pierre": "./src/pierre/index.ts", + "./pierre/*": "./src/pierre/*.ts", "./hooks": "./src/hooks/index.ts", "./context": "./src/context/index.ts", "./context/*": "./src/context/*.tsx", diff --git a/packages/ui/src/components/diff-ssr.tsx b/packages/ui/src/components/diff-ssr.tsx index b38b4a34f..e367a4fbe 100644 --- a/packages/ui/src/components/diff-ssr.tsx +++ b/packages/ui/src/components/diff-ssr.tsx @@ -1,8 +1,9 @@ -import { FileDiff } from "@pierre/diffs" +import { DIFFS_TAG_NAME, FileDiff } from "@pierre/diffs" import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" import { onCleanup, onMount, Show, splitProps } from "solid-js" -import { isServer } from "solid-js/web" +import { Dynamic, isServer } from "solid-js/web" import { createDefaultOptions, styleVariables, type DiffProps } from "../pierre" +import { useWorkerPool } from "../context/worker-pool" export type SSRDiffProps<T = {}> = DiffProps<T> & { preloadedDiff: PreloadMultiFileDiffResult<T> @@ -12,17 +13,21 @@ export function Diff<T>(props: SSRDiffProps<T>) { let container!: HTMLDivElement let fileDiffRef!: HTMLElement const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"]) + const workerPool = useWorkerPool() let fileDiffInstance: FileDiff<T> | undefined const cleanupFunctions: Array<() => void> = [] onMount(() => { if (isServer || !props.preloadedDiff) return - fileDiffInstance = new FileDiff<T>({ - ...createDefaultOptions(props.diffStyle), - ...others, - ...props.preloadedDiff, - }) + fileDiffInstance = new FileDiff<T>( + { + ...createDefaultOptions(props.diffStyle), + ...others, + ...props.preloadedDiff, + }, + workerPool, + ) // @ts-expect-error - fileContainer is private but needed for SSR hydration fileDiffInstance.fileContainer = fileDiffRef fileDiffInstance.hydrate({ @@ -65,11 +70,11 @@ export function Diff<T>(props: SSRDiffProps<T>) { return ( <div data-component="diff" style={styleVariables} ref={container}> - <diffs-container ref={fileDiffRef} id="ssr-diff"> + <Dynamic component={DIFFS_TAG_NAME} ref={fileDiffRef} id="ssr-diff"> <Show when={isServer}> <template shadowrootmode="open" innerHTML={props.preloadedDiff.prerenderedHTML} /> </Show> - </diffs-container> + </Dynamic> </div> ) } diff --git a/packages/ui/src/components/diff.css b/packages/ui/src/components/diff.css index 345271a12..3251eb4c6 100644 --- a/packages/ui/src/components/diff.css +++ b/packages/ui/src/components/diff.css @@ -1,4 +1,6 @@ [data-component="diff"] { + contain: content; + [data-slot="diff-hunk-separator-line-number"] { position: sticky; left: 0; diff --git a/packages/ui/src/components/session-review.css b/packages/ui/src/components/session-review.css index 0cd228592..35df4a80f 100644 --- a/packages/ui/src/components/session-review.css +++ b/packages/ui/src/components/session-review.css @@ -5,6 +5,7 @@ height: 100%; overflow-y: auto; scrollbar-width: none; + contain: strict; &::-webkit-scrollbar { display: none; } diff --git a/packages/ui/src/context/worker-pool.tsx b/packages/ui/src/context/worker-pool.tsx new file mode 100644 index 000000000..fc2eecc03 --- /dev/null +++ b/packages/ui/src/context/worker-pool.tsx @@ -0,0 +1,10 @@ +import type { WorkerPoolManager } from "@pierre/diffs/worker" +import { createSimpleContext } from "./helper" + +const ctx = createSimpleContext<WorkerPoolManager | undefined, { pool: WorkerPoolManager | undefined }>({ + name: "WorkerPool", + init: (props) => props.pool, +}) + +export const WorkerPoolProvider = ctx.provider +export const useWorkerPool = ctx.use diff --git a/packages/ui/src/custom-elements.d.ts b/packages/ui/src/custom-elements.d.ts index b756e51da..49ec4449f 100644 --- a/packages/ui/src/custom-elements.d.ts +++ b/packages/ui/src/custom-elements.d.ts @@ -1,12 +1,15 @@ +import { DIFFS_TAG_NAME } from "@pierre/diffs" + /** * TypeScript declaration for the <diffs-container> custom element. * This tells TypeScript that <diffs-container> is a valid JSX element in SolidJS. * Required for using the @pierre/diffs web component in .tsx files. */ + declare module "solid-js" { namespace JSX { interface IntrinsicElements { - "diffs-container": HTMLAttributes<HTMLElement> + [DIFFS_TAG_NAME]: HTMLAttributes<HTMLElement> } } } diff --git a/packages/ui/src/pierre/worker.ts b/packages/ui/src/pierre/worker.ts index e47268d4e..2d2640674 100644 --- a/packages/ui/src/pierre/worker.ts +++ b/packages/ui/src/pierre/worker.ts @@ -1,20 +1,28 @@ -import { getOrCreateWorkerPoolSingleton } from "@pierre/diffs/worker" +import { getOrCreateWorkerPoolSingleton, WorkerPoolManager } from "@pierre/diffs/worker" import ShikiWorkerUrl from "@pierre/diffs/worker/worker.js?worker&url" export function workerFactory(): Worker { return new Worker(ShikiWorkerUrl, { type: "module" }) } -export const workerPool = getOrCreateWorkerPoolSingleton({ - poolOptions: { - workerFactory, - // poolSize defaults to 8. More workers = more parallelism but - // also more memory. Too many can actually slow things down. - // poolSize: 8, - }, - highlighterOptions: { - theme: "OpenCode", - // Optionally preload languages to avoid lazy-loading delays - // langs: ["typescript", "javascript", "css", "html"], - }, -}) +export const workerPool: WorkerPoolManager | undefined = (() => { + if (typeof window === "undefined") { + return undefined + } + return getOrCreateWorkerPoolSingleton({ + poolOptions: { + workerFactory, + // poolSize defaults to 8. More workers = more parallelism but + // also more memory. Too many can actually slow things down. + // NOTE: 2 is probably better for OpenCode, as I think 8 might be + // a bit overkill, especially because Safari has a significantly slower + // boot up time for workers + poolSize: 2, + }, + highlighterOptions: { + theme: "OpenCode", + // Optionally preload languages to avoid lazy-loading delays + // langs: ["typescript", "javascript", "css", "html"], + }, + }) +})() |
