From 7c70f77255dd5073ab5b55f31539b7d10e07ff15 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Tue, 1 Apr 2025 16:15:25 +1100 Subject: [PATCH] fix worker bundled with window related code --- packages/excalidraw/lasso/index.ts | 110 +++++------------- .../excalidraw/lasso/lasso-worker-polyfill.ts | 28 +++++ 2 files changed, 57 insertions(+), 81 deletions(-) create mode 100644 packages/excalidraw/lasso/lasso-worker-polyfill.ts diff --git a/packages/excalidraw/lasso/index.ts b/packages/excalidraw/lasso/index.ts index a1bc73f01..ee1cdba2c 100644 --- a/packages/excalidraw/lasso/index.ts +++ b/packages/excalidraw/lasso/index.ts @@ -17,7 +17,7 @@ import { selectGroupsForSelectedElements } from "@excalidraw/element/groups"; import { getContainerElement } from "@excalidraw/element/textElement"; -import { arrayToMap, easeOut, promiseTry } from "@excalidraw/common"; +import { arrayToMap, easeOut } from "@excalidraw/common"; import type { ExcalidrawElement, @@ -29,9 +29,9 @@ import { type AnimationFrameHandler } from "../animation-frame-handler"; import { AnimatedTrail } from "../animated-trail"; -import { WorkerPool } from "../workers"; +import LassoWorker from "./lasso-worker.chunk?worker"; -import { updateSelection } from "./utils"; +import { LassoWorkerPolyfill } from "./lasso-worker-polyfill"; import type App from "../components/App"; import type { LassoWorkerInput, LassoWorkerOutput } from "./types"; @@ -43,6 +43,8 @@ export class LassoTrail extends AnimatedTrail { null; private keepPreviousSelection: boolean = false; + private worker: Worker | LassoWorkerPolyfill | null = null; + constructor(animationFrameHandler: AnimationFrameHandler, app: App) { super(animationFrameHandler, app, { animateTrail: true, @@ -65,7 +67,7 @@ export class LassoTrail extends AnimatedTrail { }); } - async startPath(x: number, y: number, keepPreviousSelection = false) { + startPath(x: number, y: number, keepPreviousSelection = false) { // clear any existing trails just in case this.endPath(); @@ -82,6 +84,24 @@ export class LassoTrail extends AnimatedTrail { selectedLinearElement: null, }); } + + try { + this.worker = + typeof Worker !== "undefined" + ? new LassoWorker() + : new LassoWorkerPolyfill(); + + this.worker.onmessage = (event: MessageEvent) => { + const { selectedElementIds } = event.data; + this.selectElementsFromIds(selectedElementIds); + }; + + this.worker.onerror = (error) => { + console.error("Worker error:", error); + }; + } catch (error) { + console.error("Failed to start worker", error); + } } selectElementsFromIds = (ids: string[]) => { @@ -151,11 +171,7 @@ export class LassoTrail extends AnimatedTrail { }); }; - addPointToPath = async ( - x: number, - y: number, - keepPreviousSelection = false, - ) => { + addPointToPath = (x: number, y: number, keepPreviousSelection = false) => { super.addPointToPath(x, y); this.keepPreviousSelection = keepPreviousSelection; @@ -169,10 +185,10 @@ export class LassoTrail extends AnimatedTrail { }, }); - await this.updateSelection(); + this.updateSelection(); }; - private updateSelection = async () => { + private updateSelection = () => { const lassoPath = super .getCurrentTrail() ?.originalPoints?.map((p) => pointFrom(p[0], p[1])); @@ -196,15 +212,7 @@ export class LassoTrail extends AnimatedTrail { simplifyDistance: 5 / this.app.state.zoom.value, }; - const workerPool = await getOrCreateWorkerPool(); - const result = await workerPool.postMessage(message, {}); - - const { selectedElementIds } = result; - if (!selectedElementIds || !Array.isArray(selectedElementIds)) { - return; - } - - this.selectElementsFromIds(selectedElementIds); + this.worker?.postMessage(message); } }; @@ -218,66 +226,6 @@ export class LassoTrail extends AnimatedTrail { lassoSelection: null, }); - getOrCreateWorkerPool() - .then((workerPool) => { - workerPool.clear(); - }) - .catch((error) => { - console.error("Failed to clear worker pool", error); - }); - } -} - -let lassoWorker: Promise | null = null; - -const lazyLoadLassoWorkerChunk = async () => { - if (!lassoWorker) { - lassoWorker = import("./lasso-worker.chunk"); - } - - return lassoWorker; -}; - -let workerPool: Promise< - WorkerPool -> | null = null; - -const getOrCreateWorkerPool = async () => { - if (!workerPool) { - workerPool = promiseTry(async () => { - if (typeof Worker !== "undefined") { - const { WorkerUrl } = await lazyLoadLassoWorkerChunk(); - - return WorkerPool.create( - WorkerUrl, - ); - } - return WorkerPolyfillPool.create() as unknown as WorkerPool< - LassoWorkerInput, - LassoWorkerOutput - >; - }); - } - return workerPool; -}; - -class WorkerPolyfillPool { - static create() { - return new WorkerPolyfillPool(); - } - - async postMessage(data: LassoWorkerInput): Promise { - return new Promise((resolve, reject) => { - try { - const selectedElementIds = updateSelection(data); - resolve(selectedElementIds); - } catch (error) { - reject(error); - } - }); - } - - clear() { - // no-op for polyfill + this.worker?.terminate(); } } diff --git a/packages/excalidraw/lasso/lasso-worker-polyfill.ts b/packages/excalidraw/lasso/lasso-worker-polyfill.ts new file mode 100644 index 000000000..2dfd04e58 --- /dev/null +++ b/packages/excalidraw/lasso/lasso-worker-polyfill.ts @@ -0,0 +1,28 @@ +import { updateSelection } from "./utils"; + +import type { LassoWorkerInput, LassoWorkerOutput } from "./types"; + +export class LassoWorkerPolyfill { + public onmessage: ((event: MessageEvent) => void) | null = + null; + public onerror: ((event: ErrorEvent) => void) | null = null; + + postMessage(data: LassoWorkerInput) { + try { + // run asynchronously to simulate a real worker + setTimeout(() => { + const selectedElementIds = updateSelection(data); + const messageEvent = { + data: selectedElementIds, + } as MessageEvent; + this.onmessage?.(messageEvent); + }, 0); + } catch (error) { + this.onerror?.(new ErrorEvent("error", { error })); + } + } + + terminate() { + // no-op for polyfill + } +}