Membuat PWA di Google, bagian 1

Yang telah dipelajari tim Buletin tentang pekerja layanan saat mengembangkan PWA.

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

Ini adalah postingan pertama dari serangkaian postingan blog tentang pelajaran yang dipelajari tim Google Buletin saat membuat PWA yang dapat diakses secara eksternal. Dalam postingan ini, kami akan membagikan beberapa tantangan yang kami hadapi, pendekatan yang kami ambil untuk mengatasinya, dan saran umum untuk menghindari perangkap. Ini sama sekali bukan ringkasan lengkap tentang PWA. Tujuannya adalah berbagi pembelajaran dari pengalaman tim kami.

Untuk postingan pertama ini, kita akan membahas sedikit informasi latar belakang terlebih dahulu dan kemudian membahas semua hal yang telah kita pelajari tentang pekerja layanan.

Latar belakang

Buletin sedang dalam pengembangan aktif dari pertengahan 2017 hingga pertengahan 2019.

Alasan kami memilih untuk membuat PWA

Sebelum mempelajari proses pengembangan, mari kita pelajari mengapa membuat PWA menjadi opsi yang menarik untuk project ini:

  • Kemampuan untuk melakukan iterasi dengan cepat. Sangat bermanfaat karena Buletin akan diuji coba di beberapa pasar.
  • Basis kode tunggal. Pengguna kami terbelah secara merata antara Android dan iOS. Dengan PWA, kita dapat membuat satu aplikasi web yang akan berfungsi di kedua platform. Hal ini meningkatkan kecepatan dan dampak dari tim.
  • Diperbarui dengan cepat dan terpisah dari perilaku pengguna. PWA dapat otomatis diupdate, sehingga mengurangi jumlah klien lama. Kami dapat menerapkan perubahan backend yang dapat menyebabkan gangguan dengan waktu migrasi yang sangat singkat untuk klien.
  • Terintegrasi dengan mudah dengan aplikasi pihak pertama dan ketiga. Integrasi tersebut merupakan persyaratan untuk aplikasi. Dengan PWA, sering kali berarti hanya membuka URL.
  • Hilangnya hambatan penginstalan aplikasi.

Kerangka kerja kami

Untuk Buletin, kami menggunakan Polymer, tetapi framework modern apa pun yang didukung dengan baik akan dapat berfungsi.

Yang telah kita pelajari tentang pekerja layanan

Anda tidak dapat memiliki PWA tanpa pekerja layanan. Pekerja layanan memberi Anda banyak kemampuan, seperti strategi caching lanjutan, kemampuan offline, sinkronisasi latar belakang, dll. Meskipun pekerja layanan menambah kerumitan, kami mendapati bahwa manfaatnya lebih besar daripada kerumitan tambahannya.

Buatlah jika bisa

Hindari menulis skrip pekerja layanan secara manual. Menulis pekerja layanan secara manual memerlukan pengelolaan resource yang di-cache secara manual dan logika penulisan ulang yang umum dilakukan oleh sebagian besar library pekerja layanan, seperti Workbox.

Oleh karena itu, karena tech stack internal, kami tidak dapat menggunakan library untuk menghasilkan dan mengelola pekerja layanan kita. Pembelajaran kami di bawah ini terkadang akan mencerminkan hal tersebut. Buka Jebakan untuk pekerja layanan yang tidak dihasilkan untuk membaca selengkapnya.

Tidak semua library kompatibel dengan service worker

Beberapa library JS membuat asumsi yang tidak berfungsi seperti yang diharapkan saat dijalankan oleh pekerja layanan. Misalnya, dengan asumsi window atau document tersedia, atau penggunaan API tidak tersedia untuk pekerja layanan (XMLHttpRequest, penyimpanan lokal, dll.). Pastikan library penting apa pun yang diperlukan untuk aplikasi Anda kompatibel dengan pekerja layanan. Untuk PWA khusus ini, kami ingin menggunakan gapi.js untuk autentikasi, tetapi tidak dapat melakukannya karena tidak mendukung pekerja layanan. Penulis library juga harus mengurangi atau menghapus asumsi yang tidak diperlukan tentang konteks JavaScript jika memungkinkan untuk mendukung kasus penggunaan pekerja layanan, seperti dengan menghindari API yang tidak kompatibel dengan pekerja layanan dan menghindari status global.

Hindari mengakses IndexedDB selama inisialisasi

