Safari యొక్క JavaScript ఇంజిన్‌లో ఒక దాగి ఉన్న లోపం ఉంది: ఒక module-style Web Worker యొక్క entry script బండిల్‌లో ఎక్కడైనా ఇంపోర్ట్ చేయబడితే, Safari ఆ entry scriptను రెండోసారి ఎగ్జిక్యూట్ చేస్తుంది. ఈ డూప్లికేట్ రన్ singleton stateను దెబ్బతీస్తుంది, దీనివల్ల షేర్డ్ క్యాచెస్ (shared caches) లేదా సింగిల్-ఇన్‌స్టాన్స్ ఆబ్జెక్ట్‌లపై ఆధారపడే వర్కర్లు నిశ్శబ్దంగా దెబ్బతింటాయి.

ProRes ఫైల్‌లను డీకోడ్ చేయడానికి Web Workersను ఉపయోగించే బ్రౌజర్ ఆధారిత వీడియో-ప్రాసెసింగ్ యాప్‌ను డెవలప్ చేస్తున్నప్పుడు ఈ సమస్య వెలుగులోకి వచ్చింది. Chrome మరియు Firefox ఎటువంటి ఇబ్బంది లేకుండా కోడ్‌ను హ్యాండిల్ చేశాయి, కానీ Safari నిరంతరం వీడియోను లోడ్ చేయడంలో విఫలమైంది. కన్సోల్ కేవలం సాధారణ “cannot read video” ఎర్రర్‌ను మాత్రమే చూపించింది, కానీ అసలు కారణం ఏమిటంటే వర్కర్ యొక్క ఇనిషియలైజేషన్ కోడ్ రెండుసార్లు రన్ అవ్వడం మరియు మెమరీలో ఒకే మాడ్యూల్‌కు రెండు స్వతంత్ర కాపీలను వదిలివేయడం.

ఈ బగ్ ఎలా కనిపిస్తుంది

ఆధునిక బండలర్లు (Vite, Rollup, మొదలైనవి) తరచుగా వర్కర్ యొక్క entry ఫైల్‌లోకి షేర్డ్ యుటిలిటీలను తీసుకువస్తాయి, తద్వారా lazy-loaded chunks ఆ కోడ్‌ను తిరిగి entry పాయింట్ నుండి ఇంపోర్ట్ చేసుకోగలవు. స్టాండర్డ్ module loader ప్రవర్తనను అనుసరించే బ్రౌజర్‌లలో, ఒకసారి entry మాడ్యూల్ ఇన్‌స్టాంటియేట్ అయిన తర్వాత, లోడర్ తదుపరి ఇంపోర్ట్‌లకు అదే మాడ్యూల్ ఆబ్జెక్ట్‌ను తిరిగి ఇస్తుంది, దీనివల్ల రెండోసారి ఎగ్జిక్యూషన్ జరగదు.

Safari ఆ అంచనాకు భిన్నంగా వ్యవహరిస్తుంది. ఒక lazy-loaded chunk వర్కర్ యొక్క entry ఫైల్‌ను ఇంపోర్ట్ చేసినప్పుడు, Safari ఆ ఇంపోర్ట్‌ను ఒక కొత్త మాడ్యూల్ రిక్వెస్ట్‌గా పరిగణించి, entry scriptను మళ్లీ ఎగ్జిక్యూట్ చేస్తుంది. దీని ఫలితంగా అక్కడ నిర్వచించబడిన ప్రతి వేరియబుల్, క్లాస్ లేదా సింగిల్టన్ యొక్క రెండు వేర్వేరు ఇన్‌స్టాన్స్‌లు ఏర్పడతాయి.

entry రెండుసార్లు రన్ అయినప్పుడు ఏవి దెబ్బతింటాయి

  • Singletons మరియు caches ఇకపై డేటాను పంచుకోవు; ఒక కాపీ ఖాళీ క్యాచ్‌ను చూస్తుంటే, మరొకటి దానిని నింపుతుంది.
  • Registries (ఉదాహరణకు, మెసేజ్ హ్యాండ్లర్ల జాబితా) రెండు ఇన్‌స్టాన్స్‌ల మధ్య విడిపోతాయి, దీనివల్ల ఒక వైపు ఖాళీగా ఉండిపోతుంది.
  • Event listeners రెండుసార్లు అటాచ్ చేయబడతాయి, ఇది డూప్లికేట్ హ్యాండ్లింగ్‌కు లేదా మెమరీ పెరగడానికి (memory bloat) కారణం కావచ్చు.
  • WebAssembly (WASM) modules రెండుసార్లు లోడ్ అవుతాయి, దీనివల్ల బ్యాండ్‌విడ్త్ మరియు ఇనిషియలైజేషన్ సమయం వృథా అవుతాయి.
  • ఈ వైఫల్యం నిశ్శబ్దంగా జరుగుతుంది: ఎటువంటి uncaught exception రాదు, కేవలం ఆ మిస్సింగ్ స్టేట్‌పై ఆధారపడే downstream logic మాత్రమే సరిగ్గా పనిచేయదు.

ప్రాజెక్ట్‌లో ఈ సమస్యను గుర్తించడం

బిల్డ్ చేసిన అసెట్స్‌పై ఒక వేగవంతమైన grep కమాండ్ ద్వారా ఏదైనా chunk వర్కర్ యొక్క entry ఫైల్‌ను ఇంపోర్ట్ చేస్తుందో లేదో తెలుసుకోవచ్చు:

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

ఒకవేళ ఆ కమాండ్ ఏవైనా ఫైళ్లను జాబితా చేస్తే, ఆ ఇంపోర్ట్‌లు Safariలో డబుల్-రన్ బగ్ ట్రిగ్గర్ చేసే అవకాశం ఉంది.

ఆచరణాత్మక పరిష్కార మార్గాలు

  1. వర్కర్ entry నుండి షేర్డ్ కోడ్‌ను వేరు చేయండి.
    సాధారణ లైబ్రరీలను వాటి స్వంత chunkలో ఉంచడానికి బండలర్‌ను కాన్ఫిగర్ చేయండి (ఉదాహరణకు, Rollup యొక్క manualChunks ఉపయోగించి). అప్పుడు వర్కర్ మరియు ఏదైనా lazy-loaded మాడ్యూల్స్ ఆ మూడవ ఫైల్ నుండి లైబ్రరీని ఇంపోర్ట్ చేస్తాయి, దీనివల్ల వర్కర్ యొక్క entry పాయింట్‌ను ఇంపోర్ట్ చేయాల్సిన అవసరం ఉండదు.

  2. ఒక సన్నని (thin) entry ఫైల్‌ను ఉపయోగించండి.
    వర్కర్ యొక్క entry scriptను అసలు ఇంప్లిమెంటేషన్‌ను రీ-ఎక్స్‌పోర్ట్ చేసే ఒకే ఒక లైన్‌కు తగ్గించండి:

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

    worker-entry.jsను వేరే ఏ బండిల్ ఇంపోర్ట్ చేయనంత వరకు, Safari రెండో ఇంపోర్ట్ రిక్వెస్ట్‌ను చూడదు, కాబట్టి entry కేవలం ఒకేసారి రన్ అవుతుంది.

ఈ రెండు పద్ధతులు వర్కర్ యొక్క ఇనిషియలైజేషన్ కోడ్‌ను మొత్తం అప్లికేషన్ అంతటా సింగిల్-టానిక్‌గా ఉంచుతాయి.

ఈ బగ్ ఎందుకు ముఖ్యమైనది

భారీ గణనలను (heavy computation)—వీడియో ఎన్‌కోడింగ్, ఇమేజ్ ప్రాసెసింగ్, క్రిప్టోగ్రఫీ—మెయిన్ థ్రెడ్ నుండి వేరు చేయడానికి Web Workers ఒక సాధారణ పద్ధతి. నిశ్శబ్దంగా జరిగే స్టేట్ స్ప్లిట్ (state split), ఒక చక్కగా పనిచేసే ఫీచర్‌ను కేవలం Safariలో మాత్రమే కనిపించే అప్పుడప్పుడు వచ్చే వైఫల్యంగా మార్చగలదు, ఇది డెస్క్‌టాప్ మరియు మొబైల్ పరికరాల్లో పెద్ద ఎత్తున వాడబడే బ్రౌజర్. ఈ ఎర్రర్ ఒక సాధారణ మీడియా-లోడ్ ఫెయిల్యూర్ లాగా కనిపిస్తుంది కాబట్టి, డెవలపర్లు తప్పు లక్షణాల వెనుక గంటల కొద్దీ సమయాన్ని వృథా చేయవచ్చు.

