Yesterday, we learned that Service Workers (SWs) are your web app's invisible butler, sitting between your page and the network. Today, let's see how they actually work by registering one and implementing a basic "Cache-First" strategy.
π 1. Registering Your Service Worker (index.html)
This is the simple script on your main webpage that tells the browser, "Hey, go find
sw.js and install it!" It's crucial for getting the SW lifecycle started.<!-- In your index.html file, preferably at the end of <body> -->
<script>
// Check if Service Workers are supported by the browser
if ('serviceWorker' in navigator) {
// Register our Service Worker after the page has loaded
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js') // Path to your SW file
.then(registration => {
console.log('SW registered successfully:', registration.scope);
})
.catch(error => {
console.error('SW registration failed:', error);
});
});
}
</script>
πΎ 2. The Service Worker's Logic (sw.js)
This file lives separately and handles the caching and network requests.
// --- sw.js file ---
const CACHE_NAME = 'my-website-v1'; // A unique name for your cache
const ASSETS_TO_CACHE = [ // List of files to precache
'/', // The root path (e.g., index.html)
'/index.html',
'/styles.css',
'/app.js',
'/images/logo.png'
];
// 1. --- The 'install' Event: Pre-caching Core Assets ---
self.addEventListener('install', (event) => {
console.log('Service Worker: Installing...');
event.waitUntil( // Wait until all assets are added to cache
caches.open(CACHE_NAME) // Open our named cache
.then((cache) => {
console.log('Service Worker: Caching essential assets');
return cache.addAll(ASSETS_TO_CACHE); // Add all files from our list
})
);
});
// 2. --- The 'fetch' Event: Cache-First Strategy ---
self.addEventListener('fetch', (event) => {
event.respondWith( // Control how the browser responds to requests
caches.match(event.request) // Check if the requested asset is in our cache
.then((response) => {
// If asset is found in cache, return it immediately
if (response) {
console.log('Service Worker: Serving from cache for', event.request.url);
return response;
}
// If not in cache, go to the network to fetch it
console.log('Service Worker: Fetching from network for', event.request.url);
return fetch(event.request);
})
);
});
// 3. --- The 'activate' Event: Cleaning Up Old Caches ---
self.addEventListener('activate', (event) => {
console.log('Service Worker: Activating...');
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
// Delete old caches that are no longer in our whitelist
console.log('Service Worker: Deleting old cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
});
π‘ The "Cache-First" Strategy Explained
In the
fetch event above, we implemented a "Cache-First" strategy:1. When the browser requests a file, the Service Worker first checks its cache.
2. If the file is found in the cache (a "cache hit"), it serves it instantly. This means offline access and blazing-fast loads!
3. If the file isn't in the cache, the Service Worker then goes to the network to fetch it, just like a normal browser request.
π² Next up: Why they matter & where you've already seen them! (3/3)