Jangan baca IndexedDB saat menginisialisasi skrip pekerja layanan, atau Anda akan masuk ke dalam situasi yang tidak diinginkan ini:

  1. Pengguna memiliki aplikasi web dengan IndexedDB (IDB) versi N
  2. Aplikasi web baru diluncurkan dengan IDB versi N+1
  3. Pengguna mengunjungi PWA, yang memicu download pekerja layanan baru
  4. Pekerja layanan baru membaca dari IDB sebelum mendaftarkan pengendali peristiwa install, sehingga memicu siklus upgrade IDB untuk beralih dari N ke N+1
  5. Karena pengguna memiliki klien lama dengan versi N, proses upgrade pekerja layanan terhenti karena koneksi aktif masih terbuka ke database versi lama
  6. Pekerja layanan hang, dan tidak pernah menginstal

Dalam kasus kita, cache menjadi tidak valid pada penginstalan pekerja layanan, sehingga jika pekerja layanan tidak pernah diinstal, pengguna tidak akan pernah menerima aplikasi yang telah diupdate.

Membuatnya tangguh

Meskipun skrip pekerja layanan berjalan di latar belakang, skrip tersebut juga dapat dihentikan kapan saja, bahkan saat berada di tengah-tengah operasi I/O (jaringan, IDB, dll.). Setiap proses yang berjalan lama harus dapat dilanjutkan kapan saja.

Dalam kasus proses sinkronisasi yang mengupload file besar ke server dan disimpan ke IDB, solusi kami untuk upload parsial yang terputus adalah dengan memanfaatkan sistem library upload internal kami yang dapat dilanjutkan, menyimpan URL upload yang dapat dilanjutkan ke IDB sebelum mengupload, dan menggunakan URL tersebut untuk melanjutkan upload jika tidak selesai pertama kali. Selain itu, sebelum operasi I/O yang berjalan lama, status disimpan ke IDB untuk menunjukkan posisi kita dalam proses untuk setiap kumpulan data.

Jangan bergantung pada status global

Karena pekerja layanan berada dalam konteks yang berbeda, banyak simbol yang mungkin Anda kira tidak ada. Banyak kode kami berjalan dalam konteks window, serta konteks pekerja layanan (seperti logging, flag, sinkronisasi, dll.). Kode harus bersifat defensif terkait layanan yang digunakannya, seperti penyimpanan lokal atau cookie. Anda dapat menggunakan globalThis untuk merujuk ke objek global dengan cara yang akan berfungsi di semua konteks. Selain itu, jangan terlalu sering menggunakan data yang disimpan dalam variabel global, karena tidak ada jaminan terkait kapan skrip akan dihentikan dan status akan dihapus.

Pengembangan lokal

Komponen utama pekerja layanan adalah meng-cache resource secara lokal. Namun, selama pengembangan, hal ini adalah kebalikan yang Anda inginkan, terutama jika update dilakukan dengan lambat. Anda tetap ingin pekerja server diinstal agar dapat men-debug masalah terkaitnya atau menggunakan API lain seperti sinkronisasi latar belakang, atau notifikasi. Di Chrome, Anda dapat melakukannya melalui Chrome DevTools dengan mengaktifkan kotak centang Abaikan untuk jaringan (panel Application > panel Service worker) selain mengaktifkan kotak centang Disable cache di panel Network untuk juga menonaktifkan cache memori. Untuk mencakup lebih banyak browser, kami memilih solusi lain dengan menyertakan tanda untuk menonaktifkan penyimpanan cache di pekerja layanan kami yang diaktifkan secara default pada build developer. Hal ini memastikan bahwa developer selalu mendapatkan perubahan terbaru tanpa masalah penyimpanan dalam cache. Penting untuk menyertakan header Cache-Control: no-cache juga untuk mencegah browser menyimpan aset apa pun dalam cache.

Mercusuar

Lighthouse menyediakan sejumlah alat proses debug yang berguna untuk PWA. Fitur ini memindai situs dan menghasilkan laporan yang mencakup PWA, performa, aksesibilitas, SEO, dan praktik terbaik lainnya. Sebaiknya jalankan Lighthouse pada continuous integration untuk memberi tahu Anda jika Anda melanggar salah satu kriteria untuk menjadi PWA. Hal ini sebenarnya pernah terjadi pada kita, saat pekerja layanan tidak melakukan penginstalan dan kami tidak menyadarinya sebelum proses produksi dimulai. Memiliki Lighthouse sebagai bagian dari CI kita akan dapat mencegah hal itu.

Mendukung continuous delivery

Karena pekerja layanan dapat mengupdate secara otomatis, pengguna tidak memiliki kemampuan untuk membatasi upgrade. Hal ini secara signifikan mengurangi jumlah klien yang sudah usang. Saat pengguna membuka aplikasi kita, pekerja layanan akan melayani klien lama selagi mendownload klien baru dengan lambat. Setelah didownload, klien baru akan meminta pengguna untuk memuat ulang halaman guna mengakses fitur baru. Meskipun pengguna mengabaikan permintaan ini, saat berikutnya mereka memuat ulang halaman, mereka akan menerima klien versi baru. Akibatnya, pengguna cukup sulit menolak update dengan cara yang sama seperti yang mereka lakukan untuk aplikasi iOS/Android.

Kami dapat menerapkan perubahan backend yang dapat menyebabkan gangguan dengan waktu migrasi yang sangat singkat untuk klien. Biasanya, kami akan memberikan waktu satu bulan bagi pengguna untuk memberikan update ke klien yang lebih baru sebelum melakukan perubahan yang dapat menyebabkan gangguan. Karena aplikasi akan ditayangkan meskipun sudah tidak berlaku, sebenarnya masih ada kemungkinan klien lama tetap ada di luar jika pengguna tidak membuka aplikasi dalam waktu yang lama. Di iOS, pekerja layanan dikeluarkan setelah beberapa minggu sehingga hal ini tidak terjadi. Untuk Android, masalah ini dapat dimitigasi dengan tidak menayangkan konten saat sudah tidak berlaku, atau mengakhiri konten secara manual setelah beberapa minggu. Pada praktiknya, kami tidak pernah menghadapi masalah dari klien yang sudah basi. Seberapa ketat tim tertentu ingin berada di sini bergantung pada kasus penggunaan spesifik mereka, tetapi PWA memberikan fleksibilitas yang jauh lebih banyak daripada aplikasi iOS/Android.

Mendapatkan nilai cookie di pekerja layanan

Terkadang perlu untuk mengakses nilai cookie dalam konteks pekerja layanan. Dalam kasus ini, kita perlu mengakses nilai cookie untuk membuat token guna mengautentikasi permintaan API pihak pertama. Dalam pekerja layanan, API sinkron seperti document.cookies tidak tersedia. Anda dapat mengirim pesan ke klien aktif (berjendela) kapan saja dari pekerja layanan untuk meminta nilai cookie, meskipun pekerja layanan dapat berjalan di latar belakang tanpa klien berjendela apa pun yang tersedia, seperti selama sinkronisasi latar belakang. Untuk mengatasi hal ini, kita membuat endpoint di server frontend yang meneruskan nilai cookie kembali ke klien. Pekerja layanan membuat permintaan jaringan ke endpoint ini dan membaca respons untuk mendapatkan nilai cookie.

Dengan dirilisnya Cookie Store API, solusi ini seharusnya tidak diperlukan lagi oleh browser yang mendukungnya, karena solusi ini menyediakan akses asinkron ke cookie browser dan dapat digunakan langsung oleh pekerja layanan.

Perangkap untuk pekerja layanan non-hasil

Memastikan skrip pekerja layanan berubah jika ada perubahan file yang di-cache statis

Pola PWA yang umum adalah pekerja layanan menginstal semua file aplikasi statis selama fase install-nya, yang memungkinkan klien mencapai cache Cache Storage API secara langsung untuk semua kunjungan berikutnya . Pekerja layanan hanya diinstal saat browser mendeteksi bahwa skrip pekerja layanan telah berubah dengan cara tertentu. Jadi, kita harus memastikan file skrip pekerja layanan itu sendiri berubah dengan cara tertentu saat file yang di-cache berubah. Kami melakukannya secara manual dengan menyematkan hash file resource statis dalam skrip pekerja layanan, sehingga setiap rilis menghasilkan file JavaScript pekerja layanan yang berbeda. Library pekerja layanan seperti Workbox mengotomatiskan proses ini untuk Anda.

Pengujian unit

API pekerja layanan berfungsi dengan menambahkan pemroses peristiwa ke objek global. Contoh:

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

Hal ini mungkin merepotkan untuk diuji karena Anda perlu meniru pemicu peristiwa, objek peristiwa, menunggu callback respondWith(), lalu menunggu promise, sebelum akhirnya menyatakan hasilnya. Cara yang lebih mudah untuk menyusunnya adalah dengan mendelegasikan semua implementasi ke file lain, yang lebih mudah diuji.

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

Karena kesulitan pengujian unit skrip pekerja layanan, kami membuat skrip pekerja layanan inti sesederhana mungkin, membagi sebagian besar implementasi menjadi modul lainnya. Karena file-file tersebut hanya modul JS standar, file dapat lebih mudah diuji unit dengan library pengujian standar.

Nantikan bagian 2 dan 3

Di bagian 2 dan 3 seri ini, kami akan membahas tentang pengelolaan media dan masalah khusus iOS. Jika Anda ingin bertanya lebih lanjut tentang cara membuat PWA di Google, kunjungi profil penulis kami untuk mengetahui cara menghubungi kami: