Safari ਦੇ JavaScript engine ਵਿੱਚ ਇੱਕ ਲੁਕਿਆ ਹੋਇਆ ਨੁਕਸ ਹੈ: ਜਦੋਂ ਕਿਸੇ ਮੋਡਿਊਲ-ਸਟਾਈਲ Web Worker ਦੀ entry script ਬੰਡਲ ਵਿੱਚ ਕਿਤੇ ਹੋਰ import ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ Safari ਉਸ entry script ਨੂੰ ਦੂਜੀ ਵਾਰ ਚਲਾਉਂਦਾ ਹੈ। ਇਹ ਦੁਹਰਾਅ (duplicate run) singleton state ਨੂੰ ਤੋੜ ਦਿੰਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਉਹ workers ਖ਼ਰਾਬ ਹੋ ਜਾਂਦੇ ਹਨ ਜੋ shared caches ਜਾਂ single-instance objects 'ਤੇ ਨਿਰਭਰ ਕਰਦੇ ਹਨ।
ਇਹ ਸਮੱਸਿਆ ਇੱਕ ਬ੍ਰਾਊਜ਼ਰ-ਅਧਾਰਤ ਵੀਡੀਓ-ਪ੍ਰੋਸੈਸਿੰਗ ਐਪ ਬਣਾਉਂਦੇ ਸਮੇਂ ਸਾਹਮਣੇ ਆਈ, ਜੋ ProRes ਫਾਈਲਾਂ ਨੂੰ ਡੀਕੋਡ ਕਰਨ ਲਈ Web Workers ਦੀ ਵਰਤੋਂ ਕਰਦੀ ਹੈ। Chrome ਅਤੇ Firefox ਨੇ ਬਿਨਾਂ ਕਿਸੇ ਸਮੱਸਿਆ ਦੇ ਕੋਡ ਨੂੰ ਸੰਭਾਲ ਲਿਆ, ਪਰ Safari ਵੀਡੀਓ ਲੋਡ ਕਰਨ ਵਿੱਚ ਲਗਾਤਾਰ ਅਸਫਲ ਰਿਹਾ। ਕੰਸੋਲ ਨੇ ਸਿਰਫ ਇੱਕ ਆਮ “cannot read video” ਐਰਰ ਦੱਸਿਆ, ਜਦੋਂ ਕਿ ਅਸਲ ਕਾਰਨ worker ਦਾ initialization code ਦੋ ਵਾਰ ਚੱਲਣਾ ਸੀ, ਜਿਸ ਨਾਲ ਮੈਮਰੀ ਵਿੱਚ ਉਸੇ ਮੋਡਿਊਲ ਦੀਆਂ ਦੋ ਸੁਤੰਤਰ ਕਾਪੀਆਂ ਬਣ ਗਈਆਂ ਸਨ।
ਇਹ ਬੱਗ (bug) ਕਿਵੇਂ ਪ੍ਰਗਟ ਹੁੰਦਾ ਹੈ
ਆਧੁਨਿਕ ਬੰਡਲਰ (Vite, Rollup, ਆਦਿ) ਅਕਸਰ shared utilities ਨੂੰ worker ਦੀ entry file ਵਿੱਚ ਲਿਆਉਂਦੇ ਹਨ ਤਾਂ ਜੋ lazy-loaded chunks ਉਸ ਕੋਡ ਨੂੰ entry point ਤੋਂ ਵਾਪਸ import ਕਰ ਸਕਣ। ਉਹਨਾਂ ਬ੍ਰਾਊਜ਼ਰਾਂ ਵਿੱਚ ਜੋ standard module loader ਵਿਵਹਾਰ ਦੀ ਪਾਲਣਾ ਕਰਦੇ ਹਨ, ਇੱਕ ਵਾਰ entry module instantiate ਹੋਣ ਤੋਂ ਬਾਅਦ, loader ਕਿਸੇ ਵੀ ਅਗਲੇ import ਲਈ ਉਹੀ ਮੋਡਿਊਲ object ਵਾਪਸ ਕਰ ਦਿੰਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਦੂਜੀ ਵਾਰ ਚੱਲਣ ਤੋਂ ਰੋਕਿਆ ਜਾਂਦਾ ਹੈ।
Safari ਇਸ ਉਮੀਦ ਤੋਂ ਵੱਖਰਾ ਹੈ। ਜਦੋਂ ਕੋਈ lazy-loaded chunk worker ਦੀ entry file ਨੂੰ import ਕਰਦਾ ਹੈ, ਤਾਂ Safari ਉਸ import ਨੂੰ ਇੱਕ ਨਵੇਂ ਮੋਡਿਊਲ ਦੀ ਬੇਨਤੀ ਵਜੋਂ ਮੰਨਦਾ ਹੈ ਅਤੇ entry script ਨੂੰ ਦੁਬਾਰਾ ਚਲਾਉਂਦਾ ਹੈ। ਇਸਦਾ ਨਤੀਜਾ ਇਹ ਹੁੰਦਾ ਹੈ ਕਿ ਉੱਥੇ ਪਰਿਭਾਸ਼ਿਤ ਹਰ variable, class, ਜਾਂ singleton ਦੀਆਂ ਦੋ ਵੱਖ-ਵੱਖ instances ਬਣ ਜਾਂਦੀਆਂ ਹਨ।
ਜਦੋਂ entry ਦੋ ਵਾਰ ਚੱਲਦੀ ਹੈ ਤਾਂ ਕੀ ਖ਼ਰਾਬ ਹੁੰਦਾ ਹੈ
- Singletons ਅਤੇ caches ਹੁਣ ਡਾਟਾ ਸਾਂਝਾ ਨਹੀਂ ਕਰਦੇ; ਇੱਕ ਕਾਪੀ ਖਾਲੀ cache ਦੇਖਦੀ ਹੈ ਜਦੋਂ ਕਿ ਦੂਜੀ ਇਸਨੂੰ ਭਰਦੀ ਹੈ।
- Registries (ਉਦਾਹਰਨ ਲਈ, message handlers ਦੀ ਇੱਕ ਸੂਚੀ) ਦੋਵਾਂ instances ਵਿੱਚ ਵੰਡੀਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਜਿਸ ਨਾਲ ਇੱਕ ਪਾਸਾ ਪ੍ਰਭਾਵਸ਼ਾਲੀ ਰੂਪ ਵਿੱਚ ਖਾਲੀ ਰਹਿ ਜਾਂਦਾ ਹੈ।
- Event listeners ਦੋ ਵਾਰ ਅਟੈਚ ਕੀਤੇ ਜਾਂਦੇ ਹਨ, ਜਿਸ ਨਾਲ ਸੰਭਾਵੀ ਤੌਰ 'ਤੇ ਡੁਪਲੀਕੇਟ ਹੈਂਡਲਿੰਗ ਜਾਂ ਮੈਮਰੀ ਵਧ (memory bloat) ਹੋ ਸਕਦੀ ਹੈ।
- WebAssembly (WASM) modules ਦੋ ਵਾਰ ਲੋਡ ਹੁੰਦੇ ਹਨ, ਜਿਸ ਨਾਲ bandwidth ਅਤੇ initialization ਸਮੇਂ ਦੀ ਬਰਬਾਦੀ ਹੁੰਦੀ ਹੈ।
- ਇਹ ਅਸਫਲਤਾ ਚੁੱਪਚਾਪ ਹੁੰਦੀ ਹੈ: ਕੋਈ uncaught exception ਨਹੀਂ ਆਉਂਦਾ, ਸਿਰਫ ਉਹ downstream logic ਜੋ ਗੁੰਮ ਹੋ된 state 'ਤੇ ਨਿਰਭਰ ਕਰਦਾ ਹੈ, ਉਹ ਗਲਤ ਤਰੀਕੇ ਨਾਲ ਕੰਮ ਕਰਦਾ ਹੈ।
ਪ੍ਰੋਜੈਕਟ ਵਿੱਚ ਸਮੱਸਿਆ ਦਾ ਪਤਾ ਲਗਾਉਣਾ
ਬਣੀਆਂ ਹੋਈਆਂ assets ਦੇ ਵਿਰੁੱਧ ਇੱਕ ਤੇਜ਼ grep ਇਹ ਦੱਸ ਸਕਦਾ ਹੈ ਕਿ ਕੀ ਕੋਈ chunk worker ਦੀ entry file ਨੂੰ import ਕਰਦਾ ਹੈ:
grep -l 'from"./your.worker-' dist/assets/*.js
ਜੇਕਰ command ਕਿਸੇ ਵੀ ਫਾਈਲ ਦੀ ਸੂਚੀ ਦਿੰਦੀ ਹੈ, ਤਾਂ ਉਹ imports ਸੰਭਾਵਤ ਰੂਪ ਵਿੱਚ Safari ਵਿੱਚ double-run bug ਨੂੰ ਟਰਿਗਰ ਕਰ ਰਹੇ ਹਨ।
ਵਿਹਾਰਕ ਉਪਾਵਾਂ (Practical workarounds)
Worker entry ਤੋਂ shared code ਨੂੰ ਬਾਹਰ ਕੱਢੋ।
ਬੰਡਲਰ ਨੂੰ ਆਮ ਲਾਇਬ੍ਰੇਰੀਆਂ ਨੂੰ ਆਪਣੇ ਖਾਸ chunk ਵਿੱਚ ਰੱਖਣ ਲਈ ਕੌਂਫਿਗਰ ਕਰੋ (ਉਦਾਹਰਨ ਲਈ, Rollup ਦੇmanualChunksਦੀ ਵਰਤੋਂ ਕਰਕੇ)। ਫਿਰ worker ਅਤੇ ਕੋਈ ਵੀ lazy-loaded modules ਉਸ ਤੀਜੀ ਫਾਈਲ ਤੋਂ ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ import ਕਰਦੇ ਹਨ, ਜਿਸ ਨਾਲ worker ਦੇ entry point ਨੂੰ import ਕਰਨ ਦੀ ਲੋੜ ਖਤਮ ਹੋ ਜਾਂਦੀ ਹੈ।ਇੱਕ ਪਤਲੀ (thin) entry file ਦੀ ਵਰਤੋਂ ਕਰੋ।
Worker ਦੀ entry script ਨੂੰ ਇੱਕ ਸਿੰਗਲ ਲਾਈਨ ਤੱਕ ਸੀਮਤ ਕਰ ਦਿਓ ਜੋ ਅਸਲ implementation ਨੂੰ re-exports ਕਰਦੀ ਹੈ:// worker-entry.js import("./main.js");ਜਦੋਂ ਤੱਕ ਕੋਈ ਹੋਰ ਬੰਡਲ
worker-entry.jsਨੂੰ import ਨਹੀਂ ਕਰਦਾ, Safari ਕਦੇ ਵੀ ਦੂਜੀ import ਬੇਨਤੀ ਨਹੀਂ ਦੇਖਦਾ, ਇਸ ਲਈ entry ਸਿਰਫ ਇੱਕ ਵਾਰ ਚੱਲਦੀ ਹੈ।
ਦੋਵੇਂ ਤਰੀਕੇ ਪੂਰੀ ਐਪਲੀਕੇਸ਼ਨ ਵਿੱਚ worker ਦੇ initialization code ਨੂੰ single-tonic ਰੱਖਦੇ ਹਨ।
ਇਹ ਬੱਗ ਕਿਉਂ ਮਹੱਤਵਪੂਰਨ ਹੈ
Web Workers ਭਾਰੀ ਕੰਪਿਊਟੇਸ਼ਨ—ਵੀਡੀਓ इनकोਡਿੰਗ, ਇਮੇਜ ਪ੍ਰੋਸੈਸਿੰਗ, ਕ੍ਰਿਪਟੋਗ੍ਰਾਫੀ—ਨੂੰ main thread ਤੋਂ ਦੂਰ ਕਰਨ ਲਈ ਇੱਕ ਆਮ ਪੈਟਰਨ ਹਨ। ਇੱਕ ਚੁੱਪਚਾਪ state split ਇੱਕ ਬਿਲਕੁਲ ਕਾਰਜਸ਼ੀਲ ਫੀਚਰ ਨੂੰ ਇੱਕ ਅਜਿਹੀ ਅਸਥਿਰ ਅਸਫਲਤਾ ਵਿੱਚ ਬਦਲ ਸਕਦਾ ਹੈ ਜੋ ਸਿਰਫ Safari 'ਤੇ ਦਿਖਾਈ ਦਿੰਦੀ ਹੈ, ਜੋ ਕਿ ਡੈਸਕਟਾਪ ਅਤੇ ਮੋਬਾਈਲ ਡਿਵਾਈਸਾਂ ਦੇ ਇੱਕ ਵੱਡੇ ਹਿੱਸੇ 'ਤੇ ਡਿਫੌਲਟ ਬ੍ਰਾਊਜ਼ਰ ਹੈ। ਕਿਉਂਕਿ ਇਹ ਐਰਰ ਇੱਕ ਆਮ media-load ਅਸਫਲਤਾ ਵਜੋਂ ਸਾਹਮਣੇ ਆਉਂਦੀ ਹੈ, ਡਿਵੈਲਪਰ ਗਲਤ ਲੱਛਣਾਂ ਦਾ ਪਿੱਛਾ ਕਰਨ ਵਿੱਚ ਕਈ ਘੰਟੇ ਬਿਤਾ ਸਕਦੇ ਹਨ।
ਇਹ ਬੱਗ ਇੱਕ ਵਿਆਪਕ ਜੋਖਮ ਨੂੰ ਵੀ ਉਜਾਗਰ ਕਰਦਾ ਹੈ: ਉਹਨਾਂ module-loader semantics 'ਤੇ ਨਿਰਭਰ ਕਰਨਾ ਜੋ ਬ੍ਰਾਊਜ਼ਰਾਂ ਵਿੱਚ ਇੱਕਸਾਰ ਰੂਪ ਵਿੱਚ ਲਾਗੂ ਨਹੀਂ ਕੀਤੇ ਗਏ ਹਨ। ਜਦੋਂ ਇੱਕ ਬੰਡਲਰ ਦੀ optimization strategy ਇੱਕ ਸਿੰਗਲ shared module instance ਨੂੰ ਮੰਨ ਕੇ ਚੱਲਦੀ ਹੈ, ਤਾਂ ਕੋਈ ਵੀ ਵਿਚਲਣ ਉਸ ਅਨੁਮਾਨ ਨੂੰ ਤੋੜ ਸਕਦਾ ਹੈ।
ਵਿਰੋਧੀ ਵਿਚਾਰ ਅਤੇ ਖੁੱਲ੍ਹੇ ਸਵਾਲ
Safari ਦਾ ਵਿਵਹਾਰ ਆਪਣੇ ਮੋਡਿਊਲ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਨਿਯਮਾਂ ਦੇ ਅਨੁਕੂਲ ਹੈ, ਜੋ ਕਿ workers ਨਾਲ ਜੁੜੇ edge cases ਵਿੱਚ spec ਤੋਂ ਥੋੜ੍ਹੇ ਜਿਹੇ ਵੱਖਰੇ ਹਨ। ਕੁਝ ਡਿਵੈਲਪਰਾਂ ਦਾ ਤਰਕ ਹੈ ਕਿ ਬੰਡਲਰਾਂ ਨੂੰ worker ਦੀ entry file ਵਿੱਚ shared code ਰੱਖਣ ਤੋਂ ਬਿਲਕੁਲ ਬਚਣਾ ਚਾਹੀਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਇਹ ਮੁੱਦਾ ਬ੍ਰਾਊਜ਼ਰ ਦੇ ਨੁਕਸ ਦੀ ਬਜਾਏ build-time ਅਨੁਸ਼ਾਸਨ ਦਾ ਮਾਮਲਾ ਬਣ ਜਾਂਦਾ ਹੈ। ਦੂਜੇ ਲੋਕ ਇਹ ਦੱਸਦੇ ਹਨ ਕਿ Safari ਦਾ ਇਹ ਵਿਚਲਣ ਦਸਤਾਵੇਜ਼ੀ (documented) ਨਹੀਂ ਹੈ, ਜਿਸ ਨਾਲ ਡਿਵੈਲਪਰਾਂ ਕੋਲ ਇਸਦਾ ਅਨੁਮਾਨ ਲਗਾਉਣ ਦਾ ਕੋਈ ਭਰੋਸੇਯੋਗ ਤਰੀਕਾ ਨਹੀਂ ਬਚਦਾ।
Apple ਨੇ ਜਨਤਕ ਤੌਰ 'ਤੇ ਇਸ ਸਮੱਸਿਆ ਨੂੰ ਸਵੀਕਾਰ ਨਹੀਂ ਕੀਤਾ ਹੈ, ਅਤੇ ਇਸਦੇ ਸੁਧਾਰ ਲਈ ਕੋਈ ਜਾਣਿਆ-ਪਛਾਣਿਆ ਸਮਾਂ ਨਹੀਂ ਹੈ। ਜਦੋਂ ਤੱਕ Safari ਆਪਣੇ loader ਨੂੰ ਨਹੀਂ ਬਦਲਦਾ, ਉਦੋਂ ਤੱਕ ਆਪਣੇ ਬੰਡਲ ਨੂੰ ਮੁੜ-ਸੰਰਚਿਤ ਕਰਨ ਜਾਂ ਆਪਣੇ CI pipelines ਵਿੱਚ detection logic ਜੋੜਨ ਦੀ ਜ਼ਿੰਮੇਵਾਰੀ ਡਿਵੈਲਪਰਾਂ ਦੀ ਹੀ ਰਹੇਗੀ।
ਅੱਗੇ ਕੀ ਦੇਖਣਾ ਹੈ
- ਬ੍ਰਾਊਜ਼ਰ ਅੱਪਡੇਟਸ – module-worker ਹੈਂਡਲਿੰਗ ਬਾਰੇ ਕਿਸੇ ਵੀ ਜ਼ਿਕਰ ਲਈ Safari ਰਿਲੀਜ਼ ਨੋਟਸ 'ਤੇ ਨਜ਼ਰ ਰੱਖੋ।
- ਬੰਡਲਰ ਕਮਿਊਨਿਟੀ ਪੈਚਸ – Vite, Rollup, ਅਤੇ ਹੋਰਾਂ ਵੱਲੋਂ ਉਸ ਪੈਟਰਨ ਤੋਂ ਬਚਣ ਲਈ ਚੇਤਾਵਨੀਆਂ ਜਾਂ ਆਟੋਮੈਟਿਕ ਚੰਕਿੰਗ ਰਣਨੀਤੀਆਂ ਲਿਆਂਦੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ ਜੋ ਇਸ ਬੱਗ ਨੂੰ ਤਰਸ਼ਾਉਂਦੀ ਹੈ।
- ਟੈਸਟਿੰਗ ਅਭਿਆਸ – ਰਿਲੀਜ਼ ਤੋਂ ਪਹਿਲਾਂ Safari 'ਤੇ ਅਸਲ-ਦੁਨੀਆ ਦੀਆਂ ਮੀਡੀਆ ਫਾਈਲਾਂ ਅਤੇ ਫੁੱਲ-ਸਟੈਕ ਵਰਕਰ ਟੈਸਟਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਨਾਲ ਇਸ ਚੁੱਪ ਰਹਿਣ ਵਾਲੀ ਅਸਫਲਤਾ ਨੂੰ ਜਲਦੀ ਫੜਿਆ ਜਾ ਸਕਦਾ ਹੈ।
ਮੁੱਖ ਗੱਲ
ਜੇਕਰ ਤੁਹਾਡੇ Safari ਉਪਭੋਗਤਾ ਅਣਸਪਸ਼ਟ ਵਰਕਰ-ਸਬੰਧਤ ਅਸਫਲਤਾਵਾਂ ਦਾ ਸਾਹਮਣਾ ਕਰਦੇ ਹਨ, ਤਾਂ ਚੈੱਕ ਕਰੋ ਕਿ ਕੀ ਕੋਈ non-worker ਬੰਡਲ ਵਰਕਰ ਦੀ entry script ਨੂੰ ਇੰਪੋਰਟ ਕਰ ਰਿਹਾ ਹੈ। ਡਬਲ ਐਗਜ਼ੀਕਿਊਸ਼ਨ ਬੱਗ ਚੁੱਪਚਾਪ singleton state ਨੂੰ ਤਬਾਹ ਕਰ ਦਿੰਦਾ ਹੈ, ਪਰ ਸਾਂਝੇ ਕੋਡ ਨੂੰ entry point ਤੋਂ ਬਾਹਰ ਕੱਢਣ ਜਾਂ entry ਨੂੰ ਇੱਕ thin re-export ਵਿੱਚ ਬਦਲਣ ਨਾਲ ਬ੍ਰਾਊਜ਼ਰ ਫਿਕਸ ਦੀ ਉਡੀਕ ਕੀਤੇ ਬਿਨਾਂ ਸਹੀ ਵਿਵਹਾਰ ਬਹਾਲ ਹੋ ਜਾਂਦਾ ਹੈ।
