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
Extract shared code from the worker entry.
Configure the bundler to place common libraries into their own chunk (e.g., using Rollup’smanualChunks). 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.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
- ब्राउझर अपडेट्स – module-worker हाताळणीबाबत काही उल्लेख असल्यास Safari च्या रिलीज नोट्सवर लक्ष ठेवा.
- बंडलर कम्युनिटी पॅचेस – Vite, Rollup आणि इतर साधने हा बग ट्रिगर करणारा पॅटर्न टाळण्यासाठी चेतावणी (warnings) किंवा स्वयंचलित चंकिंग स्ट्रॅटेजीज (automatic chunking strategies) आणू शकतात.
- टेस्टिंग पद्धती – रिलीज करण्यापूर्वी Safari वर वास्तविक मीडिया फाइल्स आणि फुल-स्टॅक वर्कर टेस्ट्सचा समावेश केल्यास ही 'सायलेंट फेल्युअर' (silent failure) लवकर शोधता येईल.
मुख्य निष्कर्ष
जर तुमच्या Safari वापरकर्त्यांना स्पष्ट न होणारे वर्कर-संबंधित दोष (failures) जाणवत असतील, तर कोणताही नॉन-वर्कर बंडल वर्करच्या एन्ट्री स्क्रिप्टला (entry script) इम्पोर्ट करत नाही ना, याची तपासणी करा. डबल एक्झिक्यूशन बगमुळे 'सिंगलटन स्टेट' (singleton state) शांतपणे विस्कळीत होते, परंतु शेअर केलेला कोड एन्ट्री पॉइंटमधून बाहेर काढल्यास किंवा एन्ट्रीला एका 'थिन री-एक्सपोर्ट' (thin re-export) मध्ये रूपांतरित केल्यास, ब्राउझर फिक्सची वाट न पाहता योग्य वर्तन पुन्हा प्राप्त करता येते.
