Google में PWA बनाना, भाग 1

PWA को बनाते समय, बुलेटिन टीम ने सर्विस वर्कर के बारे में क्या सीखा.

Douglas Parker
Douglas Parker
Joel Riley
Joel Riley
Dikla Cohen
Dikla Cohen

Google बुलेटिन टीम को बाहरी पीडब्ल्यूए बनाते समय ये चीज़ें सीखने को मिली हैं. यह ब्लॉग पोस्ट की पहली सीरीज़ है. इन पोस्ट में हम आपके सामने आई कुछ चुनौतियों के बारे में बताएंगे, उनका सामना करने के लिए अपनाए गए तरीकों के बारे में और गलतियों से बचने के लिए सामान्य सलाह देंगे. इसका मतलब यह नहीं है कि पीडब्ल्यूए के बारे में पूरी जानकारी दी गई है. इसका मकसद, हमारी टीम के अनुभव से मिली जानकारी को शेयर करना है.

इस पहली पोस्ट में हम पहले कुछ बुनियादी जानकारी लेंगे और फिर सर्विस वर्कर के बारे में उन सभी चीज़ों के बारे में जानेंगे जिन्हें हमने सीखा है.

बैकग्राउंड

साल 2017 के मध्य से 2019 के मध्य तक, बुलेटिन को तैयार किया गया था.

हमने पीडब्ल्यूए बनाना क्यों चुना

डेवलपमेंट की प्रोसेस शुरू करने से पहले, आइए जानते हैं कि इस प्रोजेक्ट के लिए पीडब्ल्यूए बनाना एक आकर्षक विकल्प क्यों था:

  • दोहराने की क्षमता. यह खास तौर पर तब अहम है, क्योंकि 'बुलेटिन' को कई बाज़ारों में चलाया जाएगा.
  • सिंगल कोड बेस. हमारे उपयोगकर्ताओं की संख्या Android और iOS के बीच करीब-करीब बराबर थी. PWA का मतलब है कि हम एक ऐसा वेब ऐप्लिकेशन बना सकते हैं जो दोनों प्लैटफ़ॉर्म पर काम करे. इससे टीम की क्षमता और असर बढ़ गया.
  • उपयोगकर्ता के व्यवहार के हिसाब से और तुरंत अपडेट किया जाता है. PWA अपने-आप अपडेट हो सकते हैं, जिससे वेब पर पुराने हो चुके क्लाइंट की संख्या कम हो जाती है. हम क्लाइंट के लिए, माइग्रेशन में लगने वाले कम समय की मदद से, बैकएंड में किए जा सकने वाले अहम बदलावों को हल करने में कामयाब रहे.
  • पहले और तीसरे पक्ष के ऐप्लिकेशन के साथ आसानी से इंटिग्रेट किया जा सकता है. इस तरह के इंटिग्रेशन, ऐप्लिकेशन के लिए ज़रूरी थे. पीडब्ल्यूए में इसका मतलब, अक्सर यूआरएल को खोलना होता था.
  • ऐप्लिकेशन इंस्टॉल करने की समस्या को हटा दिया गया है.

हमारा फ़्रेमवर्क

'बुलेटिन' के लिए, हमने Polymer का इस्तेमाल किया. हालांकि, कोई भी आधुनिक और अच्छी तरह से काम करने वाला फ़्रेमवर्क ही काम करेगा.

हमने सर्विस वर्कर के बारे में क्या सीखा

सेवा देने वाले व्यक्ति के बिना पीडब्ल्यूए नहीं किया जा सकता. सर्विस वर्कर से आपको बहुत ज़्यादा पावर मिलती है, जैसे कि बेहतर कैश मेमोरी, ऑफ़लाइन काम करने की सुविधाएं, बैकग्राउंड सिंक वगैरह. वैसे तो, सर्विस वर्कर थोड़ी मुश्किलें पैदा करते हैं, लेकिन हमने पाया कि इससे मिलने वाले फ़ायदे, ज़्यादा मुश्किलों से ज़्यादा मुश्किल हो जाते हैं.

अगर हो सके, तो इसे जनरेट करें

सर्विस वर्कर स्क्रिप्ट को हाथ से लिखने से बचें. राइटिंग सर्विस वर्कर को मैन्युअल तरीके से कैश मेमोरी में सेव किए गए रिसॉर्स को मैनेज करने और इस लॉजिक को रीराइट करने की ज़रूरत होती है कि ज़्यादातर सर्विस वर्कर लाइब्रेरी, जैसे कि Workbox में होती हैं.

