PageSourceSearch

https://www.csusb.edu/service-worker.js

js csusb.edu collected 2026-09-24 08:37:29 UTC 7,911 bytes, 226 lines download raw bytes

1// Only import the core Workbox library.
2// It will manage loading necessary modules like strategies.
3importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js');
4
5// Set Workbox's global cache name details.
6// This is important for Workbox to manage its caches properly,
7// especially during activation and cleanup.
8// CHANGE THIS SUFFIX (e.g., 'v1.10') FOR EACH SIGNIFICANT DEPLOYMENT
9// TO BUST ALL WORKBOX CACHES.
10workbox.core.setCacheNameDetails({
11  prefix: 'csusb',
12  suffix: 'v1.15', // <--- IMPORTANT: Change this value for new deployments!
13  precache: 'precache',
14  runtime: 'runtime',
15});
16
17// Use Workbox's internally managed cache names for consistency
18const imageCacheName = workbox.core.cacheNames.runtime + '-images';
19const cssJsFontsCacheName = workbox.core.cacheNames.runtime + '-css-js-fonts';
20const htmlCacheName = workbox.core.cacheNames.runtime + '-html';
21
22const prodUrl = 'https://www.csusb.edu';
23
24// Critical pages to cache on install (e.g., homepage, offline page)
25const pagesToPrecache = [
26  { url: '/offline.html', revision: null },
27  //{ url: '/', revision: null },
28  // Add other truly static, critical HTML pages here if needed
29  // { url: '/about', revision: null },
30];
31
32if (workbox) {
33  console.log('Workbox is loaded');
34  // DEBUG FOR DEV ONLY! Uncomment for debugging in development.
35  // workbox.setConfig({
36  //   debug: true,
37  // });
38} else {
39  console.warn('Workbox failed to load');
40}
41
42// Precache essential files (like offline fallback page and homepage)
43workbox.precaching.precacheAndRoute(pagesToPrecache);
44workbox.precaching.cleanupOutdatedCaches();
45
46// Navigation preload cuts TTFB even more
47workbox.navigationPreload.enable();
48
49const htmlHandler = new workbox.strategies.NetworkFirst({
50  cacheName: htmlCacheName,
51  networkTimeoutSeconds: 7, // 6–8s is a good sweet spot for your site
52  plugins: [
53    // Never cache logged-in/private HTML
54    {
55      cacheWillUpdate: async ({response}) => {
56        if (!response || response.status !== 200) return null;
57        const cc = response.headers.get('Cache-Control') || '';
58        if (/private|no-store|no-cache/i.test(cc)) return null;
59        return response;
60      },
61    },
62    new workbox.expiration.ExpirationPlugin({
63      maxEntries: 10,
64      maxAgeSeconds: 60, // keep HTML very fresh (60–300s)
65    }),
66  ],
67});
68
69// Use NavigationRoute so preload + respondWith are handled correctly.
70/*const navigationRoute = new workbox.routing.NavigationRoute(htmlHandler, {
71  // block admin pages from SW HTML caching
72  denylist: [/^\/admin(\/|$)/],
73});*/
74// Instead of htmlHandler/NetworkFirst, use NetworkOnly for navigations
75const navigationRoute = new workbox.routing.NavigationRoute(
76  new workbox.strategies.NetworkOnly(),
77  { denylist: [/^\/admin(\/|$)/] }
78);
79workbox.routing.registerRoute(navigationRoute);
80
81// Route for images (CacheFirst)
82workbox.routing.registerRoute(
83  /\.(?:png|jpg|jpeg|webp|svg|ico)$/,
84  new workbox.strategies.CacheFirst({
85    cacheName: imageCacheName,
86    plugins: [
87      new workbox.expiration.ExpirationPlugin({
88        maxEntries: 30,
89        maxAgeSeconds: 60 * 60, // 1 hour
90      }),
91      new workbox.cacheableResponse.CacheableResponsePlugin({
92        statuses: [0, 200],
93      }),
94    ]
95  })
96);
97
98// Route for CSS, JS, and Fonts (StaleWhileRevalidate)
99workbox.routing.registerRoute(
100  ({url, request}) => {
101    // Matches external font/CDN origins
102    const isExternalAsset = (
103      url.origin === 'https://fonts.googleapis.com' ||
104      url.origin === 'https://fonts.gstatic.com' ||
105      url.origin === 'https://use.fontawesome.com' ||
106      url.origin === 'https://pro.fontawesome.com' ||
107      url.origin === 'https://kit.fontawesome.com' ||
108      url.origin === 'https://use.typekit.net'
109    );
110    // Matches internal CSS/JS (including Drupal aggregated files like /sites/default/files/css/...)
111    const isInternalCode = (
112      url.hostname.includes('csusb') && (
113        request.destination === 'script' ||
114        request.destination === 'style'  ||
115        request.destination === 'font'
116      )
117    );
118    return isExternalAsset || isInternalCode;
119  },
120  new workbox.strategies.StaleWhileRevalidate({
121    cacheName: cssJsFontsCacheName,
122    plugins: [
123      new workbox.expiration.ExpirationPlugin({
124        maxEntries: 100,
125        //maxAgeSeconds: 60 * 60, // 1 hour
126        maxAgeSeconds: 60 * 60 * 24 * 5, // 5 days
127      }),
128      new workbox.cacheableResponse.CacheableResponsePlugin({
129        statuses: [0, 200],
130      }),
131    ]
132  })
133);
134
135// Fallback to offline.html for HTML requests when network fails
136workbox.routing.setCatchHandler(async ({ request }) => {
137  if (request.mode === 'navigate') {
138    return showErrorPage();
139  }
140  // For other types of requests (e.g., images, scripts) that fail,
141  // Workbox will default to a network error. You can add more specific
142  // fallbacks here if needed (e.g., a default image for failed image loads).
143  return Response.error();
144});
145
146
147// Manual addFilesToCacheOnInstall and fetchFilesAndAddToCache functions are no longer needed
148// if you are using Workbox's precaching and routing for HTML.
149
150self.addEventListener('install', function(e) {
151  // Workbox's precaching handles most of what was here.
152  // Add any custom installation steps if needed, but for now, rely on Workbox.
153  print('[Service Worker] Install');
154  // If you need to ensure the precached items are added during install,
155  // Workbox's precacheAndRoute handles this.
156  // The 'e.waitUntil(addFilesToCacheOnInstall())' might become redundant if all
157  // critical files are in `pagesToPrecache`.
158  // If `pagesToPrecache` isn't comprehensive enough, you might adapt `addFilesToCacheOnInstall`
159  // to work with Workbox's `cache.addAll`.
160  // For simplicity and relying on Workbox's precaching, this install event might be empty
161  // or only contain simple logging.
162  // Removing it might be an option if precaching handles all needs.
163  // For now, let's keep it minimal if Workbox handles the rest:
164  // e.waitUntil(self.skipWaiting()); // This forces the new SW to activate immediately after install.
165});
166
167
168self.addEventListener('activate', (event) => {
169  event.waitUntil(
170    caches.keys()
171      .then((keys) => {
172        const currentSuffix = workbox.core.cacheNames.suffix; // e.g., v1.15
173        return Promise.all(keys.map((k) => {
174          const isCurrentVersion = k.includes(currentSuffix);
175          const isHtmlBucket = k.endsWith('-html');
176          if (!isCurrentVersion || isHtmlBucket) {
177            print(`[Service Worker] Deleting cache: ${k}`);
178            return caches.delete(k);
179          }
180          return Promise.resolve(false);
181        }));
182      })
183      .then(() => clients.claim())
184  );
185});
186
187// This event listener will receive messages from the main thread (your webpage).
188self.addEventListener('message', (event) => {
189  // Check if the message is specifically asking the service worker to skip waiting.
190  if (event.data && event.data.type === 'SKIP_WAITING') {
191    // Calling self.skipWaiting() forces the waiting service worker to become active.
192    self.skipWaiting();
193  }
194});
195
196// Your helper functions (showErrorPage, print, logErrors) remain the same.
197async function showErrorPage() {
198  // Guaranteed to work for precached assets:
199  return workbox.precaching.matchPrecache('/offline.html');
200}
201
202function print(arg) {
203  if (location.origin !== prodUrl) {
204    console.log(arg);
205  }
206}
207
208function logErrors(msg, url, line) {
209  try {
210    fetch(location.origin + '/api/create/log', {
211      method: 'POST',
212      headers: {
213        'Content-Type': 'application/json',
214        Accept: 'application/json',
215      },
216      body: JSON.stringify({
217        type: 'service workers',
218        data: { message: msg, url: url, debug: line },
219      }),
220    }).catch((err) => {
221      console.warn('Logging error failed', err);
222    });
223  } catch (e) {
224    console.warn('Log error threw exception', e);
225  }
226}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.