Safari’s JavaScript engine has a hidden flaw: when a module-style Web Worker’s entry script is imported anywhere else in the bundle, Safari executes that entry script a second time. The duplicate run breaks singleton state, silently sabotaging workers that rely on shared caches or single-instance objects.

The problem surfaced while developing a browser-based video-processing app that uses Web Workers to decode ProRes files. Chrome and Firefox handled the code without incident, but Safari consistently failed to load the video. The console only reported a generic “cannot read video” error, while the real culprit was the worker’s initialization code running twice and leaving two independent copies of the same module in memory.

How the bug manifests

Modern bundlers (Vite, Rollup, etc.) often pull shared utilities into the worker’s entry file so that lazy-loaded chunks can import that code back from the entry point. In browsers that follow the standard module loader behavior, once the entry module is instantiated the loader returns the same module object to any subsequent import, preventing a second execution.

Safari diverges from that expectation. When a lazy-loaded chunk imports the worker’s entry file, Safari treats the import as a fresh module request and re-executes the entry script. The result is two separate instances of every variable, class, or singleton defined there.

What breaks when the entry runs twice

  • Singletons and caches no longer share data; one copy sees an empty cache while the other populates it.
  • Registries (for example, a list of message handlers) end up split between the two instances, leaving one side effectively empty.
  • Event listeners are attached twice, potentially causing duplicate handling or memory bloat.
  • WebAssembly (WASM) modules load two times, wasting bandwidth and initialization time.
  • The failure is silent: no uncaught exception is thrown, only downstream logic that depends on the missing state misbehaves.

Detecting the issue in a project

A quick grep against the built assets can reveal whether any chunk imports the worker’s entry file:

grep -l 'from"./your.worker-' dist/assets/*.js

If the command lists any files, those imports are likely triggering the double-run bug in Safari.

Practical workarounds

  1. Extract shared code from the worker entry.
    Configure the bundler to place common libraries into their own chunk (e.g., using Rollup’s manualChunks). Both the worker and any lazy-loaded modules then import the library from that third file, eliminating the need to import the worker’s entry point.

  2. Use a thin entry file.
    Reduce the worker’s entry script to a single line that re-exports the real implementation:

    // worker-entry.js
    import("./main.js");
    

    As long as no other bundle imports worker-entry.js, Safari never sees a second import request, so the entry runs only once.

Both approaches keep the worker’s initialization code single-tonic across the entire application.

Why the bug matters

Web Workers are a common pattern for off-loading heavy computation—video encoding, image processing, cryptography—away from the main thread. A silent state split can turn a perfectly functional feature into an intermittent failure that only appears on Safari, the default browser on a large share of desktop and mobile devices. Because the error surfaces as a generic media-load failure, developers may spend hours chasing the wrong symptom.

The bug also highlights a broader risk: relying on module-loader semantics that are not uniformly implemented across browsers. When a bundler’s optimization strategy assumes a single shared module instance, any deviation can break that assumption.

Counter-point and open questions

Safari’s behavior aligns with its own module resolution rules, which differ subtly from the spec in edge cases involving workers. Some developers argue that bundlers should avoid placing shared code in a worker’s entry file altogether, making the issue a matter of build-time discipline rather than a browser defect. Others point out that Safari’s deviation is not documented, leaving developers without a reliable way to anticipate it.

Apple has not publicly acknowledged the problem, and there is no known timeline for a fix. Until Safari changes its loader, the onus remains on developers to restructure their bundles or add detection logic to their CI pipelines.

What to watch next

  • Sasisho za kivinjari – Fuatilia maelezo ya toleo la Safari kwa orodha yoyote inayotaja ushughulikiaji wa module-worker.
  • Marekebisho ya jamii ya bundler – Vite, Rollup, na nyinginezo zinaweza kuanzisha onyo au mbinu za kugawa vipande (chunking) kiotomatiki ili kuepuka mfumo unaochochea hitilafu hiyo.
  • Mbinu za upimaji – Kujumuisha faili za media za ulimwengu halisi na majaribio ya worker ya full-stack kwenye Safari kabla ya toleo kunaweza kugundua hitilafu hiyo ya kimyakimya mapema.

Muhtasari

Ikiwa watumiaji wako wa Safari wanapata hitilafu zisizoelezeka zinazohusiana na worker, angalia ikiwa kuna bundle yoyote isiyo ya worker inayofanya import ya script ya kuingilia (entry script) ya worker. Hitilafu ya utekelezaji mara mbili inaharibu kimyakimya hali ya singleton, lakini kuhamisha kodi inayoshirikiwa nje ya nukta ya kuingilia (entry point) au kufupisha nukta ya kuingilia kuwa re-export nyepesi kurejesha utendaji sahihi bila kusubiri marekebisho ya kivinjari.