Google'da PWA oluşturma, 1. bölüm

Bulletin ekibinin, PWA geliştirirken Service Worker'lar hakkında öğrendikleri.

Douglas Parker
Douglas Parker
Ali Rıza
Joel Riley
Dikla Cohen
Dikla Cohen

Bu, Google Bulletin ekibinin dışarıya yönelik bir PWA oluştururken öğrendiği dersler hakkındaki bir dizi blog yayınının ilkidir. Bu yayınlarda karşılaştığımız bazı zorlukları, bunları aşmak için uyguladığımız yaklaşımları ve tuzaklardan kaçınmanızı sağlayacak genel tavsiyeleri paylaşacağız. Bu, PWA'lara eksiksiz bir genel bakış sağlandığı anlamına gelmez. Amacımız, ekibimizin deneyimlerinden edindiğimiz bilgileri paylaşmaktır.

Bu ilk gönderide, öncelikle bazı temel bilgilere değineceğiz ve ardından Service Worker'lar hakkında öğrendiğimiz tüm noktaları ele alacağız.

Arka plan

Bulletin, 2017 yılının ortalarından 2019'un ortasına kadar aktif bir şekilde geliştirildi.

PWA oluşturmayı seçme nedenimiz

Geliştirme sürecine geçmeden önce, PWA geliştirmenin bu proje için neden cazip bir seçenek olduğuna göz atalım:

  • Hızlıca yineleme yapabilme. Bulletin'ın pilot uygulamaya geçirileceği birden fazla pazarda kullanıma sunulacağı için bu, özellikle değerliydi.
  • Tek kod tabanı. Kullanıcılarımız Android ve iOS arasında yaklaşık olarak eşit bir şekilde bölünmüştür. PWA, her iki platformda da çalışacak tek bir web uygulaması oluşturabileceğimiz anlamına geliyordu. Bu da ekibin hızını ve etkisini artırdı.
  • Hızlı ve kullanıcı davranışından bağımsız olarak güncellenir. PWA'lar otomatik olarak güncellenebilir. Bu da, kullanımdaki güncel olmayan istemci sayısını azaltır. Müşterilere çok kısa bir geçiş süresiyle son dakika arka uç değişikliklerini uygulayabildik.
  • Birinci ve üçüncü taraf uygulamalarıyla kolayca entegre edin. Bu tür entegrasyonlar uygulama için bir gereklilikti. PWA ile genellikle sadece bir URL açmak demek oluyordu.
  • Uygulama yükleme zorluğunu ortadan kaldırdı.

Çerçevemiz

Bulletin için Polymer'i kullandık ancak iyi desteklenen tüm modern çerçeveler işe yarayacaktır.

Service Worker'lar hakkında öğrendiklerimiz

Hizmet çalışanı olmadan PWA'ya sahip olamazsınız. Service Worker'lar size gelişmiş önbelleğe alma stratejileri, çevrimdışı özellikler, arka plan senkronizasyonu gibi birçok güç sağlar. Service Worker'lar biraz karmaşıklık eklese de sağladığı avantajların bu karmaşıklığa ağır bastığını gördük.

Mümkünse hesap oluşturun

Service Worker komut dosyasını elle yazmaktan kaçının. Service Worker'ları elle yazmak, önbelleğe alınan kaynakların manuel olarak yönetilmesini ve Workbox gibi çoğu Service Worker kitaplığında ortak olan yeniden yazma mantığını gerektirir.

Bununla birlikte, şirket içi teknoloji yığınımız nedeniyle hizmet çalışanlarımızı oluşturmak ve yönetmek için kitaplık kullanamadık. Aşağıda edindiğimiz bilgiler zaman zaman bunu yansıtmaktadır. Daha fazla bilgi için Oluşturulmayan hizmet çalışanları için tehlikeler bölümüne gidin.

Tüm kitaplıklar hizmet çalışanları ile uyumlu değildir

