/ concept-collection / mesh-studio
concept-collection / mesh-studio
mesh-studio / src / occ / loader.ts
39 lines · 1.4 KBBlameHistoryRaw
1/**
2 * Loads the OpenCASCADE WASM runtime exactly once and caches the promise.
3 *
4 * We deliberately bypass the package's `index.js` wrapper: it does a bare
5 * `import ... from "./opencascade.full.wasm"`, which a URL-based bundler (Vite /
6 * rolldown) cannot resolve. Instead we import the Emscripten factory directly
7 * and hand it the wasm URL through `locateFile` — the `?url` import makes Vite
8 * emit the ~30 MB wasm as a static asset, fetched lazily on first use.
9 */
10import ocFactory from 'opencascade.js/dist/opencascade.full.js'
11import wasmUrl from 'opencascade.js/dist/opencascade.full.wasm?url'
12import type { OpenCascade } from './types'
14type Factory = (module: { locateFile: (path: string) => string }) => Promise<OpenCascade>
16let cached: Promise<OpenCascade> | null = null
18export function loadOpenCascade(onStatus?: (msg: string) => void): Promise<OpenCascade> {
19 if (cached) return cached
20 onStatus?.('Loading CAD engine (OpenCASCADE, ~30 MB)…')
21 const factory = ocFactory as unknown as Factory
22 cached = factory({
23 locateFile: (path: string) => (path.endsWith('.wasm') ? wasmUrl : path),
24 })
25 .then((oc: OpenCascade) => {
26 onStatus?.('CAD engine ready')
27 return oc
28 })
29 .catch((e: unknown) => {
30 cached = null // allow a retry on the next action
31 throw e
32 })
33 return cached
36/** True once the runtime has finished loading in this session. */
37export function isLoaded(): boolean {
38 return cached !== null