Cara Membuat Progressive Web App Pertama


Pada codelab sebelumnya kita telah membuat SPA sederhana menggunakan framework Materialize CSS dan juga beberapa kode JavaScript untuk membuat pergantian konten halaman. Namun belum sempurna bila dikatakan kita telah menggunakan app shell pada SPA kita.

Karena meskipun halaman sudah tidak memuat ulang saat berpindah halaman sebagaimana website multi halaman, tetapi app shell masih tidak tampil pada kondisi perangkat offline atau tanpa koneksi.

Dengan kata lain app shell kita belum berlaku seperti aplikasi native yang tetap menampilkan komponen UI meskipun dalam kondisi offline. Untuk dapat melakukan hal tersebut, kita membutuhkan dua teknologi web browser yaitu Service Worker dan Cache.

Registrasi Service Worker

Service Worker adalah skrip yang dijalankan oleh browser di latar belakang, yang terpisah dengan skrip lain di halaman web browser. Service worker ditulis menggunakan bahasa pemrograman JavaScript, namun dipanggil dengan cara yang berbeda dari kode JavaScript pada umumnya. Dalam studi kasus kita kali ini, service worker berlaku sebagai pengatur jalur request dengan memilah aset mana yang sudah ada di cache untuk langsung digunakan, dan aset mana yang perlu dimintakan dahulu ke jaringan.

Cara memanggil kode service worker sedikit berbeda dengan kode JavaScript pada umumnya. Umumnya, kita menyisipkan berkas kode atau library JavaScript menggunakan tag <script> pada halaman. Sedangkan untuk memanggil berkas service worker, kita menggunakan method navigator.serviceWorker.register('/service-worker.js').

Pre-cache Aset

Di dalam berkas service-worker.js tuliskan kode untuk menyimpan aset ke dalam cache serta menyuplai aset yang sudah ada di cache agar dapat digunakan pada pemanggilan halaman kedepannya. Untuk mendaftarkan aset ke dalam cache, kita menggunakan API Cache dari browser, di antaranya caches.open() untuk membuka cache, caches.add() dan cache.addAll() untuk menyimpan aset ke cache, dan caches.match() untuk mengecek apakah aset yang diminta sudah ada di dalam cache. Cache API sudah berbasis promise. Bila kamu belum familiar dengan promise, kamu dapat pelajari pada bab "Promise dan Fetch API".

Materi Service worker dan Cache API dapat kamu pelajari lebih dalam pada bab selanjutnya. Sekarang kita akan melanjutkan codelab selanjutnya agar aplikasi kita dapat tetap menampilkan komponen UI meskipun dalam kondisi jaringan offline.

Di codelab yang pertama ini, kita akan mengubah single page application yang telah dibuat ditutorial sebelumnya untuk menerapkan fitur-fitur PWA satu demi satu secara progresif. Langkah paling awal ialah dengan mendaftarkan sebuah service worker ke aplikasi yang sudah dibuat.

Mendaftarkan Service Worker

Buat file dengan nama service-worker.js di dalam folder project. Biarkan kosong terlebih dahulu.
Kemudian buka kembali file index.html dan tambahkan kode berikut di bagian paling bawah sebelum tag tutup </body>:

<script>
// REGISTER SERVICE WORKER
if ("serviceWorker" in navigator) {
window.addEventListener("load", function() {
navigator.serviceWorker
.register("/service-worker.js")
.then(function() {
console.log("Pendaftaran ServiceWorker berhasil");
})
.catch(function() {
console.log("Pendaftaran ServiceWorker gagal");
});
});
} else {
console.log("ServiceWorker belum didukung browser ini.");
}
</script>

Pada kode di atas kita mengecek terlebih dahulu apakah object navigator sudah ada di browser. Artinya bila object tersebut tidak ada, tandanya browser yang digunakan belum mendukung fitur service worker, karena service worker berjalan di dalam object navigator.

Kemudian kita mendaftarkan file service-worker.js menggunakan method navigator.serviceWorker.register().

Proses registrasi akan berhasil hanya pada website dengan domain https:// atau http:// (hanya diperbolehkan saat development). Muat ulang aplikasimu dan Kamu akan dapat mengecek apakah proses registrasi berhasil atau gagal pada panel Chrome DevTools di tab Application bagian Service Worker (dapat diakses di menu sebelah kiri Application):

201811270018215595b1dbe4d162adf74e603e646b29e2.png

Pada tab console pun kita bisa melihat pesan log dari kode registrasi service worker yang mengindikasikan apakah service worker berhasil atau gagal didaftarkan.

Menyimpan Aset ke Cache

Sekarang kita akan menulis kode service worker pada file service-worker.js. Tambahkan kode berikut di dalam file tersebut:
const CACHE_NAME = "firstpwa";
var urlsToCache = [
"/",
"/nav.html",
"/index.html",
"/pages/home.html",
"/pages/about.html",
"/pages/contact.html",
"/css/materialize.min.css",
"/js/materialize.min.js",
"/js/nav.js"
];

self.addEventListener("install", function(event) {
event.waitUntil(
caches.open(CACHE_NAME).then(function(cache) {
return cache.addAll(urlsToCache);
})
);
});

Pada kode di atas, kita membuat variabel konstanta CACHE_NAME berisi string yang nanti akan kita gunakan sebagai nama cache. Kita juga membuat variabel urlsToCache untuk memudahkan menulis daftar aset dan halaman mana saja yang akan disimpan ke dalam cache.

Kemudian kita daftarkan event listener untuk event install yang akan dipanggil setelah proses registrasi service worker berhasil. Di dalamnya kita membuka cache dengan nama yang sudah kita tulis. Bila belum ada maka cache baru dengan nama tersebut akan dibuat. Setelah cache dibuka, kita langsung menyimpan aset ke dalam cache tersebut sejumlah daftar aset yang sudah kita buat pada variable urlsToCache menggunakan method cache.addAll().

Bila kode berjalan baik, maka seharusnya aset tadi akan terdaftar pada cache browser. Kamu dapat mengecek cache yang sudah terdaftar pada DevTools tab Application bagian Cache Storage. Klik tanda segitiga di sebelah kiri menu Cache Storage untuk melihat daftar cache.

201811270018524d796d9ddad59b91cf230ebee4275eae.png

Sampai sini kita baru menyimpan aset ke cache. Bila kamu cek tab Network dan refresh halaman, halaman masih menggunakan aset dari hasil request ke server.

20181127001917f4f16c969baea2e940d392d646b32fc2.png

Pada contoh gambar di atas, nampak kolom Size masih menampilkan ukuran aset hasil pemuatan dari server.

Menggunakan Aset dari Cache

Tambahkan kode berikut pada file service-worker.js agar halaman menggunakan aset yang sudah disimpan di cache:
self.addEventListener("fetch", function(event) {
event.respondWith(
caches
.match(event.request, { cacheName: CACHE_NAME })
.then(function(response) {
if (response) {
console.log("ServiceWorker: Gunakan aset dari cache: ", response.url);
return response;
}

console.log(
"ServiceWorker: Memuat aset dari server: ",
event.request.url
);
return fetch(event.request);
})
);
});

Pada kode di atas kita mendaftarkan event listener untuk event fetch dari service worker, yang akan dipanggil setiap kali browser mengirimkan request ke jaringan seperti memuat halaman, css, js, aset grafis dan font.

Terlebih dahulu kita cek apakah request cocok dengan salah satu aset yang sudah tersimpan di dalam cache. Bila ada yang cocok maka kita kembalikan aset tersebut untuk dapat langsung digunakan di halaman. Bila tidak ditemukan maka baru kita lanjutkan mengirim request menggunakan method fetch().

Bila sekarang kamu refresh kembali halaman, kamu akan lihat pada tab Network aplikasi masih belum menggunakan aset dari cache. Hal ini disebabkan karena service worker yang aktif masih kode yang lama.

Browser akan menunggu proses pengaktifan sampai kita membuka aplikasi pada sesi yang baru. Satu sesi dihitung selama kita membuka aplikasi sampai kita menutup tab browser atau jendela browsernya.

201811270020411a347df143d184ee76e78963c4442190.png
Pada gambar di atas kita lihat status service worker yang aktif dan berjalan masih versi yang lama, dan versi terbaru yang sudah kita tambahkan kode event listener fetch sudah diterima tapi belum diaktifkan.

Untuk mengaktifkan service worker yang terbaru, kamu dapat menutup terlebih dahulu tab browser aplikasi tersebut kemudian membuka lagi untuk mendapat sesi baru. Namun cara ini kurang efisien dalam proses pengembangan.

Cara yang lebih mudah adalah dengan mengklik tautan skipWaiting yang ada di samping status service worker yang terbaru. Atau agar lebih efisien lagi, kamu dapat mengaktifkan ceklis opsi Update on reload di bagian atas panel Service Workers. Dengan demikian browser akan langsung mengaktifkan service worker setiap kali ada pembaharuan.

Setelah service worker yang terbaru diaktifkan, kamu dapat memuat ulang halaman dan sekarang seharusnya halaman sudah menggunakan aset dari cache, ditunjukkan pada kolom Size yang sekarang sudah tertulis bahwa aset disuplai dari service worker.

20181127002114631e08f97fa9687baa42de35c3d80081.png

Sekarang kamu dapat mencoba memanggil halaman dalam mode offline untuk memastikan aplikasi tetap tampil meskipun tidak terhubung ke jaringan. Kamu dapat mematikan web server, atau pada tab Network di DevTools, kamu dapat mengaktifkan ceklis opsi Offline di bagian atas panel untuk mensimulasikan mode jaringan offline.

201811270021577f98ce60027a281e5125a1039f65e88e.png

Selamat, kamu telah menerapkan fitur utama dari service worker yakni akses offline. Dengan demikian pengguna aplikasimu tetap dapat mengakses aplikasi meskipun sudah tidak terhubung ke internet!

Menghapus Cache Lama

Apa yang terjadi bila kita mengubah konten dari halaman aplikasi, atau mengubah kode CSSnya? Yup, Kamu tidak akan melihat perubahan apapun di halaman browser karena tampilan aplikasi menggunakan aset dari cache. Tapi bila kamu mengaktifkan opsi Update on reload di panel Service Workers pada DevTools maka semua perubahan konten dan aset akan diperbaharui ke dalam cache setiap kali kita me-refresh halaman aplikasi.

Opsi Update on reload sangat berguna dalam proses pengembangan aplikasi. Namun opsi ini tidak dapat diandalkan ketika aplikasi sudah dirilis ke pengguna, karena kita tidak dapat memaksa pengguna untuk membuka DevTools dan mengaktifkan opsi tersebut. Terlebih bila pengguna membuka aplikasi melalui perangkat mobile.

Solusinya agar pembaharuan terjadi di sisi pengguna adalah dengan mengganti nama cache yang digunakan di service worker.

Bila sebelumnya nama cache kita adalah firstpwa, maka kita dapat mengganti dengan nama lain. Biasa kita cukup menambahkan penanda versi agar kita pun mudah dalam melacak perubahan apa yang sudah dilakukan, misalnya kita ubah nama cache menjadi firstpwa-v1, firstpwa-v2 dan seterusnya. Intinya setiap kali kamu merilis pembaharuan aplikasi ke pengguna, kamu harus memastikan untuk juga mengubah nama cachenya.

Sekarang coba buat beberapa perubahan kecil pada halaman (konten atau CSS) dan ganti nama cachenya di file service-worker.js:

const CACHE_NAME = 'firstpwa-v1';

Maka bila halaman aplikasi di-refresh, hasil perubahan akan muncul dan cache yang baru pun akan dibuat.

2018112700223626354ae31308480dffc0b623f44d56d3.png

Masalah baru akan muncul. Semakin sering kita mengganti nama cache, maka akan banyak cache sampah di browser pengguna dan tentunya akan memakan ruang penyimpanan perangkat milik si pengguna. Untuk itu kita harus membuat mekanisme penghapusan cache yang lama agar tidak membebani pengguna. Tambahkan kode berikut di bagian akhir file service-worker.js:

self.addEventListener("activate", function(event) {
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheName != CACHE_NAME) {
console.log("ServiceWorker: cache " + cacheName + " dihapus");
return caches.delete(cacheName);
}
})
);
})
);
});

Pada kode di atas kita mendaftarkan event listener untuk event activate service worker yang akan dipanggil saat service worker diaktifkan, sesaat setelah proses instalasi service worker.

Pertama-tama kita ambil dahulu semua nama cache yang sudah terdaftar. Kemudian satu per satu kita cek bila nama cachenya tidak sama dengan nama cache yang sedang digunakan oleh service worker, maka kita panggil di dalam method caches.delete() untuk dihapus.

Kamu dapat mencoba membuka kembali aplikasimu dan melihat sekarang cache yang ada di dalam Cache Storage browser hanya akan tertinggal cache yang sedang digunakan saja.

Menambahkan Aplikasi ke Home Screen

Add to Home Screen atau yang sering juga disebut dengan web app install prompt dibuat untuk mempermudah pengguna untuk memasang aplikasi PWA kita di perangkat mobile atau desktop. Tidak hanya mempermudah pengguna untuk membuka kembali aplikasi kita, menambahkan ikon aplikasi ke home screen juga punya efek yang lebih besar yakni memperkuat ikatan dengan pengguna.

Sebagaimana telah diulas di bagian Pendahuluan, salah satu kelebihan PWA adalah antarmuka seperti aplikasi native. Bila seseorang mengakses sebuah website PWA, maka ia dapat menambahkan shortcut ke halaman depan dari sebuah perangkat. Sehingga untuk selanjutnya pengguna tersebut tinggal menjalankan aplikasi PWA tadi dengan membuka shortcut yang sudah tersedia seperti halnya bila hendak membuka aplikasi native.

Tampilan aplikasinya pun sudah seperti aplikasi native, tidak ada lagi address bar dan tombol-tombol lain seperti bila kita buka melalui browser.

Agar sebuah PWA bisa dipasang ke home screen, aplikasi kita harus memenuhi beberapa kriteria berikut:
  • Belum pernah terpasang pada perangkat
  • Memenuhi user engagement heuristic (yakni syarat dimana pengguna harus berinteraksi dengan aplikasi yang bersangkutan sekurang-kurangnya 30 detik).
  • Memiliki web app manifest yang memiliki atribut:
    • name atau short_name
    • icons dengan ukuran 192x192 atau 512x512
    • start_url
    • display harus bernilai fullscreen, standalone, atau minimal-ui.
  • Harus menggunakan HTTPS (agar service worker bisa bekerja)
  • Memiliki sebuah service worker dengan sebuah event handlerfetch.

Mendaftarkan Web App Manifest

Web app manifest atau yang sering disingkat dengan app manifest adalah sebuah file JSON yang menyimpan informasi dari sebuah aplikasi web seperti nama aplikasi, pengembang, gambar ikon, warna tema, dan sebagainya. Sebuah web app manifest didaftarkan melalui elemen link yang disimpan di dalam tag head di setiap halaman HTML seperti saat kita akan menggunakan CSS eksternal.

Ubah kode index.html yang telah kita buat di modul sebelumnya untuk mendaftarkan sebuah web app manifest. Simpan kode berikut di dalam elemen <head>:

<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#00897B"/>
Selanjutnya, buat sebuah file bernama manifest.json di folder project berdampingan dengan index.html dan isikan dengan konten berikut ini:
{
"name": "My First PWA",
"short_name": "My PWA",
"description": "Aplikasi PWA pertama saya",
"start_url": "/index.html",
"display": "standalone",
"background_color": "#00897B",
"theme_color": "#00897B",
"icons": [
{
"src": "icon.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

Terakhir simpan file icon berikut di dalam folder project dan beri nama icon.png. Kamu dapat mengunduhnya pada url berikut: LINK. kamu juga dapat menggunakan gambar lain asalkan berukuran persegi minimal 512x512 pixel.

201811270023440f91a586db04ac7f63dcb26013a084ca.png
Perhatian: Kamu juga akan perlu menambahkan path icon.png ini ke dalam daftar aset yang akan dicache di service worker. Jangan lupa untuk memperbaharui nama cachenya juga.

Atribut-atribut Web App Manifest

Sebelum melanjutkan, mari kita bahas atribut-atribut apa saja yang bisa kita masukkan ke dalam sebuah web app manifest.
  • name dan short_name
    Jika ingin menggunakan web app manifest, kita wajib menambahkan salah satu dari name atau short_name. Sesuai dengan namanya, atribut ini berisi nama aplikasi kita. Atribut name bisa berisi teks sepanjang maksimum 45 karakter dan ditampilkan di jendela pemasangan, jendela extension management, dan Chrome Web Store. Sementara itu, short_name dapat berisi teks sepanjang maksimum 12 karakter dan pada umumnya dipakai oleh launcher aplikasi (di home screen), dan halaman new tab.
  • description
    Atribut ini berisi teks sepanjang maksimal 132 karakter untuk mendeskripsikan aplikasi secara singkat. Teks harus berisi plain text tanpa ada kode HTML atau format lainnya.
  • start_url
    Atribut start_url berfungsi untuk memberitahu browser halaman apa yang harus dibuka saat pengguna mengakses aplikasi lewat home screen. Kita boleh menambahkan query string di atribut ini sebagai sarana melakukan tracking untuk aplikasi semacam analytics.
  • display
    Kita bisa mengatur bagaimana browser menampilkan aplikasi saat diluncurkan. Ada beberapa nilai yang bisa kita berikan untuk atribut display diantaranya:
    • fullscreen: Membuka aplikasi tanpa antarmuka browser dan mengambil seluruh ruang di layar.
    • standalone: Membuka aplikasi dan menampilkannya seperti aplikasi native. Aplikasi akan memiliki jendela sendiri yang terpisah dari browser serta menyembunyikan UI browser seperti address bar.
    • minimal-ui: Mirip seperti fullscreen akan tetapi memiliki akses navigasi minimalis seperti tombol back, forward, reload, dll.
    • browser: Membuka aplikasi di browser seperti web biasa.
  • theme_color
    Atribut theme_color dipakai untuk menentukan warna tool bar, dan warna yang ditampilkan saat pengguna membuka task switcher.
  • background_color
    Atribut ini dipakai untuk menentukan warna latar belakang splash screen saat aplikasi diluncurkan. Bila tidak diset, warna latar splash screen akan berwarna putih.
  • icons
    Kita bisa menentukan gambar yang akan ditampilkan untuk mewakili aplikasi kita di saat pengguna menambahkannya ke home screen. Gambar yang ditentukan di dalam atribut icons akan digunakan dibeberapa tempat selain home screen yaitu, app launcher, task switcher, splash screen, dsb.
    Atribut ini memiliki 3 subatribut, diantaranya:
    • sizes: string berisi ukuran gambar dengan format penulisan 'widthxheight'
    • src: path dari gambar yang akan digunakan. Bila menggunakan path relatif, maka base urlnya akan menggunakan base url yang sama dengan dimana file manifest ini disimpan
    • type: tipe gambar yang digunakan
  • Meski di contoh sebelumnya kita hanya menentukan satu gambar ikon, kita bisa menentukan sampai dengan 6 ukuran atau lebih yang akan disesuaikan oleh browser sesuai dengan ukuran dan resolusi layar perangkat. Keenam ukuran yang bisa diatur seperti misalnya: 72x72, 96x96, 128x128, 144x144, 192x192, 256x256, 384x384, dan 512x512. Umumnya satu icon dengan ukuran 512x512 sudah mencukupi untuk sebagian besar kasus. Berikut ini contoh deklarasi atribut icons lebih dari satu ukuran:
  "icons": [
{
"src": "icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],

Menguji Web App Manifest

Untuk memastikan bahwa web app manifest kita telah berhasil di daftarkan, silahkan buka kembali aplikasi PWA di Chrome lalu buka tab Application di jendela Chrome Dev Tools dan pilih menu Manifest di sebelah kiri. Periksa bahwa atribut-atribut yang tadi telah kita definisikan di dalam file manifest.json di sini.

20181127002406cad30521df7d949d83ffb8a42efb8242.png

Pada jendela Manifest, bila kita mengatur file manifest dengan benar, mestinya akan muncul deskripsi seperti pada gambar di atas. Nampak atribut-atribut manifest yang sudah kita set sebelumnya.

Kita juga dapat melihat daftar atribut lain yang masih kosong karena memang belum kita atur di dalam file manifest.

Web App Manifest Generator

Konten App Manifest tidak begitu rumit untuk diingat. Akan tetapi, jika pembaca kesulitan mengingat struktur komponen yang menyusun sebuah App Manifest, terdapat sebuah layanan web yang membantu penulisannya melalui sebuah form.

Dengan menekan tombol ENTER kita akan mendapatkan sebuah file JSON yang langsung bisa disalin berdasarkan nilai-nilai yang telah dimasukkan ke dalam form.

Web App Manifest Generator dapat diakses pada halaman https://app-manifest.firebaseapp.com.
2018112700243497c8eedab069742e71fe4681de07589a.png

Codelab ini dapat Anda unduh pada tautan berikut ini :

Untuk Belajar Lebih Lanjut anda bisa cek github ini: 


Jangan lupa untuk pelajari juga:

  • Service Worker
  • Cache API
  • IndexedDB
  • Push API
  • Layanan Push Notification (FCM)
  • Notification Payload dengan Web Push
  • Library Workbox
  • Routing di Workbox
  • Deploy PWA di Firebase Hosting

Komentar