Apa kesamaan antara aplikasi Asisten Google, aplikasi Slack, aplikasi Zoom, dan hampir semua aplikasi khusus platform lainnya di ponsel atau komputer Anda? Benar, setidaknya selalu memberi Anda sesuatu. Meskipun tidak memiliki koneksi jaringan, Anda masih dapat membuka aplikasi Asisten, masuk ke Slack, atau meluncurkan Zoom. Anda mungkin tidak mendapatkan sesuatu yang sangat berarti atau bahkan tidak dapat mencapai apa yang ingin dicapai, tetapi setidaknya Anda mendapatkan sesuatu dan aplikasi berada dalam kontrol.
Sebaliknya, di Web, biasanya Anda tidak mendapatkan apa pun saat offline. Chrome memberi Anda game dino offline, dan ini saja.
Halaman penggantian offline dengan pekerja layanan kustom
Namun, sebenarnya tidak harus seperti ini. Berkat pekerja layanan dan Cache Storage API, Anda dapat memberikan pengalaman offline yang disesuaikan bagi pengguna. Halaman ini dapat berupa halaman bermerek sederhana dengan informasi bahwa pengguna sedang offline, tetapi juga bisa menjadi solusi yang lebih kreatif, seperti, misalnya, game labirin offline trivago yang terkenal dengan tombol Hubungkan kembali manual dan hitung mundur upaya koneksi ulang otomatis.
Mendaftarkan pekerja layanan
Cara untuk melakukannya adalah melalui pekerja layanan. Anda dapat mendaftarkan pekerja layanan dari halaman utama seperti dalam contoh kode di bawah ini. Biasanya Anda melakukannya setelah aplikasi dimuat.
window.addEventListener("load", () => {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("service-worker.js");
}
});
Kode pekerja layanan
Konten file pekerja layanan yang sebenarnya mungkin tampak sedikit rumit pada awalnya, tetapi
komentar dalam contoh di bawah ini akan menjelaskan semuanya. Ide utamanya adalah melakukan pra-cache file bernama offline.html
yang hanya ditayangkan pada permintaan navigasi yang gagal, dan memungkinkan browser menangani semua kasus lainnya:
/*
Copyright 2015, 2019, 2020, 2021 Google LLC. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Incrementing OFFLINE_VERSION will kick off the install event and force
// previously cached resources to be updated from the network.
// This variable is intentionally declared and unused.
// Add a comment for your linter if you want:
// eslint-disable-next-line no-unused-vars
const OFFLINE_VERSION = 1;
const CACHE_NAME = "offline";
// Customize this with a different URL if needed.
const OFFLINE_URL = "offline.html";
self.addEventListener("install", (event) => {
event.waitUntil(
(async () => {
const cache = await caches.open(CACHE_NAME);
// Setting {cache: 'reload'} in the new request ensures that the
// response isn't fulfilled from the HTTP cache; i.e., it will be
// from the network.
await cache.add(new Request(OFFLINE_URL, { cache: "reload" }));
})()
);
// Force the waiting service worker to become the active service worker.
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(
(async () => {
// Enable navigation preload if it's supported.
// See https://developers.google.com/web/updates/2017/02/navigation-preload
if ("navigationPreload" in self.registration) {
await self.registration.navigationPreload.enable();
}
})()
);
// Tell the active service worker to take control of the page immediately.
self.clients.claim();
});
self.addEventListener("fetch", (event) => {
// Only call event.respondWith() if this is a navigation request
// for an HTML page.
if (event.request.mode === "navigate") {
event.respondWith(
(async () => {
try {
// First, try to use the navigation preload response if it's
// supported.
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
}
// Always try the network first.
const networkResponse = await fetch(event.request);
return networkResponse;
} catch (error) {
// catch is only triggered if an exception is thrown, which is
// likely due to a network error.
// If fetch() returns a valid HTTP response with a response code in
// the 4xx or 5xx range, the catch() will NOT be called.
console.log("Fetch failed; returning offline page instead.", error);
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(OFFLINE_URL);
return cachedResponse;
}
})()
);
}
// If our if() condition is false, then this fetch handler won't
// intercept the request. If there are any other fetch handlers
// registered, they will get a chance to call event.respondWith().
// If no fetch handlers call event.respondWith(), the request
// will be handled by the browser as if there were no service
// worker involvement.
});
Halaman penggantian offline
File offline.html
adalah tempat Anda bisa berkreasi dan menyesuaikannya dengan kebutuhan Anda serta menambahkan
branding. Contoh di bawah menunjukkan hal-hal minimum yang memungkinkan.
Contoh ini mendemonstrasikan pemuatan ulang manual berdasarkan penekanan tombol serta pemuatan ulang otomatis berdasarkan peristiwa online
dan polling server reguler.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>You are offline</title>
<!-- Inline the page's stylesheet. -->
<style>
body {
font-family: helvetica, arial, sans-serif;
margin: 2em;
}
h1 {
font-style: italic;
color: #373fff;
}
p {
margin-block: 1rem;
}
button {
display: block;
}
</style>
</head>
<body>
<h1>You are offline</h1>
<p>Click the button below to try reloading.</p>
<button type="button">⤾ Reload</button>
<!-- Inline the page's JavaScript file. -->
<script>
// Manual reload feature.
document.querySelector("button").addEventListener("click", () => {
window.location.reload();
});
// Listen to changes in the network state, reload when online.
// This handles the case when the device is completely offline.
window.addEventListener('online', () => {
window.location.reload();
});
// Check if the server is responding and reload the page if it is.
// This handles the case when the device is online, but the server
// is offline or misbehaving.
async function checkNetworkAndReload() {
try {
const response = await fetch('.');
// Verify we get a valid response from the server
if (response.status >= 200 && response.status < 500) {
window.location.reload();
return;
}
} catch {
// Unable to connect to the server, ignore.
}
window.setTimeout(checkNetworkAndReload, 2500);
}
checkNetworkAndReload();
</script>
</body>
</html>
Demo
Anda dapat melihat cara kerja halaman penggantian offline di demo yang disematkan di bawah. Jika tertarik, Anda dapat mempelajari kode sumber di Glitch.
Catatan tambahan untuk membuat aplikasi Anda dapat diinstal
Sekarang setelah situs Anda memiliki halaman penggantian offline, Anda mungkin bertanya-tanya tentang langkah selanjutnya. Agar aplikasi dapat diinstal, Anda perlu menambahkan manifes aplikasi web dan, jika perlu, membuat strategi penginstalan.
Catatan tambahan tentang menayangkan halaman penggantian offline dengan Workbox.js
Anda mungkin pernah mendengar tentang Workbox. Workbox adalah kumpulan library JavaScript untuk menambahkan dukungan offline ke aplikasi web. Jika lebih suka menulis sendiri kode pekerja layanan yang lebih sedikit, Anda dapat menggunakan urutan langkah Workbox untuk halaman offline saja.
Selanjutnya, pelajari cara menentukan strategi penginstalan untuk aplikasi Anda.