ஒவ்வொரு இணைய மேம்பாட்டாளருக்கும் (web developer) ஒரு கட்டுப்படுத்தப்பட்ட ஸ்டேஜிங் சூழலில் (staging environment) தங்களது அப்ளிகேஷன் சரியாக இயங்குவதைப் பார்க்கும் உணர்வு தெரியும். ஒரு எம்பெடட் விட்ஜெட்டை (embedded widget) வெளியிடுவது அந்த நிம்மதியை முற்றிலும் சிதைத்துவிடும். நீங்கள் இனி அந்தப் பக்கத்தின் வடிவமைப்பாளர் (architect) அல்ல. நீங்கள் ஒரு அழைக்கப்படாத விருந்தினர், நீங்கள் உரிமை கொண்டாடாத ஒரு DOM-க்குள், நீங்கள் உருவாக்காத ஒரு CSS கேஸ்கேடிற்குள் (CSS cascade), மற்றும் உங்களுக்கு எதிராகவே செயல்படக்கூடிய ஒரு ரன்டைம் சூழலுக்குள் (runtime environment) ஒரு React அப்ளிகேஷனைத் திணிக்கிறீர்கள். Clanker Support விட்ஜெட்டை உருவாக்கும்போது, உங்கள் கோட் வேறொருவரின் தீமில் (theme) இயங்கத் தொடங்கும் அந்தத் தருணத்தில், வழக்கமான இணைய மேம்பாட்டு அனுமானங்கள் அனைத்தும் உடைந்துவிடுகின்றன என்பதை நாங்கள் கற்றுக்கொண்டோம். ஹோஸ்ட் தளம் எழுத்துரு அளவுகளை (font sizes) மாற்றலாம், காலியான div-களை மறைக்கலாம், அல்லது உங்கள் கான்ஃபிகரேஷனைப் படிப்பதற்கு முன்பே செல்லுபடியாகாதவாறு ஒரு ஸ்கிரிப்ட் லைஃப்சைக்கிளை (script lifecycle) நடைமுறைப்படுத்தலாம். தயாரிப்புச் சூழலில் (production) நாங்கள் அனுபவத்தினால் கற்றுக்கொண்ட பாதுகாப்பு விதிகள் இதோ.
One File, One Failure Mode
நவீன பண்டலர்கள் (bundlers) கோட் ஸ்பிளிட்டிங் (code splitting) மற்றும் டைனமிக் இம்போர்ட்ஸ் (dynamic imports) மூலம் உங்களைத் தூண்டும். அவற்றைத் தவிர்க்கவும். ஒரு எம்பெடட் விட்ஜெட் ஒரு ஒற்றை கோப்பு கொண்ட Immediately Invoked Function Expression (IIFE) ஆக இருக்க வேண்டும். ஒரு வாடிக்கையாளர் உங்கள் ஸ்கிரிப்ட் டேக்-ஐ (script tag) தங்களது டெம்ப்ளேட்டிற்குள் நகலெடுக்கும்போது, அவர்கள் ஒரே ஒரு நெட்வொர்க் கோரிக்கையை (network request) எதிர்பார்க்கிறார்கள். உங்கள் பண்டில் ஒரு கனமான பார்சிங் லைப்ரரியையோ (parsing library) அல்லது ஒரு லாங்குவேஜ் மாடல் சங்க் (language model chunk) அல்லது லேசி-லோட் (lazy-load) செய்ய முயன்றால், அந்த ஃபெட்ச் (fetch) அமைதியாகத் தோல்வியடையக்கூடும். ஹோஸ்ட் தளத்தில் கடுமையான Content Security Policy, ஒரு தீவிரமான ஆட் பிளாக்கர் (ad blocker), அல்லது உங்கள் publicPath அனுமானங்களுடன் பொருந்தாத ஒரு CDN பாத் இருக்கலாம். அனைத்தையும் ஒரே IIFE-க்குள் கொண்டு வருவதன் மூலம், இரண்டாம் நிலை சங்க் லோடிங்கில் (secondary chunk loading) ஏற்படும் நிச்சயமற்ற தன்மைகளை நீங்கள் தவிர்க்கலாம். ஒரு டிபென்டென்சி (dependency) அதன் உட்பகுதிகளை லேசி-லோட் செய்ய வற்புறுத்தினால், பில்ட் நேரத்தில் (build time) அதை ஒரு லேசான ஸ்டப் (lightweight stub) ஆக மாற்றவும் (alias). இதன் விளைவாக ஒரு ஒற்றை ஆர்டிஃபாக்ட் (artifact), ஒரு ஒற்றை தோல்வி முறை (failure mode), மற்றும் வாடிக்கையாளரின் தள மேலாளர் உமிற்கு ஒரு உடைந்த சாட் பபுளின் (broken chat bubble) ஸ்கிரீன்ஷாட்டை மின்னஞ்சல் அனுப்பும்போது மிக எளிதான டீபக்கிங் (debugging) அமையும்.
The Shadow DOM Leaks Too
டெவலப்பர்கள் பெரும்பாலும் Shadow DOM-ஐ ஊடுருவ முடியாத ஒரு கோட்டையாகக் கருதுகிறார்கள். இது ஹோஸ்ட் பக்கத்தின் CSS-லிருந்து உங்கள் செலெக்டர்களைத் (selectors) தனிமைப்படுத்தினாலும், இது இன்ஹெரிட்டன்ஸை (inheritance) தனிமைப்படுத்தாது. font-family, line-height, color, மற்றும் text-align போன்ற பண்புகள் (properties), எல்லை இல்லை என்பது போலவே உங்கள் ஷேடோ ட்ரீக்குள் (shadow tree) கீழ்நோக்கிப் பாய்கின்றன. ஒரு Shopify ஸ்டோரில் உலகளாவிய font-family: "Comic Sans MS" என்ற அறிவிப்பு இருந்தால், உங்கள் ரூட் எலிமெண்டில் (root element) ஒவ்வொரு இன்ஹெரிட்டபிள் பண்பையும் (inheritable property) நீங்கள் வெளிப்படையாகப் பூட்டி வைக்காதவரை, அது உங்கள் கவனமாக வடிவமைக்கப்பட்ட சப்போர்ட் விட்ஜெட்டையும் பாதிக்கும். ஹோஸ்ட் மட்டத்தில் (host level) உங்கள் சொந்த டைப்போகிராபி (typography), இடைவெளி (spacing) மற்றும் உரை சீரமைப்பை (text alignment) உறுதியான மதிப்புகளுடன் அமைக்கவும். பெற்றோர் பக்கம் (parent page) உங்களுக்கு எதிராகச் செயல்படும் என்று கருதி, உங்களுக்குத் தேவையான அனைத்தையும் ரீசெட் (reset) செய்யவும். Shadow DOM உங்கள் கிளாஸ்களைப் (classes) பாதுகாக்கிறது, உங்கள் அழகியலை (aesthetics) அல்ல.
The Empty Div Vanishing Act
இது எங்களை முற்றிலும் திடுக்கிட வைத்தது. Shopify Dawn உட்பட பல பிரபலமான தீம்கள், div:empty { display: none; } என்ற அப்பாவித்தனமான ஒரு CSS விதியுடன் வருகின்றன. உங்கள் விட்ஜெட் மவுண்ட் (mount) ஆகும்போது, அது பொதுவாக காலியாகத் தொடங்கும் ஒரு ஹோஸ்ட் div-ஐ இலக்காகக் கொள்ளும். உங்கள் JavaScript இயங்கி, React அந்த நோடை (node) ஹைட்ரேட் (hydrate) செய்வதற்கு முன்பு, அந்த div உண்மையில் காலியாக இருக்கும். தீமின் ஸ்டைல்ஷீட் (stylesheet) அதை மறைத்துவிடும். உங்கள் ஸ்கிரிப்ட் இயங்கும், ReactDOM.createRoot-ஐ அழைக்கும், ஆனால் எதுவும் தோன்றாது. கன்சோலில் (console) எந்தத் தவறும் இருக்காது. அந்த எலிமெண்ட் லேஅவுட்டில் (layout) இருந்தே காணாமல் போய்விடும். இதற்கான தீர்வு நேரடியானது மற்றும் வெளிப்படையானது: உங்கள் மவுண்ட் பாயிண்டிற்கு (mount point) display: block !important என்ற இன்லைன் ஸ்டைலை (inline style) பயன்படுத்தவும். இதைத் தற்போதைக்குத் தள்ளிப்போட உங்கள் CSS-in-JS லைப்ரரியைச் சார்ந்திருக்க வேண்டாம். உங்கள் ஸ்டைல்ஷீட்கள் செயல்படும்போது, ஹோஸ்ட் தீம் ஏற்கனவே வெற்றி பெற்றுவிடும்.
Abandon rem for px
ஒரு சாதாரண அப்ளிகேஷனில், rem போன்ற ஒப்பீட்டு அலகுகள் (relative units) பொறுப்பான தேர்வாகும். ஆனால் ஒரு எம்பெடில் (embed), அவை ஒரு சுமையாகும். ஒரு rem மதிப்பு உங்கள் விட்ஜெட்டைப் பொறுத்து அல்லாமல், ஹோஸ்ட் ஆவணத்தின் ரூட் html எழுத்துரு அளவைப் பொறுத்தே அமையும். ஹோஸ்ட் பக்கம் html { font-size: 10px; } என்று அமைத்தாலோ அல்லது பழைய 62.5% முறையைப் பயன்படுத்தினாலோ, உங்கள் முழு டைப்போகிராஃபிக் மற்றும் ஸ்பேசிங் அளவுகளும் (typographic and spacing scale) எச்சரிக்கையின்றி மாறிவிடும். வசதியான 1.6rem லைன் ஹைட் (line height) 16px-ஆகச் சுருங்கலாம், அல்லது உங்கள் பேடிங் (padding) படிக்க முடியாத அளவிற்குச் சிறுத்துவிடலாம். ஹோஸ்டின் ரூட் அளவை உங்களால் கணிக்கவோ அல்லது கட்டுப்படுத்தவோ முடியாது என்பதால், ஒரு எம்பெடட் விட்ஜெட்டிற்கு பிக்சல்கள் (pixels) மட்டுமே நம்பகமான அலகு. அவை சுற்றியுள்ள பக்கத்தின் அனுமானங்களைப் பொருட்படுத்தாமல் ஒரே இயற்பியல் அளவில் (physical size) தோன்றும். மற்றொரு தளத்தின் கேஸ்கேடிற்குள் நீங்கள் வாழும்போது, rem-ன் தத்துவார்த்த அணுகல்தன்மை நெகிழ்வுத்தன்மையைக் (theoretical accessibility flexibility) கைவிட்டு, px-ன் நடைமுறை நம்பகத்தன்மையை (practical reliability) தேர்ந்தெடுங்கள்.
Read Your Config Before It Disappears
உங்கள் விட்ஜெட்டிற்கு (widget) script tag-ல் உள்ள data attributes மூலம் உள்ளமைப்புகளை (configuration) வழங்கினால், அவற்றை நீங்கள் உடனடியாக (synchronously) படிக்க வேண்டும். ஒரு script தனது சொந்த tag-ஐ ஆய்வு செய்ய வசதியாக உலாவல் (browser) document.currentScript-ஐ வழங்குகிறது, ஆனால் இந்தத் தரவு (reference) தற்காலிகமானது. நீங்கள் DOMContentLoaded அல்லது ஏதேனும் ஒரு asynchronous எல்லையைத் தொடங்கும் வரை காத்திருந்தால், document.currentScript என்பது null ஆகிவிடும். உங்கள் உள்ளமைப்புகள் காணாமல் போய்விடும். உங்கள் script இயங்கத் தொடங்கும் போதே அந்த attributes-களை உடனடியாகப் படியுங்கள். API key, widget ID மற்றும் color theme ஆகியவற்றை அந்தத் தருணமே பிடித்துக் கொண்டு, அவற்றை ஒரு closure அல்லது module variable-ல் சேமித்து வைத்துவிட்டு, அதன் பின்னரே React-ஐத் தொடங்குங்கள்.
Script URL-ஐயே API Origin-ஐத் தேர்ந்தெடுக்க விடவும்
உங்கள் bundle-க்குள் ஒரு production API URL-ஐ நேரடியாகக் குறிப்பிடுவது (Hardcoding), பல்வேறு சூழல்களில் (environments) பல சிக்கல்களை உருவாக்கும் ஒரு தவறாகும். அதற்குப் பதிலாக, script element-ன் சொந்த src attribute-லிருந்து உங்கள் API origin-ஐப் பெறுங்கள். விட்ஜெட் https://cdn.staging.example.com/widget.js-லிருந்து ஏற்றப்பட்டால், அதன் API அழைப்புகள் இயல்பாகவே https://api.staging.example.com-க்குச் செல்ல வேண்டும். ஒரு டெவலப்பர் localhost:3000-லிருந்து இயக்கப்படும் ஒரு உள்ளூர் HTML கோப்பில் script tag-ஐப் பயன்படுத்தினால், அந்த local build கோரிக்கைகளை (requests) ஒரு உள்ளூர் சர்வருக்கு அனுப்ப வேண்டும். இந்த முறை, சூழலுக்குத் தனித்தனி builds, feature flags அல்லது embed பயனரிடமிருந்து கைமுறை உள்ளமைப்புகள் (manual configuration) தேவைப்படுவதைத் தவிர்க்கிறது. இது தானாகவே வேலை செய்யும், ஏனெனில் உள்கட்டமைப்பின் இருப்பிடம் (infrastructure location), அது வழங்கப்படப்படும் இடத்திலிருந்தே (delivery location) தீர்மானிக்கப்படுகிறது.
Cache Headers-ஐ ஒரு அவசரத் தீர்வின் (Hotfix) உயிர்நாடியாகக் கருதுங்கள்
பயனர்கள் உங்கள் script tag-ஐ ஒருமுறை மட்டும் தங்கள் footer template-ல் நகலெடுத்துவிட்டுப் பிறகு அதைப் பற்றி மறந்துவிடுவார்கள். நீங்கள் ஐந்தாயிரம் வணிகர்களுக்கு மின்னஞ்சல் அனுப்பி, ஒரு version query parameter-ஐ மாற்றும்படி கேட்க முடியாது. இதன் பொருள், உங்கள் cache headers என்பது உங்கள் incident response strategy-ன் ஒரு பகுதியாகும். உங்கள் widget bundle-க்குச் சிறிய max-age-ஐ அமைக்கவும்; இதன் மூலம் நீங்கள் ஒரு முக்கியமான திருத்தத்தை (critical fix) வெளியிடும்போது, அது வாரக்கணக்கில் காத்திருக்காமல் சில மணிநேரங்களிலேயே பரவிவிடும். நீண்ட காலம் சேமிக்கப்படும் (cached) ஒரு asset-ன் வசதியானது, ஆயிரக்கணக்கான தளங்கள் நீங்கள் மாற்ற முடியாத ஒரு பழுதான பதிப்பை (broken version) இயக்குகின்றன என்பதைத் தெரிந்துகொள்வதால் ஏற்படும் மன உளைச்சலுக்கு ஈடாகாது. CDN போக்குவரத்துச் செலவை (traffic cost) ஏற்றுக்கொள்ளுங்கள். உங்கள் நிம்மதி அதில்தான் உள்ளது.
iframe Embeds-காக உங்கள் CSP-யை மாற்றியமைக்கவும்
நீங்கள் iframe-அடிப்படையிலான embedding விருப்பத்தை வழங்கினால், உங்கள் Content Security Policy (CSP) வழக்கமான web application சிந்தனையில் இருந்து மாறுபட வேண்டும். பொதுவாக, clickjacking-ஐத் தடுக்க நீங்கள் framing-ஐத் தடை செய்யலாம். ஆனால் ஒரு விட்ஜெட்டிற்கு, நீங்கள் அதை அனுமதிக்க வேண்டும். எந்தத் தளமும் உங்கள் iframe-ஐத் தரமளிக்க (host) ஏதுவாக frame-ancestors *-ஐ அமைக்கவும். அதன் பிறகு மற்ற அனைத்திலும் மிகவும் கண்டிப்புடன் செயல்படுங்கள். அந்த iframe policy-க்குள் script-src, style-src, மற்றும் connect-src ஆகியவற்றை மிகக் கடுமையாகக் கட்டுப்படுத்துங்கள். நீங்கள் framing வழியாக இணையத்திற்குத் உங்களை வேண்டுமென்றே வெளிப்படுத்துகிறீர்கள், எனவே ஒரு host page உங்களை மாற்றியமைக்க முயன்றால், iframe-க்குள் இயங்கும் குறியீடு தவறாகச் செயல்பட வாய்ப்பில்லை என்பதை நீங்கள் உறுதி செய்ய வேண்டும்.
விருந்தினர் மனநிலை (The Guest Mindset)
Embeds உருவாக்குவது என்பது வழக்கமான web applications உருவாக்குவதிலிருந்து மாறுபட்ட அணுகுமுறையைக் கோருகிறது. உங்கள் சொந்த செயலியில் (app), container, routing, build pipeline மற்றும் global styles ஆகிய அனைத்தும் உங்கள் கட்டுப்பாட்டில் இருக்கும். ஆனால் ஒரு embed-ல், உங்களிடம் எதுவும் இல்லை. அந்த host page எதுவாக வேண்டுமானாலும் இருக்கலாம், அது பெரும்பாலும் பழமையானதாகவோ, அவ்வப்போது உங்களுக்குப் प्रतिकूलமானதாகவோ அல்லது எப்போதும் உங்கள் கட்டுப்பாட்டிற்கு அப்பாற்பட்டதாகவோ இருக்கலாம். ஒவ்வொரு அனுமானமும் பாதுகாப்பானதாக (defensive) இருக்க வேண்டும். நீங்கள் எதைச் சொல்ல வருகிறீர்கள் என்பதைத் தெளிவாகக் குறிப்பிடுங்கள், சூழலை (environment) விரைவாகச் சரிபார்க்கவும், நீங்கள் பார்க்க முடியாத பிழைகளுக்காகவும் (breakage) வடிவமைக்கவும். Clanker Support widget இன்று வேலை செய்கிறது என்றால், இணையம் கணிக்கக்கூடியது (predictable) என்பதால் அல்ல, மாறாக அது அப்படி இருக்கும் என்று நாங்கள் நம்புவதை நிறுத்தியதால்தான்.