हालांकि, हमारे इंटरनल टेक्नोलॉजी स्टैक की वजह से हम अपना सर्विस वर्कर जनरेट और मैनेज करने के लिए, लाइब्रेरी का इस्तेमाल नहीं कर सके. यहां दी गई जानकारी से, कभी-कभी हमें इस बारे में भी पता चलेगा. ज़्यादा पढ़ने के लिए, जनरेट नहीं किए गए सर्विस वर्कर के लिए होने वाले नुकसान पर जाएं.

सभी लाइब्रेरी, सर्विस वर्कर के साथ काम नहीं करतीं

कुछ JS लाइब्रेरी यह अनुमान लगाती हैं कि सर्विस वर्कर के चलाए जाने पर, उम्मीद के मुताबिक काम नहीं करती. उदाहरण के लिए, यह मान लें कि window या document उपलब्ध हैं या ऐसे एपीआई का इस्तेमाल कर रहे हैं जो सर्विस वर्कर के लिए उपलब्ध नहीं है (XMLHttpRequest, लोकल स्टोरेज वगैरह). पक्का करें कि आपको अपने ऐप्लिकेशन के लिए जिन ज़रूरी लाइब्रेरी की ज़रूरत है वे सर्विस वर्कर के साथ काम करती हैं. इस खास PWA के लिए, हम पुष्टि करने के लिए gapi.js का इस्तेमाल करना चाहते थे. हालांकि, हम ऐसा नहीं कर सके, क्योंकि इसमें सर्विस वर्कर काम नहीं करते थे. जहां भी हो सके, लाइब्रेरी के लेखकों को सर्विस वर्कर के इस्तेमाल के उदाहरणों को समझने के लिए JavaScript के संदर्भ के बारे में गलत धारणाओं को कम करना चाहिए या हटाना चाहिए. जैसे, सर्विस वर्कर के साथ काम न करने वाले एपीआई से बचना चाहिए और ग्लोबल स्टेट से बचना चाहिए.

शुरू करने के दौरान, IndexedDB ऐक्सेस करने से बचें

अपनी सर्विस वर्कर स्क्रिप्ट को शुरू करते समय, IndexedDB न पढ़ें वरना आप इस अनचाही स्थिति में जा सकते हैं:

  1. उपयोगकर्ता के पास, IndexedDB (IDB) वर्शन N वाला वेब ऐप्लिकेशन है
  2. नए वेब ऐप्लिकेशन को IDB वर्शन N+1 के साथ पुश किया गया है
  3. उपयोगकर्ता PWA पर जाता है, जो नए सर्विस वर्कर का डाउनलोड ट्रिगर होता है
  4. install इवेंट हैंडलर को रजिस्टर करने से पहले नया सर्विस वर्कर, IDB से पढ़ता है. इससे N से N+1 पर जाने के लिए IDB अपग्रेड साइकल ट्रिगर होता है
  5. उपयोगकर्ता के पास वर्शन N वाला पुराना क्लाइंट है, इसलिए सर्विस वर्कर के अपग्रेड की प्रोसेस रुक गई है, क्योंकि चालू कनेक्शन अब भी डेटाबेस के पुराने वर्शन पर काम करते हैं
  6. सर्विस वर्कर हैंग हो जाता है और कभी इंस्टॉल नहीं होता

हमारे मामले में, सर्विस वर्कर इंस्टॉल होने पर कैश मेमोरी अमान्य हो गई थी. इसलिए, अगर सर्विस वर्कर कभी इंस्टॉल नहीं हुआ, तो उपयोगकर्ताओं को अपडेट किया गया ऐप्लिकेशन कभी नहीं मिला.

इसे लचीला बनाएं

सर्विस वर्कर स्क्रिप्ट, बैकग्राउंड में चलती हैं, लेकिन इन्हें किसी भी समय बंद किया जा सकता है. भले ही, वे I/O कार्रवाइयों (नेटवर्क, आईडीबी वगैरह) के बीच में हों. लंबे समय तक चलने वाली किसी भी प्रोसेस को किसी भी समय फिर से शुरू किया जा सकता है.

