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

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

डगलस पार्कर
डगलस पार्कर
जोएल रिले
जोएल रिले
डिक्ला कोहेन
डिक्ला कोहेन

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

इस पहली पोस्ट में हम पहले थोड़ी पृष्ठभूमि जानकारी कवर करेंगे और फिर सेवा कर्मियों के बारे में सीखी गई सारी चीज़ों के बारे में चर्चा करेंगे.

बैकग्राउंड

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

हमने PWA को बनाने का फ़ैसला क्यों किया

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

किसी भी आपदा का सामना करने के लिए तैयार करें

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

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

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

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

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

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

लाइटहाउस

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

लगातार डिलीवरी की सुविधा अपनाएं

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

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

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

कभी-कभी सर्विस वर्कर के मामले में, कुकी वैल्यू को ऐक्सेस करना ज़रूरी होता है. हमारे मामले में, पहले-पक्ष के एपीआई अनुरोधों की पुष्टि करने के लिए, हमें टोकन जनरेट करने के लिए कुकी की वैल्यू को ऐक्सेस करने की ज़रूरत होती है. किसी सर्विस वर्कर में, 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 मॉड्यूल थीं, इसलिए स्टैंडर्ड टेस्ट लाइब्रेरी की मदद से उनकी यूनिट की जांच ज़्यादा आसानी से की जा सकती थी.

दूसरे और तीसरे चरण के बारे में जानने के लिए, हमारे साथ बने रहें

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