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

Bulletin की टीम को PWA बनाते समय, सेवा वर्कर के बारे में क्या पता चला.

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

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

इस पहली पोस्ट में, हम आपको इस बारे में थोड़ी जानकारी देंगे कि सेवा वर्कर क्या हैं. इसके बाद, हम सेवा वर्कर के बारे में अपनी सभी जानकारी शेयर करेंगे.

बैकग्राउंड

बुलेटिन को साल 2017 के मध्य से 2019 के मध्य तक डेवलप किया गया था.

हमने PWA बनाने का विकल्प क्यों चुना

डेवलपमेंट की प्रोसेस के बारे में जानने से पहले, यह देखें कि इस प्रोजेक्ट के लिए PWA बनाना क्यों एक बेहतर विकल्प था:

  • दोहराने की क्षमता. यह जानकारी खास तौर पर अहम है, क्योंकि Bulletin को कई बाज़ारों में पायलट किया जाएगा.
  • एक कोड बेस. हमारे उपयोगकर्ताओं को 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 ऑपरेशन (नेटवर्क, आईडीबी वगैरह) के बीच में हों. लंबे समय तक चलने वाली प्रोसेस को किसी भी समय फिर से शुरू किया जा सकता है.

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

ग्लोबल स्टेटस पर निर्भर न रहें

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

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

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

लाइटहाउस

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

लगातार डिलीवरी की सुविधा का इस्तेमाल करना

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

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

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

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

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

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

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

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

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

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

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

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

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

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

दूसरे और तीसरे हिस्से के लिए हमारे साथ बने रहें

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