एक सिंक प्रोसेस के मामले में, जो सर्वर पर बड़ी फ़ाइलें अपलोड करके आईडीबी में सेव की गई थी, रुकावट वाले आंशिक अपलोड के लिए हमारा समाधान था कि इंटरनल अपलोड लाइब्रेरी के फिर से शुरू किए जाने वाले सिस्टम का फ़ायदा उठाया गया था. अपलोड करने से पहले अपलोड किए गए यूआरएल को IDB में सेव किया जा सकता था और अगर वह पहली बार में पूरा नहीं हुआ था, तो उस यूआरएल का इस्तेमाल करके अपलोड को फिर से शुरू किया जा सकता था. साथ ही, लंबे समय तक चलने वाले I/O ऑपरेशन से पहले, राज्य को यह बताने के लिए IDB में सेव किया जाता था कि प्रोसेस में हम हर रिकॉर्ड के लिए कहां मौजूद थे.

वैश्विक स्थिति पर निर्भर न रहें

सर्विस वर्कर अलग-अलग कॉन्टेक्स्ट में होते हैं. इसलिए, कई सिंबल मौजूद नहीं हैं. हमारे बहुत सारे कोड window कॉन्टेक्स्ट के साथ-साथ सर्विस वर्कर के कॉन्टेक्स्ट में भी चलाए गए. जैसे- लॉगिंग, फ़्लैग, सिंकिंग वगैरह. यह ज़रूरी है कि कोड अपनी सेवाओं की सुरक्षा के लिए बना हो, जैसे कि लोकल स्टोरेज या कुकी. आपके पास globalThis का इस्तेमाल करके, ग्लोबल ऑब्जेक्ट को रेफ़र करने के लिए इस तरह का विकल्प है जो सभी कॉन्टेक्स्ट में काम करेगा. साथ ही, ग्लोबल वैरिएबल में सेव किए गए डेटा का कम से कम इस्तेमाल करें, क्योंकि इस बात की कोई गारंटी नहीं है कि स्क्रिप्ट कब खत्म होगी और स्क्रिप्ट कब बंद होगी.

लोकल डेवलपमेंट

सर्विस वर्कर का एक मुख्य कॉम्पोनेंट, संसाधनों को स्थानीय तौर पर कैश मेमोरी में सेव करना होता है. हालांकि, डेवलपमेंट के दौरान यह आपकी ज़रूरत से पूरी तरह विपरे होता है, खास तौर पर तब, जब अपडेट लेज़ी तरीके से किए गए हों. आप अब भी सर्वर वर्कर को इंस्टॉल करना चाहते हैं, ताकि आप उससे जुड़ी समस्याएं डीबग कर सकें या बैकग्राउंड सिंक या सूचनाओं जैसे दूसरे एपीआई के साथ काम कर सकें. Chrome पर, आप Chrome DevTools की मदद से नेटवर्क के लिए बायपास चेकबॉक्स (ऐप्लिकेशन पैनल > सर्विस वर्कर पैनल) को चालू करके भी ऐसा कर सकते हैं. इससे मेमोरी कैश को भी बंद करने के लिए नेटवर्क पैनल में कैश मेमोरी बंद करें चेकबॉक्स को चालू किया जा सकता है. ज़्यादा ब्राउज़र शामिल करने के लिए, हमने अपने सर्विस वर्कर में कैश मेमोरी बंद करने का फ़्लैग शामिल करके एक अलग समाधान चुना है, जो डेवलपर बिल्ड पर डिफ़ॉल्ट रूप से चालू होता है. इससे यह पक्का होता है कि डेवलपर को हमेशा हाल ही में किए गए बदलाव मिलते हैं. इसके लिए, उन्हें कैश मेमोरी में सेव करने की कोई समस्या नहीं होती. Cache-Control: no-cache हेडर को शामिल करना ज़रूरी है, ताकि ब्राउज़र को कोई भी ऐसेट कैश मेमोरी में सेव होने से रोका जा सके.

लाइटहाउस

Lighthouse, डीबग करने वाले कई टूल उपलब्ध कराता है जो पीडब्ल्यूए के लिए काम के हैं. यह किसी साइट को स्कैन करता है और ऐसी रिपोर्ट जनरेट करता है जिनमें PWA, परफ़ॉर्मेंस, सुलभता, एसईओ, और दूसरे सबसे सही तरीकों की जानकारी शामिल होती है. हमारा सुझाव है कि आप लाइटहाउस को लगातार इंटिग्रेट करने की सुविधा पर चलाएं. इससे आपको पीडब्ल्यूए की किसी शर्त को तोड़ने पर, आपको सूचना मिलेगी. हमारे साथ एक बार ऐसा हुआ, जहां सर्विस वर्कर इंस्टॉल नहीं कर रहा था और प्रोडक्शन शुरू होने से पहले हमें इसके बारे में पता नहीं चला था. हमारे सीआई के हिस्से के तौर पर लाइटहाउस होने से, हमें इस समस्या से बचा जा सकता है.

