ہر ویب ڈویلپر اس احساس سے واقف ہے جب وہ اپنے کنٹرول شدہ اسٹیجنگ انوائرمنٹ (staging environment) میں اپنی ایپلی کیشن کو مکمل طور پر درست طریقے سے رینڈر (render) ہوتے ہوئے دیکھتا ہے۔ ایک ایمبیڈڈ ویجیٹ (embedded widget) کو لانچ کرنا اس سکون کو مکمل طور پر ختم کر دیتا ہے۔ اب آپ پیج کے آرکیٹیکٹ نہیں رہے۔ آپ ایک ناخوش آمد کے مہمان ہیں، جو ایک ایسے DOM میں React ایپلی کیشن کو انجیکٹ کر رہے ہیں جس پر آپ کا اختیار نہیں، ایک ایسی CSS کیسکیڈ (cascade) میں جسے آپ نے نہیں لکھا، اور ایک ایسے رن ٹائم انوائرمنٹ (runtime environment) میں جو شاید آپ کے خلاف کام کر رہا ہو۔ Clanker Support ویجیٹ بناتے اور لانچ کرتے وقت، ہم نے سیکھا کہ ویب ڈویلپمنٹ کے عام مفروضے اس لمحے ہی دم توڑ دیتے ہیں جب آپ کا کوڈ کسی دوسرے کے تھیم کے اندر چلتا ہے۔ ہوسٹ سائٹ فونٹ سائز ری سیٹ کر سکتی ہے، خالی divs کو چھپا سکتی ہے، یا ایک ایسا اسکرپٹ لائف سائیکل نافذ کر سکتی ہے جو آپ کی کنفیگریشن کو پڑھنے سے پہلے ہی اسے کالعدم کر دے۔ یہاں وہ دفاعی اصول ہیں جو ہم نے عملی تجربات سے سیکھے ہیں۔

ایک فائل، ایک فیلر موڈ (One Failure Mode)

جدید بنڈلرز (bundlers) آپ کو کوڈ سپلٹنگ (code splitting) اور ڈائنامک امپورٹس (dynamic imports) کی طرف راغب کرتے ہیں۔ ان سے بچیں۔ ایک ایمبیڈڈ ویجیٹ کو ایک سنگل فائل 'Immediately Invoked Function Expression' (IIFE) کے طور پر بھیجا جانا چاہیے۔ جب کوئی کسٹمر آپ کے اسکرپٹ ٹیگ کو اپنے ٹیمپلیٹ میں کاپی کرتا ہے، تو وہ صرف ایک نیٹ ورک ریکویسٹ کی توقع رکھتا ہے۔ اگر آپ کا بنڈل کسی بھاری پارسنگ لائبریری یا لینگویج ماڈل چنک (chunk) کو لیزی لوڈ (lazy-load) کرنے کی کوشش کرتا ہے، تو وہ فیچ (fetch) خاموشی سے ناکام ہو سکتا ہے۔ ہوسٹ سائٹ کی ایک سخت Content Security Policy ہو سکتی ہے، ایک جارحانہ ایڈ بلاکر (ad blocker) ہو سکتا ہے، یا کوئی ایسا CDN پاتھ ہو سکتا ہے جو آپ کے publicPath کے مفروضوں سے میل نہ کھاتا ہو۔ سب کچھ ایک IIFE میں زبردستی شامل کر کے، آپ سیکنڈری چنک لوڈنگ کے نامعلوم خطرات کو ختم کر دیتے ہیں۔ اگر کوئی ڈیپینڈینسی (dependency) اپنے اندرونی حصوں کو لیزی لوڈ کرنے پر اصرار کرے، تو بلڈ ٹائم پر اسے ایک ہلکی پھلکی 'stub' کے ساتھ ایلیس (alias) کر دیں۔ اس کا نتیجہ ایک واحد آرٹفیکٹ، ایک ہی فیلر موڈ، اور ایک بہت آسان ڈی بگنگ سیشن ہوگا جب کسی کسٹمر کا سائٹ مینیجر آپ کو ٹوٹے ہوئے چیٹ ببل کا اسکرین شاٹ ای میل کرے گا۔

Shadow DOM بھی لیک ہوتا ہے

ڈویلپرز اکثر Shadow DOM کو ایک ناقابل تسخیر قلعہ سمجھتے ہیں۔ یہ آپ کے سلیکٹرز (selectors) کو ہوسٹ پیج کی CSS سے تو الگ رکھتا ہے، لیکن یہ وراثت (inheritance) کو الگ نہیں کر سکتا۔ font-family، line-height، color اور text-align جیسی پراپرٹیز آپ کے شیڈو ٹری (shadow tree) میں اس طرح نیچے کی طرف بہتی ہیں جیسے کہ کوئی سرحد ہی نہ ہو۔ Shopify اسٹور جس میں گلوبل font-family: "Comic Sans MS" کا اعلان ہو، وہ آپ کے احتیاط سے ڈیزائن کیے گئے سپورٹ ویجیٹ کو متاثر کرے گا جب تک کہ آپ اپنے روٹ ایلیمنٹ (root element) پر ہر وراثتی پراپرٹی کو واضح طور پر پن (pin) نہ کر دیں۔ ہوسٹ لیول پر ہی اپنی ٹائپوگرافی، اسپیسنگ اور ٹیکسٹ الائنمنٹ کے لیے ٹھوس ویلیوز (concrete values) سیٹ کریں۔ یہ فرض کر لیں کہ پیرنٹ پیج مخالف ہے اور ہر اس چیز کو ری سیٹ کر دیں جس کی آپ کو پرواہ ہے۔ Shadow DOM آپ کی کلاسز کی حفاظت کرتا ہے، آپ کے جمالیات (aesthetics) کی نہیں۔

خالی Div کا غائب ہونے والا کرتب

اس چیز نے ہمیں بالکل حیران کر دیا۔ بہت سے مقبول تھیمز، بشمول Shopify Dawn، ایک ایسے CSS رول کے ساتھ آتے ہیں جو بے ضرر لگتا ہے: div:empty { display: none; }۔ جب آپ کا ویجیٹ ماؤنٹ (mount) ہوتا ہے، تو یہ عام طور پر ایک ہوسٹ div کو نشانہ بناتا ہے جو شروع میں خالی ہوتا ہے۔ اس سے پہلے کہ آپ کا JavaScript چلے اور React اس نوڈ (node) کو ہائیڈریٹ (hydrate) کرے، وہ div لفظی طور پر خالی ہوتا ہے۔ تھیم کی اسٹائل شیٹ اسے چھپا دیتی ہے۔ آپ کا اسکرپٹ چلتا ہے، ReactDOM.createRoot کو کال کرتا ہے، اور کچھ بھی ظاہر نہیں ہوتا۔ کنسول میں کوئی ایرر نہیں ہوتا۔ وہ ایلیمنٹ لے آؤٹ میں محض وجود ختم کر دیتا ہے۔ اس کا حل زبردستی اور واضح ہے: اپنے ماؤنٹ پوائنٹ پر display: block !important کا ان لائن اسٹائل لگائیں۔ اس معاملے کو بعد میں سنبھالنے کے لیے اپنی CSS-in-JS لائبریری پر بھروسہ نہ کریں۔ جب تک آپ کی اسٹائل شیٹس لاگو ہوتی ہیں، ہوسٹ تھیم پہلے ہی جیت چکا ہوتا ہے۔

rem کو چھوڑ کر px اپنائیں

ایک عام ایپلی کیشن میں، rem جیسے ریلیٹیو یونٹس (relative units) ایک ذمہ دارانہ انتخاب ہوتے ہیں۔ ایک ایمبیڈ میں، وہ ایک خطرہ ہیں۔ ایک rem ویلیو ہوسٹ دستاویز کے روٹ html فونٹ سائز کے مطابق حل ہوتی ہے، آپ کے ویجیٹ کے مطابق نہیں۔ اگر ہوسٹ پیج html { font-size: 10px; } سیٹ کرتا ہے یا پرانا 62.5% والا طریقہ استعمال کرتا ہے، تو آپ کا پورا ٹائپوگرافک اور اسپیسنگ اسکیل بغیر کسی وارننگ کے بدل جاتا ہے۔ ایک آرام دہ 1.6rem لائن ہائٹ 16px تک سکڑ سکتی ہے، یا آپ کی پیڈنگ ناقابلِ فہم حد تک کم ہو سکتی ہے۔ چونکہ آپ ہوسٹ کے روٹ سائزنگ کا اندازہ نہیں لگا سکتے اور نہ ہی اسے کنٹرول کر سکتے ہیں، اس لیے ایمبیڈڈ ویجیٹ کے لیے پکسلز (pixels) ہی واحد ایماندار یونٹ ہیں۔ وہ ارد گرد کے پیج کے مفروضوں کے باوجود ایک ہی جسمانی سائز پر رینڈر ہوتے ہیں۔ جب آپ کسی دوسری سائٹ کے کیسکیڈ کے اندر رہ رہے ہوں، تو rem کی نظریاتی رسائی (accessibility) کی لچک کے مقابلے میں px کی عملی بھروسہ مندی کو ترجیح دیں۔

اپنی کنفیگریشن کو غائب ہونے سے پہلے پڑھ لیں

اگر آپ اپنے widget کی configuration کو script tag پر data attributes کے ذریعے پاس کرتے ہیں، تو آپ کو انہیں synchronously پڑھنا ہوگا۔ براؤزر document.currentScript فراہم کرتا ہے تاکہ ایک script اپنے ہی tag کا معائنہ کر سکے، لیکن یہ reference عارضی (ephemeral) ہوتا ہے۔ اگر آپ DOMContentLoaded یا کسی بھی asynchronous boundary کا انتظار کرتے ہیں، تو document.currentScript null ہو جاتا ہے۔ آپ کی configuration ختم ہو جاتی ہے۔ ان attributes کو اپنی script execution کے ٹاپ لیول پر فوری طور پر پڑھیں۔ API key، widget ID، اور color theme کو اسی وقت حاصل کریں، انہیں کسی closure یا module variable میں محفوظ کریں، اور اس کے بعد ہی React کو boot کرنے کا عمل شروع کریں۔