Bazı JS kitaplıkları, hizmet çalışanı tarafından çalıştırıldığında beklendiği gibi çalışmayan varsayımlarda bulunur. Örneğin, window veya document hizmetinin mevcut olduğu ya da hizmet çalışanlarının (XMLHttpRequest, yerel depolama alanı vb.) kullanımına sunulmayan bir API kullanıldığı varsayılır. Uygulamanız için ihtiyaç duyduğunuz kritik kitaplıkların hizmet çalışanları ile uyumlu olduğundan emin olun. Bu özel PWA için kimlik doğrulama amacıyla gapi.js'yi kullanmak istedik ancak hizmet çalışanlarını desteklemediğinden bunu yapamadık. Kütüphane yazarları; Service Worker'la uyumsuz API'lerden ve global durumdan kaçınmak gibi, mümkün olduğunda JavaScript bağlamıyla ilgili gereksiz varsayımları da azaltmalı veya kaldırmalıdır.

Başlatma sırasında IndexedDB'ye erişmekten kaçının

Service Worker komut dosyanızı başlatırken IndexedDB'yi okumayın. Aksi takdirde bu istenmeyen durum ortaya çıkabilir:

  1. Kullanıcının, IndexedDB (IDB) N sürümüne sahip web uygulaması var
  2. Yeni web uygulaması IDB N+1 sürümüyle aktarıldı
  3. Kullanıcı yeni hizmet çalışanının indirilmesini tetikleyen PWA'yı ziyaret eder
  4. Yeni hizmet çalışanı, install etkinlik işleyicisini kaydetmeden önce IDB'den okuma yapar ve N'den N+1'e giden bir IDB yükseltme döngüsü tetikler
  5. Kullanıcının sürümü N olan eski bir istemci olduğundan etkin bağlantılar veritabanının eski sürümüne hâlâ açık olduğundan hizmet çalışanı yükseltme işlemi kilitleniyor
  6. Hizmet çalışanı kilitleniyor ve hiç yüklenmiyor

Bizim örneğimizde, hizmet çalışanı yüklemesinde önbellek geçersiz kılınmıştır. Bu yüzden, hizmet çalışanı yükleme işlemi yapılmazsa kullanıcılar güncellenmiş uygulamayı hiç alamamıştır.

Dayanıklı hale getirin

Service Worker komut dosyaları arka planda çalışsalar da, G/Ç işlemlerinin (ağ, IDB vb.) ortasında bile herhangi bir zamanda sonlandırılabilir. Uzun süren herhangi bir süreç her an devam ettirilebilir olmalıdır.

Sunucuya büyük dosyalar yükleyip IDB'ye kaydedilen bir senkronizasyon işlemi durumunda, kesintiye uğrayan kısmi yükleme işlemleri için çözümümüz, dahili yükleme kitaplığımızın devam ettirilebilir sisteminden yararlanmak, devam ettirilebilir yükleme URL'sini yüklemeden önce IDB'ye kaydetmek ve ilk seferde tamamlanmamışsa yükleme işlemini devam ettirmek için bu URL'yi kullanmaktı. Ayrıca uzun süren herhangi bir G/Ç işleminden önce, her bir kayıt için sürecin hangi aşamasında olduğumuzu belirtmek amacıyla durum IDB'ye kaydediliyordu.

Global duruma bağlı kalmayın

Service Worker'lar farklı bir bağlamda mevcut olduğundan var olmasını beklediğiniz birçok simge mevcut değildir. Kodlarımızın çoğu hem window bağlamında hem de Service Worker bağlamında (ör. günlük kaydı, işaretlemeler, senkronizasyon vb.) çalışıyordu. Kodun yerel depolama veya çerezler gibi kullandığı hizmetleri savunması gerekir. Global nesneye tüm bağlamlarda çalışacak şekilde başvuruda bulunmak için globalThis kullanabilirsiniz. Komut dosyasının ne zaman sonlandırılacağı ve durumun ne zaman çıkarılacağı konusunda bir garanti olmadığı için genel değişkenlerde depolanan verileri de tutumlu bir şekilde kullanın.