ఈ బగ్ ఒక విస్తృతమైన ప్రమాదాన్ని కూడా ఎత్తి చూపుతుంది: బ్రౌజర్‌లన్నింటిలో ఏకరీతిగా అమలు చేయబడని module-loader సెమాంటిక్స్‌పై ఆధారపడటం. ఒక బండలర్ యొక్క ఆప్టిమైజేషన్ స్ట్రాటజీ ఒకే షేర్డ్ మాడ్యూల్ ఇన్‌స్టాన్స్‌ను ఊహిస్తున్నప్పుడు, ఏ చిన్న మార్పు అయినా ఆ ఊహను దెబ్బతీస్తుంది.

ప్రతివాదన మరియు పెండింగ్‌లో ఉన్న ప్రశ్నలు

Safari యొక్క ప్రవర్తన దాని స్వంత module resolution నియమాలతో సరిపోలుతుంది, ఇవి వర్కర్లకు సంబంధించిన ఎడ్జ్ కేసులలో స్పెక్‌తో స్వల్పంగా భిన్నంగా ఉంటాయి. బండలర్లు వర్కర్ యొక్క entry ఫైల్‌లో షేర్డ్ కోడ్‌ను ఉంచడాన్ని పూర్తిగా నివారించాలని, తద్వారా ఈ సమస్య బ్రౌజర్ లోపం కంటే బిల్డ్-టైమ్ క్రమశిక్షణకు సంబంధించిన అంశంగా మారుతుందని కొందరు డెవలపర్లు వాదిస్తారు. మరికొందరు Safari యొక్క ఈ మార్పు డాక్యుమెంట్ చేయబడలేదని, దీనిని ముందుగానే ఊహించడానికి డెవలపర్లకు నమ్మకమైన మార్గం లేదని పేర్కొంటారు.

Apple ఈ సమస్యను బహిరంగంగా అంగీకరించలేదు మరియు దీనిని పరిష్కరించడానికి ఎటువంటి సమయపాలన (timeline) తెలియదు. Safari తన లోడర్‌ను మార్చే వరకు, బండిల్‌లను పునర్నిర్మించడం లేదా తమ CI పైప్‌లైన్‌లలో డిటెక్షన్ లాజిక్‌ను జోడించడం అనేది డెవలపర్ల బాధ్యతగా ఉంటుంది.

తదుపరి గమనించవలసినవి

  • బ్రౌజర్ అప్‌డేట్‌లు – module-worker హ్యాండ్లింగ్‌కు సంబంధించి ఏదైనా ప్రస్తావన ఉందేమో చూడటానికి Safari రిలీజ్ నోట్స్‌ను గమనిస్తూ ఉండండి.
  • బండ్లర్ కమ్యూనిటీ ప్యాచెస్ – ఈ బగ్ కలిగించే ప్యాటర్న్‌ను నివారించడానికి Vite, Rollup మరియు ఇతర బండ్లర్లు హెచ్చరికలను లేదా ఆటోమేటిక్ చంకింగ్ వ్యూహాలను పరిచయం చేయవచ్చు.
  • టెస్టింగ్ పద్ధతులు – రిలీజ్ చేయడానికి ముందు Safariలో వాస్తవ ప్రపంచ మీడియా ఫైల్‌లను మరియు ఫుల్-స్టాక్ వర్కర్ టెస్ట్‌లను చేర్చడం ద్వారా ఈ సైలెంట్ ఫెయిలర్‌ను ముందుగానే గుర్తించవచ్చు.

ముఖ్య గమనిక

మీ Safari వినియోగదారులు వివరించలేని వర్కర్-సంబంధిత వైఫల్యాలను ఎదుర్కొంటుంటే, ఏదైనా నాన్-వర్కర్ బండిల్ వర్కర్ యొక్క ఎంట్రీ స్క్రిప్ట్‌ను ఇంపోర్ట్ చేస్తోందో లేదో తనిఖీ చేయండి. ఈ డబుల్ ఎగ్జిక్యూషన్ బగ్ సైలెంట్‌గా singleton stateను దెబ్బతీస్తుంది, కానీ షేర్డ్ కోడ్‌ను ఎంట్రీ పాయింట్ నుండి బయటకు తీయడం లేదా ఎంట్రీని ఒక తక్కువ కోడ్‌తో కూడిన re-exportగా మార్చడం ద్వారా బ్రౌజర్ ఫిక్స్ కోసం వేచి చూడకుండానే సరైన పనితీరును తిరిగి పొందవచ్చు.