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 अपने-आप अपडेट हो सकते हैं. इससे, डिवाइसों पर इस्तेमाल किए जा रहे पुराने क्लाइंट की संख्या कम हो जाती है. हमने क्लाइंट के लिए, माइग्रेशन में लगने वाले समय को कम करके, बैकएंड में बड़े बदलाव किए.
  • पहले और तीसरे पक्ष के ऐप्लिकेशन के साथ आसानी से इंटिग्रेट किया जा सकता है. ऐप्लिकेशन के लिए, ऐसे इंटिग्रेशन ज़रूरी थे. PWA के साथ, इसका मतलब अक्सर सिर्फ़ यूआरएल खोलना होता था.
  • ऐप्लिकेशन इंस्टॉल करने में आने वाली समस्याओं को दूर किया.

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

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

सर्विस वर्कर के बारे में हमें क्या पता चला

सर्विस वर्कर के बिना, कोई PWA नहीं बनाया जा सकता. सर्विस वर्कर की मदद से, आपको कई सुविधाएं मिलती हैं. जैसे, कैश मेमोरी सेव करने की बेहतर रणनीतियां, ऑफ़लाइन काम करने की सुविधाएं, बैकग्राउंड में सिंक करने की सुविधा वगैरह. हालांकि, सर्विस वर्कर की वजह से कुछ जटिलताएं भी आती हैं. हालांकि, हमें पता चला है कि इनसे मिलने वाले फ़ायदे, इन जटिलताओं से ज़्यादा हैं.

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

सर्विस वर्कर स्क्रिप्ट को मैन्युअल तरीके से लिखने से बचें. सर्विस वर्कर को मैन्युअल तरीके से लिखने के लिए, कैश मेमोरी में सेव किए गए संसाधनों को मैन्युअल तरीके से मैनेज करना पड़ता है. साथ ही, 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 बनाने के बारे में ज़्यादा जानकारी चाहिए, तो लेखक की हमारी प्रोफ़ाइलों पर जाएं और हमसे संपर्क करने का तरीका जानें: