प्रत्येक वेब डेव्हलपरला तो अनुभव माहित असतो जेव्हा त्यांचे ॲप्लिकेशन एका नियंत्रित स्टेजिंग एन्व्हायरमेंटमध्ये (staging environment) अगदी व्यवस्थित रेंडर होते. पण एक एम्बेडेड विजेट (embedded widget) रिलीज करणे या आरामाचा पूर्णपणे नाश करते. तुम्ही आता त्या पेजचे आर्किटेक्ट राहत नाही. तुम्ही एक अवांतित पाहुणे आहात, जो अशा DOM मध्ये React ॲप्लिकेशन इंजेक्ट करत आहे ज्यावर तुमचे नियंत्रण नाही, अशा CSS कॅस्केडमध्ये (CSS cascade) ज्याचे लेखक तुम्ही नाही, आणि अशा रनटाइम एन्व्हायरमेंटमध्ये (runtime environment) जे तुमच्या विरोधात काम करू शकते. Clanker Support विजेट तयार करताना आणि रिलीज करताना, आम्हाला असे आढळले की जेव्हा तुमचे कोड दुसऱ्याच्या थीममध्ये चालते, तेव्हा वेब डेव्हलपमेंटमधील सर्व सामान्य गृहितके (assumptions) मोडीत निघतात. होस्ट साइट फॉन्ट साइज रिसेट करू शकते, रिकामे divs लपवू शकते, किंवा असे स्क्रिप्ट लाइफसायकल लागू करू शकते जे तुमची कॉन्फिगरेशन वाचण्यापूर्वीच ती अवैध ठरवते. येथे काही संरक्षणात्मक नियम (defensive rules) आहेत जे आम्ही प्रत्यक्ष अनुभवातून (production blood) शिकलो आहोत.
One File, One Failure Mode
आधुनिक बंडलर्स (bundlers) तुम्हाला कोड स्प्लिटिंग (code splitting) आणि डायनॅमिक इम्पोर्ट्सचा (dynamic imports) मोह दाखवतात. त्यांचा प्रतिकार करा. एक एम्बेडेड विजेट हे सिंगल-फाईल 'Immediately Invoked Function Expression' (IIFE) म्हणून पाठवले पाहिजे. जेव्हा एखादा ग्राहक त्यांच्या टेम्पलेटमध्ये तुमचा स्क्रिप्ट टॅग कॉपी करतो, तेव्हा त्यांना एकाच नेटवर्क रिक्वेस्टची अपेक्षा असते. जर तुमच्या बंडलने एखादी जड पार्सिंग लायब्ररी किंवा लँग्वेज मॉडेल चंक (language model chunk) 'lazy-load' करण्याचा प्रयत्न केला, तर ती फेच (fetch) प्रक्रिया शांतपणे अयशस्वी होऊ शकते. होस्ट साइटवर कडक Content Security Policy, आक्रमक ॲड ब्लॉकर (ad blocker), किंवा असा CDN पाथ असू शकतो जो तुमच्या publicPath गृहितकांशी जुळत नाही. सर्व काही एका IIFE मध्ये आणून, तुम्ही सेकंडरी चंक लोडिंगमधील अनिश्चितता दूर करता. जर एखादी डिपेंडन्सी (dependency) स्वतःच्या अंतर्गत गोष्टी 'lazy-load' करण्याचा आग्रह धरत असेल, तर बिल्ड टाइममध्ये तिला एका हलक्या (lightweight) स्टबमध्ये (stub) बदलून टाका (alias). याचा परिणाम म्हणजे एक सिंगल आर्टिफॅक्ट, एक सिंगल फेल्युअर मोड आणि जेव्हा एखाद्या ग्राहकाच्या साइट मॅनेजरकडून तुटलेल्या चॅट बबलचा स्क्रीनशॉट ईमेल येतो, तेव्हा डीबगिंग करणे खूप सोपे जाते.
The Shadow DOM Leaks Too
डेव्हलपर्स अनेकदा Shadow DOM कडे एक अभेद्य किल्ला म्हणून पाहतात. ते तुमचे सिलेक्टर्स (selectors) होस्ट पेजच्या CSS पासून वेगळे करते, परंतु ते 'inheritance' (वारसा) रोखत नाही. font-family, line-height, color, आणि text-align सारखे गुणधर्म (properties) तुमच्या शॅडो ट्रीमध्ये (shadow tree) अशा प्रकारे प्रवाहित होतात जणू काही तिथे कोणतीही सीमाच नाही. जर एखाद्या Shopify स्टोअरमध्ये ग्लोबल font-family: "Comic Sans MS" घोषित केले असेल, तर जोपर्यंत तुम्ही तुमच्या रूट एलिमेंटवर (root element) प्रत्येक वारसा घेण्यायोग्य (inheritable) प्रॉपर्टी निश्चित करत नाही, तोपर्यंत ते तुमच्या काळजीपूर्वक डिझाइन केलेल्या सपोर्ट विजेटवर परिणाम करेल. तुमच्या स्वतःच्या टायपोग्राफी, स्पेसिंग आणि टेक्स्ट अलाइनमेंटसाठी होस्ट लेव्हलवरच ठोस (concrete) व्हॅल्यूज सेट करा. पालक पेज (parent page) प्रतिकूल आहे असे गृहीत धरा आणि तुम्हाला हव्या असलेल्या सर्व गोष्टी रिसेट करा. Shadow DOM तुमच्या क्लासेसचे (classes) संरक्षण करते, तुमच्या सौंदर्याचे (aesthetics) नाही.
The Empty Div Vanishing Act
या गोष्टीने आम्हाला पूर्णपणे चकित केले. Shopify Dawn सह अनेक लोकप्रिय थीम्समध्ये एक CSS नियम असतो जो निरपराध वाटतो: div:empty { display: none; }. जेव्हा तुमचा विजेट माउंट (mount) होतो, तेव्हा तो सहसा एका अशा होस्ट div ला लक्ष्य करतो जो सुरुवातीला रिकामा असतो. तुमचे JavaScript कार्यान्वित होण्यापूर्वी आणि React नोड हायड्रेट (hydrate) करण्यापूर्वी, तो div अक्षरशः रिकामा असतो. थीमची स्टाईलशीट त्याला लपवते. तुमचा स्क्रिप्ट चालतो, ReactDOM.createRoot कॉल करतो, पण काहीही दिसत नाही. कन्सोलमध्ये कोणतीही एरर येत नाही. तो घटक लेआउटमध्ये अस्तित्वातच राहत नाही. याचे निराकरण थेट आणि स्पष्ट आहे: तुमच्या माउंट पॉइंटला (mount point) display: block !important ही इनलाइन स्टाईल लागू करा. हे नंतर हाताळण्यासाठी तुमच्या CSS-in-JS लायब्ररीवर अवलंबून राहू नका. तुमच्या स्टाईलशीट्स लागू होईपर्यंत, होस्ट थीम आधीच जिंकलेली असते.
Abandon rem for px
सामान्य ॲप्लिकेशनमध्ये, rem सारखे रिलेटिव्ह युनिट्स (relative units) जबाबदार निवड मानली जातात. पण एम्बेडेड विजेटमध्ये, ते एक ओझे (liability) ठरतात. rem व्हॅल्यू तुमच्या विजेटच्या ऐवजी होस्ट डॉक्युमेंटच्या रूट html फॉन्ट साइजच्या आधारावर ठरवली जाते. जर होस्ट पेजने html { font-size: 10px; } सेट केले किंवा जुनी 62.5% ची ट्रिक वापरली, तर तुमचे संपूर्ण टायपोग्राफी आणि स्पेसिंग स्केल कोणतीही सूचना न देता बदलू शकते. एक सोयीस्कर 1.6rem लाईन हाईट 16px पर्यंत कमी होऊ शकते, किंवा तुमचे पॅडिंग (padding) वाचता न येण्याइतके लहान होऊ शकते. तुम्ही होस्टच्या रूट साइजिंगचा अंदाज घेऊ शकत नाही किंवा त्यावर नियंत्रण मिळवू शकत नाही, म्हणून एम्बेडेड विजेटसाठी पिक्सेल (pixels) हे एकमेव प्रामाणिक युनिट आहे. ते आजूबाजूच्या पेजच्या गृहितकां regardless, त्याच भौतिक आकारात रेंडर होतात. जेव्हा तुम्ही दुसऱ्या साइटच्या कॅस्केडमध्ये जगत असता, तेव्हा rem च्या सैद्धांतिक सुलभतेपेक्षा (theoretical accessibility flexibility) px च्या व्यावहारिक विश्वासार्हतेला (practical reliability) प्राधान्य द्या.
Read Your Config Before It Disappears
जर तुम्ही स्क्रिप्ट टॅगवरील data attributes द्वारे तुमच्या विजेटला (widget) कॉन्फिगरेशन पास करत असाल, तर तुम्हाला ते सिंक्रोनसली (synchronously) वाचणे आवश्यक आहे. ब्राउझर document.currentScript प्रदान करतो जेणेकरून स्क्रिप्ट स्वतःच्या टॅगची तपासणी करू शकेल, परंतु हा संदर्भ क्षणभंगुर (ephemeral) असतो. जर तुम्ही DOMContentLoaded किंवा कोणत्याही asynchronous मर्यादेची प्रतीक्षा केली, तर document.currentScript हे null होते. तुमचे कॉन्फिगरेशन नष्ट होते. स्क्रिप्ट एक्झिक्यूशनच्या (execution) अगदी सुरुवातीलाच ते attributes वाचा. API key, widget ID आणि color theme लगेच कॅप्चर करा, त्यांना closure किंवा module variable मध्ये साठवा आणि त्यानंतरच React बूट करण्याची प्रक्रिया सुरू करा.
स्क्रिप्ट URL ला API Origin निवडू द्या
तुमच्या बंडलमध्ये (bundle) प्रोडक्शन API URL हार्डकोड करणे ही एक चूक आहे, ज्याचा परिणाम सर्व वातावरणांमध्ये (environments) दिसून येतो. त्याऐवजी, स्क्रिप्ट एलिमेंटच्या स्वतःच्या src attribute मधून तुमचा API origin मिळवा. जर विजेट https://cdn.staging.example.com/widget.js वरून लोड होत असेल, तर त्याचे API कॉल्स डीफॉल्टनुसार https://api.staging.example.com वर गेले पाहिजेत. जर एखाद्या डेव्हलपरने localhost:3000 वरून सर्व्ह केल्या जाणाऱ्या स्थानिक HTML फाईलमध्ये स्क्रिप्ट टॅग टाकला, तर लोकल बिल्डने विनंत्या (requests) स्थानिक सर्व्हरकडे वळवल्या पाहिजेत. ही पद्धत environment-specific builds, feature flags किंवा एम्बेड वापरकर्त्याकडून मॅन्युअल कॉन्फिगरेशनची गरज काढून टाकते. हे आपोआप काम करते, कारण इन्फ्रास्ट्रक्चरचे स्थान डिलिव्हरीच्या स्थानावरून सूचित होते.
Cache Headers ला Hotfix Lifeline प्रमाणे हाताळा
वापरकर्ते तुमच्या स्क्रिप्ट टॅगची त्यांच्या फूटर टेम्पलेटमध्ये एकदा कॉपी करतात आणि विसरून जातात. तुम्ही पाच हजार व्यापाऱ्यांना ईमेल करून त्यांना व्हर्जन क्वेरी पॅरामीटर (version query parameter) अपडेट करण्यास सांगू शकत नाही. याचा अर्थ असा की तुमचे cache headers हे तुमच्या incident response strategy चा भाग आहेत. तुमच्या विजेट बंडलवर कमी max-age सेट करा, जेणेकरून जेव्हा तुम्ही एखादा महत्त्वाचा फिक्स (critical fix) पाठवाल, तेव्हा तो काही आठवड्यांत नाही तर काही तासांत सर्वत्र पोहोचेल. दीर्घकाळ टिकणाऱ्या कॅश केलेल्या मालमत्तेचा (cached asset) सोयीपेक्षा, हजारो साइट्सवर एखादे बिघडलेले व्हर्जन चालू आहे आणि तुम्ही ते परत घेऊ शकत नाही, हे जाणून घेण्यातील हतबलता जास्त मोठी आहे. CDN ट्रॅफिक खर्च स्वीकारा. तुमचे मानसिक आरोग्य त्यावर अवलंबून आहे.
iframe Embeds साठी तुमचा CSP बदला
जर तुम्ही iframe-आधारित एम्बेडिंग पर्याय देत असाल, तर तुमच्या Content Security Policy साठी मानक वेब ॲप्लिकेशन विचारसरणीच्या उलट विचार करणे आवश्यक आहे. सामान्यतः, clickjacking रोखण्यासाठी तुम्ही framing प्रतिबंधित करू शकता. परंतु विजेटसाठी, तुम्हाला त्याची परवानगी द्यावी लागेल. frame-ancestors * सेट करा जेणेकरून कोणतीही साइट तुमचा iframe होस्ट करू शकेल. त्यानंतर इतर सर्व गोष्टींबाबत अत्यंत कडक बना. त्या iframe पॉलिसीमध्ये script-src, style-src, आणि connect-src कडकपणे लॉक करा. तुम्ही फ्रेमिंग वेक्टरद्वारे स्वतःला जाणीवपूर्वक संपूर्ण वेबसाठी उघडे पाडत आहात, त्यामुळे होस्ट पेजने त्यात फेरफार करण्याचा प्रयत्न केल्यास, iframe मध्ये चालणाऱ्या कोडमध्ये चुकीचे वर्तन करण्यासाठी कोणतीही संधी उरणार नाही याची खात्री तुम्ही केली पाहिजे.
पाहुण्यांची मानसिकता (The Guest Mindset)
एम्बेड्स तयार करणे हे मानक वेब ॲप्लिकेशन्स तयार करण्यापेक्षा वेगळ्या दृष्टिकोनाची मागणी करते. तुमच्या स्वतःच्या ॲपमध्ये, कंटेनर, राउटिंग, बिल्ड पाइपलाइन आणि ग्लोबल स्टाइल्सवर तुमचे नियंत्रण असते. एम्बेडमध्ये, तुमचे काहीही नियंत्रण नसते. होस्ट पेज अनिश्चित, अनेकदा जुने, कधीकधी प्रतिकूल आणि नेहमी तुमच्या नियंत्रणाबाहेर असते. प्रत्येक गृहीतक (assumption) बचावात्मक (defensive) असले पाहिजे. तुम्हाला काय अपेक्षित आहे ते स्पष्टपणे सांगा, वातावरणाची (environment) तत्परतेने पडताळणी करा आणि तुम्हाला न दिसणाऱ्या बिघाडांसाठी डिझाइन करा. Clanker Support विजेट आज काम करते कारण वेब अंदाज लावण्यायोग्य आहे म्हणून नाही, तर आम्ही ते तसे असेल यावर विश्वास ठेवणे थांबवले आहे म्हणून.