लगातार कॉन्टेंट उपलब्ध कराने की सुविधा अपनाएं

सर्विस वर्कर अपने-आप अपडेट हो सकते हैं. इसलिए, उपयोगकर्ताओं के पास अपग्रेड को सीमित करने की सुविधा नहीं होती. इससे नेटवर्क में पुराने हो चुके क्लाइंट की संख्या काफ़ी कम हो जाती है. जब उपयोगकर्ता हमारे ऐप्लिकेशन को खोलता है, तो सर्विस वर्कर पुराने क्लाइंट को सेवा देता था और नए क्लाइंट को लेज़ी तरीके से डाउनलोड करता था. नया क्लाइंट डाउनलोड होने के बाद, उपयोगकर्ता को नई सुविधाओं को ऐक्सेस करने के लिए पेज को रीफ़्रेश करने का अनुरोध करना होगा. भले ही उपयोगकर्ता ने इस अनुरोध को अनदेखा कर दिया हो, लेकिन अगली बार जब वह पेज रीफ़्रेश करेगा, तो उसे क्लाइंट का नया वर्शन दिखेगा. इस वजह से, उपयोगकर्ताओं के लिए अपडेट को उसी तरह अस्वीकार करना मुश्किल है जिस तरह वे iOS/Android ऐप्लिकेशन के लिए करते हैं.

क्लाइंट के लिए, डेटा को माइग्रेट करने में बहुत कम समय लगा. इस वजह से, हम बैकएंड में हुए बदलावों को लागू करने में आपकी मदद कर पाए. आम तौर पर, कोई बड़ा बदलाव करने से पहले, हम उपयोगकर्ताओं को एक महीने का समय देते हैं, ताकि वे नए क्लाइंट को अपडेट कर सकें. दरअसल, ऐप्लिकेशन पुराना होने के बावजूद काम करेगा, इसलिए अगर उपयोगकर्ता ने लंबे समय तक ऐप्लिकेशन नहीं खोला होगा, तो पुराने क्लाइंट के लिए जंगल में बने रहना मुमकिन था. iOS पर, सर्विस वर्कर को कुछ हफ़्तों के बाद निकाल दिया जाता है, ताकि ऐसा न हो. Android के लिए, कॉन्टेंट पुराना होने के दौरान विज्ञापन न दिखाकर या कुछ हफ़्तों के बाद मैन्युअल तरीके से उसकी समयसीमा खत्म करके, इस समस्या को कम किया जा सकता है. व्यावहारिक तौर पर, हमें पुराने क्लाइंट से कभी कोई समस्या नहीं मिली. कोई टीम यहां कितनी सख्ती बरतना चाहती है, यह उसके इस्तेमाल के खास मामले पर निर्भर करता है. हालांकि, iOS/Android ऐप्लिकेशन की तुलना में पीडब्ल्यूए में ज़्यादा सुविधाएं मिलती हैं.

सर्विस वर्कर में कुकी वैल्यू हासिल करना

कभी-कभी सर्विस वर्कर के हिसाब से, कुकी की वैल्यू को ऐक्सेस करना ज़रूरी होता है. हमारे मामले में, पहले पक्ष के एपीआई अनुरोधों की पुष्टि करने के लिए, हमें टोकन जनरेट करने के लिए कुकी की वैल्यू को ऐक्सेस करना ज़रूरी था. सर्विस वर्कर में, document.cookies जैसे सिंक्रोनस एपीआई उपलब्ध नहीं हैं. कुकी वैल्यू का अनुरोध करने के लिए, सर्विस वर्कर के ऐक्टिव (विंडो वाले) क्लाइंट को कभी भी मैसेज भेजा जा सकता है. हालांकि, सर्विस वर्कर के लिए विंडो क्लाइंट के बिना बैकग्राउंड में चल सकता है, जैसे कि बैकग्राउंड सिंक के दौरान. इससे बचने के लिए, हमने अपने फ़्रंटएंड सर्वर पर एक एंडपॉइंट बनाया, जो क्लाइंट को दी गई कुकी की वैल्यू को वापस भेजता था. सर्विस वर्कर ने इस एंडपॉइंट पर नेटवर्क का अनुरोध किया और कुकी की वैल्यू पाने के लिए, उसके जवाब को पढ़ा.

