diff --git a/frontend/src/components/Flow/layout.check.ts b/frontend/src/components/Flow/layout.check.ts index 8876f68..2ca64d3 100644 --- a/frontend/src/components/Flow/layout.check.ts +++ b/frontend/src/components/Flow/layout.check.ts @@ -14,6 +14,20 @@ import assert from "node:assert/strict" // @ts-expect-error the runtime has it, the DOM types say it is not removable. globalThis.self = undefined +// A page runs ELK in a worker Vite builds (`?worker`). Here the same build +// runs in-thread, as the fake worker it exports outside a worker. +// @ts-expect-error the worker build ships without types. +const { Worker: InThread } = await import("elkjs/lib/elk-worker.min.js") +// @ts-expect-error bun's global, which the DOM types do not know. +Bun.plugin({ + name: "elk in-thread", + setup: (build: { module: (id: string, load: () => object) => void }) => + build.module("elkjs/lib/elk-worker.min.js?worker", () => ({ + exports: { default: InThread }, + loader: "object", + })), +}) + const { layoutGraph, nodeHeight, portFraction, PORT_SPAN } = await import( "./layout" ) diff --git a/frontend/src/components/Flow/layout.ts b/frontend/src/components/Flow/layout.ts index 61ca7cb..e523bd3 100644 --- a/frontend/src/components/Flow/layout.ts +++ b/frontend/src/components/Flow/layout.ts @@ -384,14 +384,20 @@ function wrapWideRanks(placed: Map, ids: string[]): Wrap[] { * The layout engine, fetched the first time a flow needs laying out. * * Its own chunk: ELK is a compiled Java library and weighs more than the rest - * of the canvas put together, so nothing but this route ever loads it. + * of the canvas put together, so nothing but this route ever loads it. And + * its own thread: a phone lays the Demo house out eight times over, about + * half a second each, which on the page would freeze it for seconds. */ let engine: Promise<{ layout: (graph: ElkNode) => Promise }> | null = null function elk() { - engine ??= import("elkjs/lib/elk.bundled.js").then( - (module) => new module.default(), + engine ??= Promise.all([ + import("elkjs/lib/elk-api.js"), + import("elkjs/lib/elk-worker.min.js?worker"), + ]).then( + ([api, worker]) => + new api.default({ workerFactory: () => new worker.default() }), ) return engine }