@@ -4,6 +4,195 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({
44 enabled : process . env . ANALYZE === 'true' ,
55} ) ;
66
7+ const withPWA = require ( '@ducanh2912/next-pwa' ) . default ( {
8+ dest : 'public' ,
9+ cacheOnFrontEndNav : true ,
10+ aggressiveFrontEndNavCaching : true ,
11+ reloadOnOnline : true ,
12+ swcMinify : true ,
13+ disable : process . env . NODE_ENV === 'development' ,
14+ workboxOptions : {
15+ disableDevLogs : true ,
16+ runtimeCaching : [
17+ {
18+ urlPattern : / ^ h t t p s : \/ \/ f o n t s \. (?: g s t a t i c ) \. c o m \/ .* / i,
19+ handler : 'CacheFirst' ,
20+ options : {
21+ cacheName : 'google-fonts-webfonts' ,
22+ expiration : {
23+ maxEntries : 4 ,
24+ maxAgeSeconds : 365 * 24 * 60 * 60 , // 365 days
25+ } ,
26+ } ,
27+ } ,
28+ {
29+ urlPattern : / ^ h t t p s : \/ \/ f o n t s \. (?: g o o g l e a p i s ) \. c o m \/ .* / i,
30+ handler : 'StaleWhileRevalidate' ,
31+ options : {
32+ cacheName : 'google-fonts-stylesheets' ,
33+ expiration : {
34+ maxEntries : 4 ,
35+ maxAgeSeconds : 7 * 24 * 60 * 60 , // 7 days
36+ } ,
37+ } ,
38+ } ,
39+ {
40+ urlPattern : / \. (?: e o t | o t f | t t c | t t f | w o f f | w o f f 2 | f o n t .c s s ) $ / i,
41+ handler : 'StaleWhileRevalidate' ,
42+ options : {
43+ cacheName : 'static-font-assets' ,
44+ expiration : {
45+ maxEntries : 4 ,
46+ maxAgeSeconds : 7 * 24 * 60 * 60 , // 7 days
47+ } ,
48+ } ,
49+ } ,
50+ {
51+ urlPattern : / \. (?: j p g | j p e g | g i f | p n g | s v g | i c o | w e b p ) $ / i,
52+ handler : 'StaleWhileRevalidate' ,
53+ options : {
54+ cacheName : 'static-image-assets' ,
55+ expiration : {
56+ maxEntries : 64 ,
57+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
58+ } ,
59+ } ,
60+ } ,
61+ {
62+ urlPattern : / \/ _ n e x t \/ i m a g e \? u r l = .+ $ / i,
63+ handler : 'StaleWhileRevalidate' ,
64+ options : {
65+ cacheName : 'next-image' ,
66+ expiration : {
67+ maxEntries : 64 ,
68+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
69+ } ,
70+ } ,
71+ } ,
72+ {
73+ urlPattern : / \. (?: m p 3 | w a v | o g g ) $ / i,
74+ handler : 'CacheFirst' ,
75+ options : {
76+ rangeRequests : true ,
77+ cacheName : 'static-audio-assets' ,
78+ expiration : {
79+ maxEntries : 32 ,
80+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
81+ } ,
82+ } ,
83+ } ,
84+ {
85+ urlPattern : / \. (?: m p 4 ) $ / i,
86+ handler : 'CacheFirst' ,
87+ options : {
88+ rangeRequests : true ,
89+ cacheName : 'static-video-assets' ,
90+ expiration : {
91+ maxEntries : 32 ,
92+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
93+ } ,
94+ } ,
95+ } ,
96+ {
97+ urlPattern : / \. (?: j s ) $ / i,
98+ handler : 'StaleWhileRevalidate' ,
99+ options : {
100+ cacheName : 'static-js-assets' ,
101+ expiration : {
102+ maxEntries : 32 ,
103+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
104+ } ,
105+ } ,
106+ } ,
107+ {
108+ urlPattern : / \. (?: c s s | l e s s ) $ / i,
109+ handler : 'StaleWhileRevalidate' ,
110+ options : {
111+ cacheName : 'static-style-assets' ,
112+ expiration : {
113+ maxEntries : 32 ,
114+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
115+ } ,
116+ } ,
117+ } ,
118+ {
119+ urlPattern : / \/ _ n e x t \/ d a t a \/ .+ \/ .+ \. j s o n $ / i,
120+ handler : 'StaleWhileRevalidate' ,
121+ options : {
122+ cacheName : 'next-data' ,
123+ expiration : {
124+ maxEntries : 32 ,
125+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
126+ } ,
127+ } ,
128+ } ,
129+ {
130+ urlPattern : / \. (?: j s o n | x m l | c s v ) $ / i,
131+ handler : 'NetworkFirst' ,
132+ options : {
133+ cacheName : 'static-data-assets' ,
134+ expiration : {
135+ maxEntries : 32 ,
136+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
137+ } ,
138+ } ,
139+ } ,
140+ {
141+ urlPattern : ( { url } ) => {
142+ const isSameOrigin = self . origin === url . origin ;
143+ if ( ! isSameOrigin ) return false ;
144+ const pathname = url . pathname ;
145+ // Exclude /api/auth/callback/* to fix OAuth login issue
146+ if ( pathname . startsWith ( '/api/auth/' ) ) return false ;
147+ if ( pathname . startsWith ( '/api/' ) ) return true ;
148+ return false ;
149+ } ,
150+ handler : 'NetworkFirst' ,
151+ method : 'GET' ,
152+ options : {
153+ cacheName : 'apis' ,
154+ expiration : {
155+ maxEntries : 16 ,
156+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
157+ } ,
158+ networkTimeoutSeconds : 10 , // fall back to cache if api does not response within 10 seconds
159+ } ,
160+ } ,
161+ {
162+ urlPattern : ( { url } ) => {
163+ const isSameOrigin = self . origin === url . origin ;
164+ if ( ! isSameOrigin ) return false ;
165+ const pathname = url . pathname ;
166+ if ( pathname . startsWith ( '/api/' ) ) return false ;
167+ return true ;
168+ } ,
169+ handler : 'NetworkFirst' ,
170+ options : {
171+ cacheName : 'others' ,
172+ expiration : {
173+ maxEntries : 32 ,
174+ maxAgeSeconds : 24 * 60 * 60 , // 24 hours
175+ } ,
176+ networkTimeoutSeconds : 10 ,
177+ } ,
178+ } ,
179+ {
180+ urlPattern : ( { url } ) => url . origin === self . origin && url . pathname . startsWith ( '/api/' ) ,
181+ handler : 'NetworkOnly' ,
182+ method : 'POST' ,
183+ options : {
184+ backgroundSync : {
185+ name : 'api-sync-queue' ,
186+ options : {
187+ maxRetentionTime : 24 * 60 , // Retry for max of 24 Hours
188+ } ,
189+ } ,
190+ } ,
191+ } ,
192+ ] ,
193+ } ,
194+ } ) ;
195+
7196const nextConfig = {
8197 typescript : {
9198 ignoreBuildErrors : true ,
@@ -70,4 +259,4 @@ const nextConfig = {
70259 } ,
71260} ;
72261
73- module . exports = withBundleAnalyzer ( nextConfig ) ;
262+ module . exports = withBundleAnalyzer ( withPWA ( nextConfig ) ) ;
0 commit comments