Cookie Store API की रिलीज़ के साथ, यह तरीका उन ब्राउज़र के लिए ज़रूरी नहीं है जिन पर यह काम करता है. ऐसा इसलिए, क्योंकि इससे ब्राउज़र कुकी का एसिंक्रोनस ऐक्सेस मिलता है और सर्विस वर्कर सीधे तौर पर इसका इस्तेमाल कर सकता है.

जनरेट नहीं किए गए सर्विस वर्कर के लिए समस्याएं

पक्का करें कि कैश मेमोरी में सेव की गई किसी फ़ाइल में बदलाव होने पर, सर्विस वर्कर स्क्रिप्ट में बदलाव हो

सर्विस वर्कर का एक सामान्य PWA पैटर्न, सर्विस वर्कर के लिए होता है जो install फ़ेज़ के दौरान सभी स्टैटिक ऐप्लिकेशन फ़ाइलें इंस्टॉल करता है. इससे क्लाइंट, अगली सभी विज़िट के लिए सीधे कैश स्टोरेज एपीआई कैश को हिट कर सकते हैं. सर्विस वर्कर सिर्फ़ तब इंस्टॉल किए जाते हैं, जब ब्राउज़र यह पता लगाता है कि सर्विस वर्कर स्क्रिप्ट में किसी तरह का बदलाव हुआ है. इसलिए, हमें यह पक्का करना था कि कैश मेमोरी में सेव की गई फ़ाइल बदलने पर, सर्विस वर्कर स्क्रिप्ट फ़ाइल भी बदल जाए. हमने ऐसा मैन्युअल तौर पर, सर्विस वर्कर स्क्रिप्ट में स्टैटिक रिसॉर्स फ़ाइलसेट के हैश को एम्बेड करके किया, ताकि हर रिलीज़ के लिए एक अलग सर्विस वर्कर JavaScript फ़ाइल जनरेट हुई. Workbox जैसी सर्विस वर्कर लाइब्रेरी, इस प्रोसेस को अपने-आप करती हैं.

यूनिट टेस्टिंग

सर्विस वर्कर एपीआई, ग्लोबल ऑब्जेक्ट में इवेंट लिसनर जोड़कर काम करते हैं. उदाहरण के लिए:

self.addEventListener('fetch', (evt) => evt.respondWith(fetch('/foo')));

इसकी जांच करना काफ़ी मुश्किल हो सकता है, क्योंकि आपको नतीजों पर दावा करने से पहले, इवेंट ट्रिगर और इवेंट ऑब्जेक्ट की नकल करनी होगी. इसके बाद, respondWith() कॉलबैक का इंतज़ार करना होगा और फिर प्रॉमिस का इंतज़ार करना होगा. इसे स्ट्रक्चर करने का सबसे आसान तरीका, सभी तरह के लागू करने की प्रक्रिया को किसी दूसरी फ़ाइल पर सौंपना है. इसे टेस्ट करना ज़्यादा आसान है.

import fetchHandler from './fetch_handler.js';
self.addEventListener('fetch', (evt) => evt.respondWith(fetchHandler(evt)));

सर्विस वर्कर स्क्रिप्ट की यूनिट की जांच करने में आने वाली मुश्किलों की वजह से, हमने कोर सर्विस वर्कर स्क्रिप्ट को कम से कम बेसिक रखा. लागू करने के ज़्यादातर हिस्से को दूसरे मॉड्यूल में बांट दिया. वे फ़ाइलें सिर्फ़ स्टैंडर्ड JS मॉड्यूल थीं, इसलिए उन्हें स्टैंडर्ड टेस्ट लाइब्रेरी की मदद से, यूनिट की जांच के लिए ज़्यादा आसानी से टेस्ट किया जा सकता था.

पार्ट 2 और 3 के लिए हमारे साथ बने रहें

इस सीरीज़ के दूसरे और तीसरे हिस्से में, हम मीडिया मैनेजमेंट और iOS से जुड़ी समस्याओं के बारे में बात करेंगे. अगर आपको Google में PWA बनाने के बारे में और जानकारी चाहिए, तो हमसे संपर्क करने का तरीका जानने के लिए, लेखक की प्रोफ़ाइल पर जाएं: