@djangocfg/nextjs 2.1.35 → 2.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -22
- package/dist/config/index.d.mts +7 -409
- package/dist/config/index.mjs +79 -394
- package/dist/config/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +79 -394
- package/dist/index.mjs.map +1 -1
- package/dist/plugin-DuRJ_Jq6.d.mts +100 -0
- package/dist/pwa/cli.d.mts +1 -0
- package/dist/pwa/cli.mjs +140 -0
- package/dist/pwa/cli.mjs.map +1 -0
- package/dist/pwa/index.d.mts +274 -0
- package/dist/pwa/index.mjs +327 -0
- package/dist/pwa/index.mjs.map +1 -0
- package/dist/pwa/server/index.d.mts +86 -0
- package/dist/pwa/server/index.mjs +175 -0
- package/dist/pwa/server/index.mjs.map +1 -0
- package/dist/pwa/server/routes.d.mts +2 -0
- package/dist/pwa/server/routes.mjs +149 -0
- package/dist/pwa/server/routes.mjs.map +1 -0
- package/dist/pwa/worker/index.d.mts +56 -0
- package/dist/pwa/worker/index.mjs +97 -0
- package/dist/pwa/worker/index.mjs.map +1 -0
- package/dist/routes-DXA29sS_.d.mts +68 -0
- package/package.json +38 -9
- package/src/config/createNextConfig.ts +9 -13
- package/src/config/index.ts +2 -19
- package/src/config/plugins/devStartup.ts +35 -36
- package/src/config/plugins/index.ts +1 -1
- package/src/config/utils/index.ts +0 -1
- package/src/index.ts +4 -0
- package/src/pwa/cli.ts +171 -0
- package/src/pwa/index.ts +9 -0
- package/src/pwa/manifest.ts +355 -0
- package/src/pwa/notifications.ts +192 -0
- package/src/pwa/plugin.ts +194 -0
- package/src/pwa/server/index.ts +23 -0
- package/src/pwa/server/push.ts +166 -0
- package/src/pwa/server/routes.ts +137 -0
- package/src/pwa/worker/index.ts +174 -0
- package/src/pwa/worker/package.json +3 -0
- package/bin/dev-with-browser.js +0 -114
- package/src/config/plugins/pwa.ts +0 -616
- package/src/config/utils/manifest.ts +0 -195
|
@@ -1,616 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PWA (Progressive Web App) Plugin
|
|
3
|
-
*
|
|
4
|
-
* Configures @ducanh2912/next-pwa for service worker and offline support
|
|
5
|
-
* Modern fork that supports Next.js 13+ with app directory
|
|
6
|
-
*
|
|
7
|
-
* @see https://www.npmjs.com/package/@ducanh2912/next-pwa
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { NextConfig } from 'next';
|
|
11
|
-
import { consola } from 'consola';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Runtime caching handler strategies
|
|
15
|
-
*/
|
|
16
|
-
export type CacheStrategy =
|
|
17
|
-
| 'CacheFirst'
|
|
18
|
-
| 'CacheOnly'
|
|
19
|
-
| 'NetworkFirst'
|
|
20
|
-
| 'NetworkOnly'
|
|
21
|
-
| 'StaleWhileRevalidate';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Runtime cache entry configuration
|
|
25
|
-
*/
|
|
26
|
-
export interface RuntimeCacheEntry {
|
|
27
|
-
urlPattern: RegExp | string | ((context: { url: URL; request: Request }) => boolean);
|
|
28
|
-
handler: CacheStrategy;
|
|
29
|
-
options?: {
|
|
30
|
-
cacheName?: string;
|
|
31
|
-
expiration?: {
|
|
32
|
-
maxEntries?: number;
|
|
33
|
-
maxAgeSeconds?: number;
|
|
34
|
-
purgeOnQuotaError?: boolean;
|
|
35
|
-
};
|
|
36
|
-
cacheableResponse?: {
|
|
37
|
-
statuses?: number[];
|
|
38
|
-
headers?: Record<string, string>;
|
|
39
|
-
};
|
|
40
|
-
rangeRequests?: boolean;
|
|
41
|
-
backgroundSync?: {
|
|
42
|
-
name: string;
|
|
43
|
-
options?: {
|
|
44
|
-
maxRetentionTime?: number;
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
broadcastUpdate?: {
|
|
48
|
-
channelName?: string;
|
|
49
|
-
options?: {
|
|
50
|
-
headersToCheck?: string[];
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
matchOptions?: {
|
|
54
|
-
ignoreSearch?: boolean;
|
|
55
|
-
ignoreMethod?: boolean;
|
|
56
|
-
ignoreVary?: boolean;
|
|
57
|
-
};
|
|
58
|
-
networkTimeoutSeconds?: number;
|
|
59
|
-
plugins?: any[];
|
|
60
|
-
fetchOptions?: RequestInit;
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface PWAPluginOptions {
|
|
65
|
-
/**
|
|
66
|
-
* Destination directory for service worker files
|
|
67
|
-
* @default 'public'
|
|
68
|
-
*/
|
|
69
|
-
dest: string;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Disable PWA completely
|
|
73
|
-
* @default false in production, true in development
|
|
74
|
-
* @example disable: process.env.NODE_ENV === 'development'
|
|
75
|
-
*/
|
|
76
|
-
disable?: boolean;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Auto-register service worker
|
|
80
|
-
* @default true
|
|
81
|
-
* @description Set to false if you want to register SW manually
|
|
82
|
-
*/
|
|
83
|
-
register?: boolean;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* URL scope for PWA
|
|
87
|
-
* @default '/'
|
|
88
|
-
* @example '/app' - only /app/** will be PWA
|
|
89
|
-
*/
|
|
90
|
-
scope?: string;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Service worker file name
|
|
94
|
-
* @default 'sw.js'
|
|
95
|
-
*/
|
|
96
|
-
sw?: string;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Skip waiting for service worker activation
|
|
100
|
-
* @default true
|
|
101
|
-
* @description Activate new SW immediately
|
|
102
|
-
*/
|
|
103
|
-
skipWaiting?: boolean;
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Client claim - take control of uncontrolled clients immediately
|
|
107
|
-
* @default true
|
|
108
|
-
*/
|
|
109
|
-
clientsClaim?: boolean;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Cleanup outdated caches automatically
|
|
113
|
-
* @default true
|
|
114
|
-
*/
|
|
115
|
-
cleanupOutdatedCaches?: boolean;
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Runtime caching strategies
|
|
119
|
-
* @default defaultRuntimeCaching
|
|
120
|
-
* @see defaultRuntimeCaching for default configuration
|
|
121
|
-
*/
|
|
122
|
-
runtimeCaching?: RuntimeCacheEntry[];
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Exclude files from build directory precaching
|
|
126
|
-
* @example [/chunks\/images\/.*$/] - don't precache images
|
|
127
|
-
*/
|
|
128
|
-
buildExcludes?: (string | RegExp | ((chunk: any) => boolean))[];
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Exclude files from public directory precaching
|
|
132
|
-
* @default ['!noprecache/**\/*']
|
|
133
|
-
* @example ['!videos/**\/*', '!large-images/**\/*']
|
|
134
|
-
*/
|
|
135
|
-
publicExcludes?: string[];
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Cache start URL (_app or / route)
|
|
139
|
-
* @default true
|
|
140
|
-
*/
|
|
141
|
-
cacheStartUrl?: boolean;
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Dynamic start URL (returns different HTML for different states)
|
|
145
|
-
* @default true
|
|
146
|
-
* @description Set to false if start URL always returns same HTML
|
|
147
|
-
*/
|
|
148
|
-
dynamicStartUrl?: boolean;
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Redirect URL if start URL redirects (e.g., to /login)
|
|
152
|
-
* @example '/login'
|
|
153
|
-
*/
|
|
154
|
-
dynamicStartUrlRedirect?: string;
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Enable additional route caching on front-end navigation
|
|
158
|
-
* @default false
|
|
159
|
-
* @description Cache routes when navigating with next/link
|
|
160
|
-
*/
|
|
161
|
-
cacheOnFrontEndNav?: boolean;
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Subdomain prefix for static files
|
|
165
|
-
* @deprecated Use basePath in next.config.js instead
|
|
166
|
-
*/
|
|
167
|
-
subdomainPrefix?: string;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Reload app when device goes back online
|
|
171
|
-
* @default true
|
|
172
|
-
*/
|
|
173
|
-
reloadOnOnline?: boolean;
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Custom worker directory
|
|
177
|
-
* @default 'worker'
|
|
178
|
-
* @description Directory containing custom worker implementation
|
|
179
|
-
*/
|
|
180
|
-
customWorkerDir?: string;
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Custom service worker source (for InjectManifest mode)
|
|
184
|
-
* @description Path to your custom service worker source
|
|
185
|
-
*/
|
|
186
|
-
swSrc?: string;
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Offline fallback pages
|
|
190
|
-
* @example { document: '/_offline', image: '/offline.jpg' }
|
|
191
|
-
*/
|
|
192
|
-
fallbacks?: {
|
|
193
|
-
document?: string;
|
|
194
|
-
image?: string;
|
|
195
|
-
audio?: string;
|
|
196
|
-
video?: string;
|
|
197
|
-
font?: string;
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Additional workbox options
|
|
202
|
-
* @see https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin
|
|
203
|
-
*/
|
|
204
|
-
workboxOptions?: Record<string, any>;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Check if @ducanh2912/next-pwa is installed
|
|
209
|
-
*
|
|
210
|
-
* Note: @ducanh2912/next-pwa is included as a dependency,
|
|
211
|
-
* so this should always return true unless there's an installation issue
|
|
212
|
-
*/
|
|
213
|
-
export function isPWAAvailable(): boolean {
|
|
214
|
-
try {
|
|
215
|
-
require.resolve('@ducanh2912/next-pwa');
|
|
216
|
-
return true;
|
|
217
|
-
} catch {
|
|
218
|
-
// Try legacy next-pwa (not recommended for Next.js 13+)
|
|
219
|
-
try {
|
|
220
|
-
require.resolve('next-pwa');
|
|
221
|
-
consola.warn(
|
|
222
|
-
'Found legacy next-pwa. Please use @ducanh2912/next-pwa for Next.js 13+ support.\n' +
|
|
223
|
-
'Run: pnpm remove next-pwa && pnpm add @ducanh2912/next-pwa'
|
|
224
|
-
);
|
|
225
|
-
return true;
|
|
226
|
-
} catch {
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Add PWA configuration to Next.js config
|
|
234
|
-
*
|
|
235
|
-
* @example
|
|
236
|
-
* ```ts
|
|
237
|
-
* // Basic usage
|
|
238
|
-
* export default withPWA(nextConfig, {
|
|
239
|
-
* dest: 'public',
|
|
240
|
-
* disable: process.env.NODE_ENV === 'development',
|
|
241
|
-
* });
|
|
242
|
-
*
|
|
243
|
-
* // With custom runtime caching
|
|
244
|
-
* export default withPWA(nextConfig, {
|
|
245
|
-
* dest: 'public',
|
|
246
|
-
* runtimeCaching: [
|
|
247
|
-
* {
|
|
248
|
-
* urlPattern: /^https:\/\/api\.example\.com\/.* /i,
|
|
249
|
-
* handler: 'NetworkFirst',
|
|
250
|
-
* options: {
|
|
251
|
-
* cacheName: 'api-cache',
|
|
252
|
-
* expiration: { maxEntries: 50, maxAgeSeconds: 300 },
|
|
253
|
-
* },
|
|
254
|
-
* },
|
|
255
|
-
* ],
|
|
256
|
-
* });
|
|
257
|
-
*
|
|
258
|
-
* // With offline fallbacks
|
|
259
|
-
* export default withPWA(nextConfig, {
|
|
260
|
-
* dest: 'public',
|
|
261
|
-
* fallbacks: {
|
|
262
|
-
* document: '/_offline',
|
|
263
|
-
* image: '/offline.jpg',
|
|
264
|
-
* },
|
|
265
|
-
* });
|
|
266
|
-
* ```
|
|
267
|
-
*/
|
|
268
|
-
export function withPWA(
|
|
269
|
-
nextConfig: NextConfig,
|
|
270
|
-
options: Partial<PWAPluginOptions> = {}
|
|
271
|
-
): NextConfig {
|
|
272
|
-
// Check if next-pwa is available
|
|
273
|
-
if (!isPWAAvailable()) {
|
|
274
|
-
consola.error(
|
|
275
|
-
'@ducanh2912/next-pwa is missing!\n' +
|
|
276
|
-
'This is unexpected as it should be installed automatically.\n' +
|
|
277
|
-
'Try: pnpm install --force\n' +
|
|
278
|
-
'PWA features will be disabled.'
|
|
279
|
-
);
|
|
280
|
-
return nextConfig;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const isDev = process.env.NODE_ENV === 'development';
|
|
284
|
-
|
|
285
|
-
const defaultOptions: Partial<PWAPluginOptions> = {
|
|
286
|
-
dest: 'public',
|
|
287
|
-
disable: options.disable !== undefined ? options.disable : isDev,
|
|
288
|
-
register: true,
|
|
289
|
-
skipWaiting: true,
|
|
290
|
-
clientsClaim: true,
|
|
291
|
-
cleanupOutdatedCaches: true,
|
|
292
|
-
publicExcludes: ['!noprecache/**/*'],
|
|
293
|
-
buildExcludes: [/middleware-manifest\.json$/, /build-manifest\.json$/],
|
|
294
|
-
cacheStartUrl: true,
|
|
295
|
-
dynamicStartUrl: true,
|
|
296
|
-
reloadOnOnline: true,
|
|
297
|
-
...options,
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
try {
|
|
301
|
-
// Use modern next-pwa (@ducanh2912/next-pwa) - supports Next.js 13+
|
|
302
|
-
const withPWAImport = require('@ducanh2912/next-pwa').default;
|
|
303
|
-
return withPWAImport(defaultOptions)(nextConfig);
|
|
304
|
-
} catch {
|
|
305
|
-
try {
|
|
306
|
-
// Fallback to legacy next-pwa (not recommended for Next.js 13+)
|
|
307
|
-
const withPWAImport = require('next-pwa');
|
|
308
|
-
consola.warn('Using legacy next-pwa. Upgrade to @ducanh2912/next-pwa for Next.js 13+ support');
|
|
309
|
-
return withPWAImport(defaultOptions)(nextConfig);
|
|
310
|
-
} catch (error) {
|
|
311
|
-
consola.error('Failed to load next-pwa:', error);
|
|
312
|
-
return nextConfig;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Default runtime caching strategies
|
|
319
|
-
*
|
|
320
|
-
* Optimized caching rules for common assets:
|
|
321
|
-
* - Google Fonts (webfonts + stylesheets)
|
|
322
|
-
* - Static assets (images, fonts, audio, video)
|
|
323
|
-
* - Next.js resources (JS, CSS, data, images)
|
|
324
|
-
* - API routes excluded from page cache
|
|
325
|
-
*
|
|
326
|
-
* @example
|
|
327
|
-
* ```ts
|
|
328
|
-
* // Use default caching
|
|
329
|
-
* withPWA(nextConfig, {
|
|
330
|
-
* dest: 'public',
|
|
331
|
-
* runtimeCaching: defaultRuntimeCaching,
|
|
332
|
-
* });
|
|
333
|
-
*
|
|
334
|
-
* // Extend with custom rules
|
|
335
|
-
* withPWA(nextConfig, {
|
|
336
|
-
* dest: 'public',
|
|
337
|
-
* runtimeCaching: [
|
|
338
|
-
* ...defaultRuntimeCaching,
|
|
339
|
-
* {
|
|
340
|
-
* urlPattern: /^https:\/\/api\.example\.com\/.* /i,
|
|
341
|
-
* handler: 'NetworkFirst',
|
|
342
|
-
* options: { cacheName: 'api-cache' },
|
|
343
|
-
* },
|
|
344
|
-
* ],
|
|
345
|
-
* });
|
|
346
|
-
* ```
|
|
347
|
-
*/
|
|
348
|
-
export const defaultRuntimeCaching: RuntimeCacheEntry[] = [
|
|
349
|
-
{
|
|
350
|
-
urlPattern: /^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,
|
|
351
|
-
handler: 'CacheFirst',
|
|
352
|
-
options: {
|
|
353
|
-
cacheName: 'google-fonts-webfonts',
|
|
354
|
-
expiration: {
|
|
355
|
-
maxEntries: 4,
|
|
356
|
-
maxAgeSeconds: 365 * 24 * 60 * 60, // 1 year
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
urlPattern: /^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,
|
|
362
|
-
handler: 'StaleWhileRevalidate',
|
|
363
|
-
options: {
|
|
364
|
-
cacheName: 'google-fonts-stylesheets',
|
|
365
|
-
expiration: {
|
|
366
|
-
maxEntries: 4,
|
|
367
|
-
maxAgeSeconds: 7 * 24 * 60 * 60, // 1 week
|
|
368
|
-
},
|
|
369
|
-
},
|
|
370
|
-
},
|
|
371
|
-
{
|
|
372
|
-
urlPattern: /\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,
|
|
373
|
-
handler: 'StaleWhileRevalidate',
|
|
374
|
-
options: {
|
|
375
|
-
cacheName: 'static-font-assets',
|
|
376
|
-
expiration: {
|
|
377
|
-
maxEntries: 4,
|
|
378
|
-
maxAgeSeconds: 7 * 24 * 60 * 60, // 1 week
|
|
379
|
-
},
|
|
380
|
-
},
|
|
381
|
-
},
|
|
382
|
-
{
|
|
383
|
-
urlPattern: /\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,
|
|
384
|
-
handler: 'StaleWhileRevalidate',
|
|
385
|
-
options: {
|
|
386
|
-
cacheName: 'static-image-assets',
|
|
387
|
-
expiration: {
|
|
388
|
-
maxEntries: 64,
|
|
389
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
390
|
-
},
|
|
391
|
-
},
|
|
392
|
-
},
|
|
393
|
-
{
|
|
394
|
-
urlPattern: /\/_next\/image\?url=.+$/i,
|
|
395
|
-
handler: 'StaleWhileRevalidate',
|
|
396
|
-
options: {
|
|
397
|
-
cacheName: 'next-image',
|
|
398
|
-
expiration: {
|
|
399
|
-
maxEntries: 64,
|
|
400
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
401
|
-
},
|
|
402
|
-
},
|
|
403
|
-
},
|
|
404
|
-
{
|
|
405
|
-
urlPattern: /\.(?:mp3|wav|ogg)$/i,
|
|
406
|
-
handler: 'CacheFirst',
|
|
407
|
-
options: {
|
|
408
|
-
rangeRequests: true,
|
|
409
|
-
cacheName: 'static-audio-assets',
|
|
410
|
-
expiration: {
|
|
411
|
-
maxEntries: 32,
|
|
412
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
413
|
-
},
|
|
414
|
-
},
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
urlPattern: /\.(?:mp4)$/i,
|
|
418
|
-
handler: 'CacheFirst',
|
|
419
|
-
options: {
|
|
420
|
-
rangeRequests: true,
|
|
421
|
-
cacheName: 'static-video-assets',
|
|
422
|
-
expiration: {
|
|
423
|
-
maxEntries: 32,
|
|
424
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
425
|
-
},
|
|
426
|
-
},
|
|
427
|
-
},
|
|
428
|
-
{
|
|
429
|
-
urlPattern: /\.(?:js)$/i,
|
|
430
|
-
handler: 'StaleWhileRevalidate',
|
|
431
|
-
options: {
|
|
432
|
-
cacheName: 'static-js-assets',
|
|
433
|
-
expiration: {
|
|
434
|
-
maxEntries: 32,
|
|
435
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
436
|
-
},
|
|
437
|
-
},
|
|
438
|
-
},
|
|
439
|
-
{
|
|
440
|
-
urlPattern: /\.(?:css|less)$/i,
|
|
441
|
-
handler: 'StaleWhileRevalidate',
|
|
442
|
-
options: {
|
|
443
|
-
cacheName: 'static-style-assets',
|
|
444
|
-
expiration: {
|
|
445
|
-
maxEntries: 32,
|
|
446
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
447
|
-
},
|
|
448
|
-
},
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
urlPattern: /\/_next\/data\/.+\/.+\.json$/i,
|
|
452
|
-
handler: 'StaleWhileRevalidate',
|
|
453
|
-
options: {
|
|
454
|
-
cacheName: 'next-data',
|
|
455
|
-
expiration: {
|
|
456
|
-
maxEntries: 32,
|
|
457
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
458
|
-
},
|
|
459
|
-
},
|
|
460
|
-
},
|
|
461
|
-
{
|
|
462
|
-
urlPattern: /\.(?:json|xml|csv)$/i,
|
|
463
|
-
handler: 'NetworkFirst',
|
|
464
|
-
options: {
|
|
465
|
-
cacheName: 'static-data-assets',
|
|
466
|
-
expiration: {
|
|
467
|
-
maxEntries: 32,
|
|
468
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
469
|
-
},
|
|
470
|
-
},
|
|
471
|
-
},
|
|
472
|
-
{
|
|
473
|
-
urlPattern: ({ url }: { url: URL }) => {
|
|
474
|
-
const isSameOrigin = self.origin === url.origin;
|
|
475
|
-
if (!isSameOrigin) return false;
|
|
476
|
-
const pathname = url.pathname;
|
|
477
|
-
// Exclude /api/ routes
|
|
478
|
-
if (pathname.startsWith('/api/')) return false;
|
|
479
|
-
return true;
|
|
480
|
-
},
|
|
481
|
-
handler: 'NetworkFirst',
|
|
482
|
-
options: {
|
|
483
|
-
cacheName: 'pages',
|
|
484
|
-
expiration: {
|
|
485
|
-
maxEntries: 32,
|
|
486
|
-
maxAgeSeconds: 24 * 60 * 60, // 24 hours
|
|
487
|
-
},
|
|
488
|
-
},
|
|
489
|
-
},
|
|
490
|
-
];
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* Helper: Create API caching rule
|
|
494
|
-
*
|
|
495
|
-
* @example
|
|
496
|
-
* ```ts
|
|
497
|
-
* createApiCacheRule('https://api.example.com', {
|
|
498
|
-
* strategy: 'NetworkFirst',
|
|
499
|
-
* maxAge: 300, // 5 minutes
|
|
500
|
-
* });
|
|
501
|
-
* ```
|
|
502
|
-
*/
|
|
503
|
-
export function createApiCacheRule(
|
|
504
|
-
apiUrl: string,
|
|
505
|
-
options: {
|
|
506
|
-
strategy?: CacheStrategy;
|
|
507
|
-
maxAge?: number;
|
|
508
|
-
maxEntries?: number;
|
|
509
|
-
cacheName?: string;
|
|
510
|
-
} = {}
|
|
511
|
-
): RuntimeCacheEntry {
|
|
512
|
-
const {
|
|
513
|
-
strategy = 'NetworkFirst',
|
|
514
|
-
maxAge = 300,
|
|
515
|
-
maxEntries = 50,
|
|
516
|
-
cacheName = 'api-cache',
|
|
517
|
-
} = options;
|
|
518
|
-
|
|
519
|
-
return {
|
|
520
|
-
urlPattern: new RegExp(`^${apiUrl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/.*`, 'i'),
|
|
521
|
-
handler: strategy,
|
|
522
|
-
options: {
|
|
523
|
-
cacheName,
|
|
524
|
-
expiration: {
|
|
525
|
-
maxEntries,
|
|
526
|
-
maxAgeSeconds: maxAge,
|
|
527
|
-
},
|
|
528
|
-
networkTimeoutSeconds: 10,
|
|
529
|
-
},
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
/**
|
|
534
|
-
* Helper: Create static asset caching rule
|
|
535
|
-
*
|
|
536
|
-
* @example
|
|
537
|
-
* ```ts
|
|
538
|
-
* createStaticAssetRule(['jpg', 'png', 'webp'], {
|
|
539
|
-
* strategy: 'CacheFirst',
|
|
540
|
-
* maxAge: 86400, // 1 day
|
|
541
|
-
* });
|
|
542
|
-
* ```
|
|
543
|
-
*/
|
|
544
|
-
export function createStaticAssetRule(
|
|
545
|
-
extensions: string[],
|
|
546
|
-
options: {
|
|
547
|
-
strategy?: CacheStrategy;
|
|
548
|
-
maxAge?: number;
|
|
549
|
-
maxEntries?: number;
|
|
550
|
-
cacheName?: string;
|
|
551
|
-
} = {}
|
|
552
|
-
): RuntimeCacheEntry {
|
|
553
|
-
const {
|
|
554
|
-
strategy = 'CacheFirst',
|
|
555
|
-
maxAge = 86400,
|
|
556
|
-
maxEntries = 64,
|
|
557
|
-
cacheName = 'static-assets',
|
|
558
|
-
} = options;
|
|
559
|
-
|
|
560
|
-
const pattern = extensions.map((ext) => ext.replace('.', '')).join('|');
|
|
561
|
-
|
|
562
|
-
return {
|
|
563
|
-
urlPattern: new RegExp(`\\.(?:${pattern})$`, 'i'),
|
|
564
|
-
handler: strategy,
|
|
565
|
-
options: {
|
|
566
|
-
cacheName,
|
|
567
|
-
expiration: {
|
|
568
|
-
maxEntries,
|
|
569
|
-
maxAgeSeconds: maxAge,
|
|
570
|
-
},
|
|
571
|
-
},
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Helper: Create CDN caching rule
|
|
577
|
-
*
|
|
578
|
-
* @example
|
|
579
|
-
* ```ts
|
|
580
|
-
* createCdnCacheRule('https://cdn.example.com', {
|
|
581
|
-
* strategy: 'CacheFirst',
|
|
582
|
-
* maxAge: 2592000, // 30 days
|
|
583
|
-
* });
|
|
584
|
-
* ```
|
|
585
|
-
*/
|
|
586
|
-
export function createCdnCacheRule(
|
|
587
|
-
cdnUrl: string,
|
|
588
|
-
options: {
|
|
589
|
-
strategy?: CacheStrategy;
|
|
590
|
-
maxAge?: number;
|
|
591
|
-
maxEntries?: number;
|
|
592
|
-
cacheName?: string;
|
|
593
|
-
} = {}
|
|
594
|
-
): RuntimeCacheEntry {
|
|
595
|
-
const {
|
|
596
|
-
strategy = 'CacheFirst',
|
|
597
|
-
maxAge = 2592000, // 30 days
|
|
598
|
-
maxEntries = 100,
|
|
599
|
-
cacheName = 'cdn-cache',
|
|
600
|
-
} = options;
|
|
601
|
-
|
|
602
|
-
return {
|
|
603
|
-
urlPattern: new RegExp(`^${cdnUrl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/.*`, 'i'),
|
|
604
|
-
handler: strategy,
|
|
605
|
-
options: {
|
|
606
|
-
cacheName,
|
|
607
|
-
expiration: {
|
|
608
|
-
maxEntries,
|
|
609
|
-
maxAgeSeconds: maxAge,
|
|
610
|
-
},
|
|
611
|
-
cacheableResponse: {
|
|
612
|
-
statuses: [0, 200],
|
|
613
|
-
},
|
|
614
|
-
},
|
|
615
|
-
};
|
|
616
|
-
}
|