Repository navigation
Expand file tree
/
Copy pathsw.js
More file actions
137 lines (128 loc) · 4.2 KB
/
Copy pathsw.js
File metadata and controls
137 lines (128 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
const CACHE_NAME = 'markdown-viewer-cache-v3.10.4';
// PERF-011: Split precache into critical (local files) and lazy (CDN libraries)
// Critical assets are precached during SW install for instant offline startup
const CRITICAL_ASSETS = [
'./',
'./index.html',
'./workspace-storage.js',
'./visual-settings-adapters.js',
'./visual-settings-store.js',
'./script.js',
'./preview-worker.js',
'./styles.css',
'./assets/seo-metadata.mjs',
'./seo/locales.mjs',
'./seo/welcome-content.mjs',
'./assets/lucide-icons.css',
'./assets/document-toc.js',
'./RELEASE_NOTES',
'./sample.md',
'./assets/icon.jpg',
'./manifest.json'
];
// CDN assets are cached lazily on first use via runtime cache-first strategy
// This prevents the SW install from downloading ~5.4 MB of CDN resources upfront
const CDN_ORIGINS = [
'cdnjs.cloudflare.com',
'cdn.jsdelivr.net'
];
const NETWORK_FIRST_LOCAL_PATHS = new Set([
'/',
'/index.html',
'/workspace-storage.js',
'/visual-settings-adapters.js',
'/visual-settings-store.js',
'/script.js',
'/preview-worker.js',
'/styles.css',
'/assets/seo-metadata.mjs',
'/seo/locales.mjs',
'/seo/welcome-content.mjs',
'/assets/lucide-icons.css',
'/assets/document-toc.js',
'/sw.js'
]);
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(CRITICAL_ASSETS))
.then(() => self.skipWaiting())
);
});
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys => Promise.all(
keys.map(key => {
if (key !== CACHE_NAME) {
return caches.delete(key);
}
})
)).then(() => self.clients.claim())
);
});
self.addEventListener('fetch', event => {
const url = new URL(event.request.url);
const isLocal = url.origin === self.location.origin;
const isCDN = CDN_ORIGINS.some(origin => url.hostname.includes(origin));
if (isLocal) {
const localPath = url.pathname.endsWith('/') ? '/' : url.pathname;
const shouldUseNetworkFirst =
event.request.mode === 'navigate' ||
NETWORK_FIRST_LOCAL_PATHS.has(localPath) ||
localPath.startsWith('/assets/i18n/');
if (shouldUseNetworkFirst) {
event.respondWith(
caches.open(CACHE_NAME).then(cache => {
return fetch(event.request).then(networkResponse => {
if (networkResponse && networkResponse.status === 200) {
cache.put(event.request, networkResponse.clone());
}
return networkResponse;
}).catch(() => cache.match(event.request));
})
);
return;
}
// Stale-While-Revalidate strategy for non-code local assets
event.respondWith(
caches.open(CACHE_NAME).then(cache => {
return cache.match(event.request).then(cachedResponse => {
const fetchPromise = fetch(event.request).then(networkResponse => {
if (networkResponse && networkResponse.status === 200) {
cache.put(event.request, networkResponse.clone());
}
return networkResponse;
}).catch(err => {
console.warn('Background fetch failed for:', event.request.url, err);
});
return cachedResponse || fetchPromise;
});
})
);
} else if (isCDN) {
// Cache-First strategy for stable third-party CDN libraries
// PERF-011: CDN resources are cached on first use (lazy) rather than precached
event.respondWith(
caches.match(event.request)
.then(cachedResponse => {
if (cachedResponse) {
return cachedResponse;
}
return fetch(event.request).then(response => {
if (response && response.status === 200) {
const responseToCache = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseToCache);
});
}
return response;
});
})
);
} else {
// Let arbitrary external resources use the browser's normal request path.
// Wrapping user-supplied images in service-worker fetch() makes them subject
// to connect-src instead of img-src, which blocks otherwise valid images.
return;
}
});