Yerel geliştirme

Service Worker'ların önemli bir bileşeni, kaynakları yerel olarak önbelleğe almaktır. Ancak bu durum, geliştirme sırasında özellikle güncellemeler geçildikten sonra yapmak istediklerinizin tam tersi olur. Sunucu çalışanıyla ilgili hataları ayıklamak veya arka plan senkronizasyonu ya da bildirimler gibi diğer API'lerle çalışabilmek için sunucu çalışanının yüklü olmasını istersiniz. Chrome'da bu işlemi Chrome Geliştirici Araçları üzerinden gerçekleştirebilirsiniz. Bunun için, Chrome Geliştirici Araçları'nda Ağ için atla onay kutusunu (Uygulama paneli > Hizmet çalışanları bölmesi) etkinleştirerek ve bellek önbelleğini devre dışı bırakmak için panelindeki Önbelleği devre dışı bırak onay kutusunu etkinleştirebilirsiniz. Daha fazla tarayıcıyı kapsamak amacıyla, geliştirici yapılarında varsayılan olarak etkinleştirilen hizmet çalışanımıza önbelleğe almayı devre dışı bırakacak bir işaret ekleyerek farklı bir çözüm tercih ettik. Bu sayede geliştiriciler, önbelleğe alma sorunu yaşamadan en son değişikliklerini her zaman alır. Tarayıcının öğeleri önbelleğe almasını önlemek için Cache-Control: no-cache üst bilgisini de eklemek önemlidir.

Deniz Feneri

Lighthouse, PWA'lar için yararlı çeşitli hata ayıklama araçları sunar. Bir siteyi tarayıp PWA'lar, performans, erişilebilirlik, SEO ve diğer en iyi uygulamaları kapsayan raporlar oluşturur. Ölçütlerden birini PWA olacak şekilde ihlal ederseniz sizi uyarmak için Lighthouse'u sürekli entegrasyonda çalıştırmanızı öneririz. Bu, aslında Service Worker'ın yükleme yapmadığı bir zamanlar başımıza geldi. Ancak bunu üretime aktarmadan önce fark etmedik. CI'mızın bir parçası olarak Lighthouse'un olması bunu önlerdi.

Sürekli teslimi benimseyin

Service Worker'lar otomatik olarak güncellenebildiğinden, kullanıcıların yükseltmeleri sınırlama imkanı yoktur. Bu, büyük ölçüde güncelliğini yitirmiş istemcilerin sayısını önemli ölçüde azaltır. Kullanıcı uygulamamızı açtığında, hizmet çalışanı yeni istemciyi geç indirirken eski istemciye hizmet veriyordu. Yeni istemci indirildikten sonra, yeni özelliklere erişmek için kullanıcıdan sayfayı yenilemesi istenir. Kullanıcı bu isteği yoksaysa bile, sayfayı bir sonraki yenilemesinde istemcinin yeni sürümünü alırlar. Bu nedenle bir kullanıcının, iOS/Android uygulamalarında olduğu gibi güncellemeleri reddetmesi de oldukça zordur.

Müşterilere çok kısa bir taşıma süresiyle son dakika arka uç değişikliklerini uygulayabildik. Normalde, önemli değişiklikler yapmadan önce kullanıcıların yeni istemcilere geçmeleri için bir ay süre veririz. Uygulama eskiyken hizmet vereceği için, kullanıcı uygulamayı uzun bir süre açmamış olsaydı eski istemcilerin de halihazırda mevcut olması mümkündü. iOS'te, Service Worker'lar birkaç hafta sonra çıkarılır. Dolayısıyla bu durum yaşanmaz. Android için bu sorun, eskiyken sunulmaması veya içeriğin süresinin birkaç hafta sonra manuel olarak sonlandırılmasıyla azaltılabilir. Pratikte, eski istemcilerin neden olduğu sorunlarla hiç karşılaşmadık. Belirli bir ekibin burada ne kadar katı olmak istediği, kullanım alanına bağlıdır ancak PWA'lar iOS/Android uygulamalarından önemli ölçüde daha fazla esneklik sağlar.

