Skip to content

[Bug]: Multi-threaded init falls back to single-thread when web-ifc is loaded as an ES module (document.currentScript is undefined) #2068

Description

@jurassicparkicecream

What happened?

When crossOriginIsolated is true and web-ifc is loaded as an ES module (i.e. through any modern bundler — Vite, Rollup, esbuild, webpack ESM), IfcAPI.Init() never completes the multi-threaded path. Since #1946 it no longer hangs forever, but it always burns the full MT_INIT_TIMEOUT_MS (10 s) and then falls back to single-threaded — so multi-threading is effectively unavailable to ESM consumers.

Root cause — two independent defects

1. The pthread worker receives undefined as its script URL.

The generated bootstrap derives its own script URL from document.currentScript, which is always null for ES modules per spec:

// dist/web-ifc-api.js (0.0.77)
_scriptName = globalThis.document?.currentScript?.src   // undefined for ES modules

That produces new Worker(undefined). The browser resolves it to the literal path /undefined, receives the app's HTML 404 page, and the worker dies with:

Uncaught SyntaxError: Unexpected token '<'

2. The pthread worker is not created as a module.

// dist/web-ifc-api.js (0.0.77)
new Worker(pthreadMainJs, { name: "em-pthread" })   // no { type: "module" }

Even with a correct URL it then fails to parse ESM content:

Uncaught SyntaxError: Cannot use import statement outside a module

Defect 1 is fixable in the hand-written TypeScript (PR below). Defect 2 lives in Emscripten-generated glue code and can only be addressed from the build/toolchain side.

Relation to existing tickets

This is not #1702 being left unfixed — #1779 correctly fixed that one. It concerned a separate web-ifc-mt.worker.js resolved through locateFile. Since then the Emscripten output changed: 0.0.77 ships no separate worker file at all. The pthread worker now bootstraps from the main script URL, a path that locateFile does not govern. So the same user-visible symptom returned through a different mechanism.

Possibly relevant: #1779 also dropped --cors.opener-policy same-origin --cors.embedder-policy require-cor from the dev script, so the local dev server no longer runs cross-origin-isolated and the MT path isn't exercised there anymore. Restoring those flags (or a small CI check) would likely catch this class of regression.

Proposed fix for defect 1

Pass mainScriptUrlOrBlob: import.meta.url into the WebIFCWasm({...}) options. The generated bootstrap already prefers mainScriptUrlOrBlob over document.currentScript, and import.meta.url is correctly populated for ES modules.

Reproduction

  1. Any Vite (or other ESM bundler) app importing web-ifc.
  2. Serve it with COOP/COEP headers so that crossOriginIsolated === true.
  3. Call IfcAPI.Init().
  4. Observe the worker 404 / SyntaxError in the console, then the 10 s timeout and fallback to single-threaded.

Version

0.0.77 (current npm latest)

What browsers are you seeing the problem on?

Chrome (Windows)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions