How to Cache SVG Requests with Service Workers

This article explains how service workers intercept and cache Scalable Vector Graphics (SVG) requests to ensure graphical assets remain accessible in offline web applications. You will learn how to register a service worker, pre-cache critical SVG icons, intercept network requests through fetch events, and apply effective caching strategies such as Cache-First to deliver optimal offline performance.

1. Registering the Service Worker

To intercept any network requests, including SVGs, you must first register a service worker in your main application script.

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then((registration) => {
        console.log('Service Worker registered:', registration.scope);
      })
      .catch((error) => {
        console.error('Service Worker registration failed:', error);
      });
  });
}

2. Precaching Static SVGs on Install

For core UI icons, logos, and illustrations that rarely change, precache them during the service worker’s install lifecycle event.

const CACHE_NAME = 'svg-cache-v1';
const STATIC_SVGS = [
  '/icons/logo.svg',
  '/icons/menu.svg',
  '/icons/user.svg'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.addAll(STATIC_SVGS);
    })
  );
  self.skipWaiting();
});

3. Intercepting and Caching SVG Network Requests

When an HTML document requests an SVG file via an <img> tag, CSS background-image, <object>, or JavaScript fetch(), the service worker intercepts the request through the fetch event.

Cache-First Strategy for SVGs

A Cache-First strategy is ideal for vector assets because they are usually static. The service worker checks the Cache Storage API first. If the file exists, it returns the cached SVG immediately. If not, it fetches it over the network, stores a clone in the cache for future offline use, and delivers the response to the browser.

self.addEventListener('fetch', (event) => {
  const requestUrl = new URL(event.request.url);

  // Check if the requested file is an SVG
  if (requestUrl.pathname.endsWith('.svg')) {
    event.respondWith(
      caches.open(CACHE_NAME).then(async (cache) => {
        const cachedResponse = await cache.match(event.request);
        
        if (cachedResponse) {
          return cachedResponse;
        }

        try {
          const networkResponse = await fetch(event.request);
          
          // Ensure valid response before caching
          if (networkResponse && networkResponse.status === 200) {
            cache.put(event.request, networkResponse.clone());
          }
          
          return networkResponse;
        } catch (error) {
          // Provide an optional fallback SVG if offline and not in cache
          return cache.match('/icons/offline-placeholder.svg');
        }
      })
    );
  }
});

4. Cache Maintenance and Invalidation

When updating SVGs, update the cache version name (e.g., svg-cache-v2). Use the activate event to remove outdated caches.

self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames
          .filter((name) => name !== CACHE_NAME)
          .map((name) => caches.delete(name))
      );
    })
  );
  self.clients.claim();
});

Important Considerations