اسکرپٹ URL کو API Origin منتخب کرنے دیں

اپنے bundle میں production API URL کو hardcode کرنا ایک ایسی غلطی ہے جو مختلف environments میں کئی گنا بڑھ جاتی ہے۔ اس کے بجائے، اپنے API origin کو script element کے اپنے src attribute سے اخذ کریں۔ اگر widget https://cdn.staging.example.com/widget.js سے لوڈ ہو رہا ہے، تو اس کی API calls ڈیفالٹ طور پر https://api.staging.example.com ہونی چاہئیں۔ اگر کوئی ڈویلپر script tag کو localhost:3000 سے سروس ہونے والی مقامی HTML فائل میں ڈالتا ہے، تو مقامی build کو درخواستوں کو مقامی سرور پر بھیجنا چاہیے۔ یہ طریقہ کار environment-specific builds، feature flags، یا embed صارف کی طرف سے دستی configuration کی ضرورت کو ختم کر دیتا ہے۔ یہ خود بخود کام کرتا ہے، کیونکہ انفراسٹرکچر کی جگہ کی نشاندہی ڈیلیوری کی جگہ سے ہو جاتی ہے۔

Cache Headers کو Hotfix کی لائف لائن سمجھیں

صارفین آپ کے script tag کو ایک بار اپنے footer template میں کاپی کرتے ہیں اور پھر اسے بھول جاتے ہیں۔ آپ پانچ ہزار مرچنٹس کو ای میل نہیں کر سکتے اور ان سے version query parameter کو اپ ڈیٹ کرنے کا کہہ سکتے ہیں۔ اس کا مطلب ہے کہ آپ کے cache headers آپ کی incident response strategy کا حصہ ہیں۔ اپنے widget bundle پر ایک مختصر max-age سیٹ کریں تاکہ جب آپ کوئی اہم (critical) fix بھیجیں، تو وہ ہفتوں کے بجائے گھنٹوں میں پھیل جائے۔ ایک طویل عرصے تک رہنے والے cached asset کی سہولت اس مفلوج حالت کے برابر نہیں ہے جہاں آپ کو معلوم ہو کہ ہزاروں سائٹس ایک خراب ورژن چلا رہی ہیں جسے آپ واپس نہیں بلا سکتے۔ CDN ٹریفک کی لاگت کو قبول کریں۔ آپ کا سکون اسی پر منحصر ہے۔

iframe Embeds کے لیے اپنی CSP کو تبدیل کریں

اگر آپ iframe پر مبنی embedding کا آپشن فراہم کرتے ہیں، تو آپ کی Content Security Policy کو عام ویب ایپلی کیشن کی سوچ کے برعکس ہونا چاہیے۔ عام طور پر آپ clickjacking سے بچنے کے لیے framing کو ممنوع قرار دے سکتے ہیں۔ ایک widget کے لیے، آپ کو اسے اجازت دینی چاہیے۔ frame-ancestors * سیٹ کریں تاکہ کوئی بھی سائٹ آپ کا iframe ہوسٹ کر سکے۔ پھر باقی ہر چیز کے بارے میں سخت (draconian) ہو جائیں۔ اس iframe policy کے اندر script-src، style-src، اور connect-src کو سختی سے لاک کریں۔ آپ جان بوجھ کر framing vector کے ذریعے خود کو پوری ویب کے لیے کھول رہے ہیں، اس لیے آپ کو یہ یقینی بنانا چاہیے کہ iframe کے اندر چلنے والا کوڈ کوئی غلط حرکت نہ کرے اگر کوئی host page اسے تبدیل کرنے کی کوشش کرے۔

مہمانانہ ذہنیت (The Guest Mindset)

Embeds بنانے کے لیے عام ویب ایپلی کیشنز بنانے کے مقابلے میں ایک مختلف طرزِ عمل کی ضرورت ہوتی ہے۔ اپنی ایپ میں، آپ کنٹینر، routing، build pipeline، اور global styles کے مالک ہوتے ہیں۔ ایک embed میں، آپ کے پاس کچھ بھی نہیں ہوتا۔ Host page من مانا، اکثر پرانا، کبھی کبھار مخالفانہ، اور ہمیشہ آپ کے کنٹرول سے باہر ہوتا ہے۔ ہر مفروضہ دفاعی (defensive) ہونا چاہیے۔ جو آپ کا مطلب ہے اسے واضح طور پر بیان کریں، ماحول (environment) کی تیزی سے تصدیق کریں، اور ایسی خرابی کے لیے ڈیزائن کریں جسے آپ دیکھ نہیں سکتے۔ Clanker Support widget آج اس لیے کام کرتا ہے کیونکہ ویب قابلِ پیش گوئی (predictable) ہے، بلکہ اس لیے کہ ہم اس کے قابلِ پیش گوئی ہونے پر بھروسہ کرنا چھوڑ چکے ہیں۔