Files
chatwoot/app/javascript/service-worker/sw-runtime.js
T
PranavandClaude Opus 4.5 d34df7c314 feat: Add service worker for asset caching
- Add Workbox-based service worker to cache JS, CSS, and fonts
- JS/CSS cached for 30 days, fonts for 1 year
- Support for CDN assets via ASSET_CDN_HOST
- Version-based cache invalidation on deployments
- Automatic cache cleanup for old versions
- Build service worker during asset precompilation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 14:48:23 -08:00

85 lines
2.3 KiB
JavaScript

/* eslint-disable no-restricted-globals */
import { registerRoute } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { ExpirationPlugin } from 'workbox-expiration';
// Cache version will be injected at build time
const CACHE_VERSION = '__CACHE_VERSION__';
// Asset origin will be injected at build time (CDN host or empty string)
const ASSET_ORIGIN = '__ASSET_ORIGIN__';
// Define cache names with versioning
const JS_CACHE = `js-cache-${CACHE_VERSION}`;
const CSS_CACHE = `css-cache-${CACHE_VERSION}`;
const FONT_CACHE = `font-cache-${CACHE_VERSION}`;
// Cache JavaScript bundles from /packs/ or CDN
registerRoute(
({ request, url }) => {
const isScript = request.destination === 'script';
const isFromPacks = url.pathname.startsWith('/packs/');
const isFromCDN = ASSET_ORIGIN && url.origin === ASSET_ORIGIN;
return isScript && (isFromPacks || isFromCDN);
},
new CacheFirst({
cacheName: JS_CACHE,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200], // 0 for opaque responses from CDN, 200 for same-origin
}),
new ExpirationPlugin({
maxEntries: 100,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
}),
],
})
);
// Cache CSS files from /packs/ or CDN
registerRoute(
({ request, url }) => {
const isStyle = request.destination === 'style';
const isFromPacks = url.pathname.startsWith('/packs/');
const isFromCDN = ASSET_ORIGIN && url.origin === ASSET_ORIGIN;
return isStyle && (isFromPacks || isFromCDN);
},
new CacheFirst({
cacheName: CSS_CACHE,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
new ExpirationPlugin({
maxEntries: 30,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
}),
],
})
);
// Cache fonts (from anywhere)
registerRoute(
({ request, url }) => {
const isFont = request.destination === 'font';
const hasFontExtension = /\.(woff|woff2|ttf|otf|eot)$/i.test(url.pathname);
return isFont || hasFontExtension;
},
new CacheFirst({
cacheName: FONT_CACHE,
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
new ExpirationPlugin({
maxEntries: 30,
maxAgeSeconds: 365 * 24 * 60 * 60, // 1 year
}),
],
})
);