Service Worker'da çerez değerlerini alma

Bazen hizmet çalışanı bağlamında çerez değerlerine erişmek gerekir. Örneğimizde, birinci taraf API isteklerinin kimliğini doğrulamak amacıyla bir jeton oluşturmak için çerez değerlerine erişmemiz gerekiyor. Service Worker'da document.cookies gibi eşzamanlı API'ler kullanılamaz. Çerez değerlerini istemek için Service Worker'dan etkin (pencereli) istemcilere her zaman mesaj gönderebilirsiniz. Ancak arka plan senkronizasyonu sırasında olduğu gibi, hizmet çalışanı herhangi bir pencereli istemci olmadan arka planda çalışabilir. Bu sorunu çözmek için ön uç sunucumuzda, çerez değerini istemciye tekrar eden bir uç nokta oluşturduk. Service Worker bu uç noktaya bir ağ isteği gönderir ve çerez değerlerini almak için yanıtı okur.

Cookie Store API'nin kullanıma sunulmasıyla birlikte, bu geçici çözümün destekleyen tarayıcılar için artık gerekli olmayacaktır. Bunun nedeni, bu API'nin tarayıcı çerezlerine eşzamansız erişim sağlaması ve hizmet çalışanı tarafından doğrudan kullanılabilmesidir.

Oluşturulmayan hizmet çalışanlarının tehlikeleri

Önbelleğe alınan statik dosyalar değiştiğinde hizmet çalışanı komut dosyasının değiştiğinden emin olun

Yaygın bir PWA kalıbı, hizmet çalışanının install aşaması sırasında tüm statik uygulama dosyalarını yüklemesidir. Bu, istemcilerin sonraki tüm ziyaretler için Cache Storage API önbelleğine doğrudan erişmesine olanak tanır. Service Worker'lar yalnızca tarayıcı, hizmet çalışanı komut dosyasının bir şekilde değiştiğini algıladığında yüklenir. Bu nedenle, önbelleğe alınan bir dosya değiştiğinde Service Worker komut dosyasının kendisini de mutlaka bir şekilde değiştirmemiz gerekiyordu. Bu işlemi manuel olarak yapmak için hizmet çalışanı komut dosyamıza statik kaynak dosya kümesinin bir karmasını yerleştirdik. Böylece her sürüm ayrı bir Service Worker JavaScript dosyası üretti. Workbox gibi hizmet çalışanı kitaplıkları, bu süreci sizin için otomatikleştirir.

Birim testi

Service Worker API'leri, global nesneye etkinlik işleyiciler ekleyerek çalışır. Örneğin:

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

Bu, test edilmesi zor olabilir çünkü etkinlik tetikleyicisi ve etkinlik nesnesiyle alay etmeniz, respondWith() geri çağırmasını beklemeniz ve son olarak sonuçla ilgili doğrulama yapmadan önce sözü beklemeniz gerekir. Bunu yapılandırmanın daha kolay bir yolu, tüm uygulamaları için başka bir dosyaya yetki vermektir. Bu, daha kolay test edilir.

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

Service Worker komut dosyalarının birim testinde karşılaşılan zorluklar nedeniyle, temel hizmet çalışanı komut dosyasını mümkün olduğunca sade tutup uygulamanın büyük kısmını diğer modüllere böldük. Bu dosyalar sadece standart JS modülleri olduğundan, standart test kitaplıklarıyla daha kolay bir şekilde birim testi yapılabilir.

2. ve 3. bölüm için bizi takip etmeye devam edin

Bu dizinin 2. ve 3. bölümlerinde medya yönetimi ve iOS'e özel sorunlardan bahsedeceğiz. Google'da PWA oluşturma hakkında daha fazla bilgi almak istiyorsanız yazar profillerimizi ziyaret ederek bizimle nasıl iletişime geçebileceğinizi öğrenin: