mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 16:02:50 +00:00
fix(diffs): own the Pierre worker pool singleton; document StrictMode blocker
Vite dev served the worker as a raw file, so switch to the `?worker` import. Also bypass Pierre's WorkerPoolContextProvider: it terminates the pool singleton from an unmount cleanup but only recreates it in useState, so StrictMode's remount leaves consumers holding a terminated pool. Neither fixes rendering. @pierre/diffs 1.3.6 does not survive StrictMode's mount/unmount/mount at all - the shadow DOM is never committed on the second mount and every diff renders blank. Documented in PierreDiffProviders.
This commit is contained in:
@@ -3,8 +3,11 @@ import { PierreDiffEditProvider } from './pierre-diff-editor-provider'
|
||||
|
||||
/**
|
||||
* Wraps a diff surface with the Shiki worker pool and the editor factory.
|
||||
* Pierre reference-counts the pool, so every diff view can mount this and they
|
||||
* still share one set of workers.
|
||||
*
|
||||
* KNOWN BLOCKER: @pierre/diffs 1.3.6 does not survive React StrictMode's
|
||||
* mount/unmount/mount. Its shadow DOM is never committed on the second mount,
|
||||
* so every diff renders blank in dev. Verified by toggling StrictMode alone,
|
||||
* with and without the worker pool. Production builds do not run StrictMode.
|
||||
*/
|
||||
export function PierreDiffProviders({
|
||||
children
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useMemo } from 'react'
|
||||
import { WorkerPoolContextProvider } from '@pierre/diffs/react'
|
||||
import type { WorkerInitializationRenderOptions, WorkerPoolOptions } from '@pierre/diffs/react'
|
||||
import { useState } from 'react'
|
||||
// Why: `?worker` makes Vite own the worker in dev too. A bare `new URL(...)`
|
||||
// specifier is served as a raw file, so the worker's own imports of shiki and
|
||||
// hast-util-to-html never get rewritten.
|
||||
import PierreDiffHighlightWorker from '@pierre/diffs/worker/worker.js?worker'
|
||||
import { WorkerPoolContext } from '@pierre/diffs/react'
|
||||
import { getOrCreateWorkerPoolSingleton, type WorkerPoolManager } from '@pierre/diffs/worker'
|
||||
import { PIERRE_DIFF_THEMES } from './pierre-diff-theme'
|
||||
|
||||
// Why: Shiki grammars are heavy per worker; cap the pool well under Pierre's
|
||||
@@ -10,34 +14,39 @@ function resolvePoolSize(): number {
|
||||
return Math.min(4, Math.max(1, cores - 2))
|
||||
}
|
||||
|
||||
function createDiffHighlightWorker(): Worker {
|
||||
// Why: electron.vite.config.ts pins `worker.format: 'es'`, which this URL form requires.
|
||||
return new Worker(new URL('@pierre/diffs/worker/worker.js', import.meta.url), { type: 'module' })
|
||||
function createDiffHighlightPool(): WorkerPoolManager {
|
||||
return getOrCreateWorkerPoolSingleton({
|
||||
poolOptions: {
|
||||
workerFactory: () => new PierreDiffHighlightWorker(),
|
||||
poolSize: resolvePoolSize()
|
||||
},
|
||||
// Why: the pool owns `theme` for every component instance; per-file options are ignored.
|
||||
highlighterOptions: { theme: PIERRE_DIFF_THEMES }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Shares one Shiki worker pool across every mounted diff surface. Pierre
|
||||
* reference-counts providers, so wrapping each lazy diff view keeps highlighting
|
||||
* off the main thread without paying worker startup on app launch.
|
||||
* Shares one Shiki worker pool across every mounted diff surface.
|
||||
*
|
||||
* Note: Pierre's own WorkerPoolContextProvider is bypassed. It terminates the
|
||||
* pool singleton from an unmount cleanup but only recreates it in `useState`,
|
||||
* so StrictMode's remount leaves every consumer holding a terminated pool.
|
||||
* We own the singleton and never tear it down.
|
||||
*
|
||||
* Why not Pierre's `WorkerPoolContextProvider`: it terminates the singleton from
|
||||
* an unmount cleanup, but recreates it only in `useState`. StrictMode's
|
||||
* mount/unmount/mount then leaves every consumer holding a terminated pool, so
|
||||
* nothing ever renders in dev. We own the singleton and never tear it down —
|
||||
* the pool is process-wide and cheap to keep warm for an app that reopens diffs
|
||||
* constantly.
|
||||
*/
|
||||
export function PierreDiffWorkerPoolProvider({
|
||||
children
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}): React.JSX.Element {
|
||||
const poolOptions = useMemo<WorkerPoolOptions>(
|
||||
() => ({ workerFactory: createDiffHighlightWorker, poolSize: resolvePoolSize() }),
|
||||
[]
|
||||
)
|
||||
// Why: the pool owns `theme` for every component instance; per-file options are ignored.
|
||||
const highlighterOptions = useMemo<WorkerInitializationRenderOptions>(
|
||||
() => ({ theme: PIERRE_DIFF_THEMES }),
|
||||
[]
|
||||
)
|
||||
// Why: lazy initializer keeps worker startup off app launch until a diff opens.
|
||||
const [pool] = useState(createDiffHighlightPool)
|
||||
|
||||
return (
|
||||
<WorkerPoolContextProvider poolOptions={poolOptions} highlighterOptions={highlighterOptions}>
|
||||
{children}
|
||||
</WorkerPoolContextProvider>
|
||||
)
|
||||
return <WorkerPoolContext.Provider value={pool}>{children}</WorkerPoolContext.Provider>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user