-
Notifications
You must be signed in to change notification settings - Fork 265
WS-1837: Service worker changes to render offline page #13520
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+1,202
−104
Merged
Changes from all commits
Commits
Show all changes
146 commits
Select commit
Hold shift + click to select a range
7f929cf
working offline component
DmitryGron 2cb8b52
update offline page
DmitryGron d334d98
update
DmitryGron a886733
updating bundle size
DmitryGron 9be198b
update tests
DmitryGron 624f4b4
update tests
DmitryGron 9c59cbb
update tests
DmitryGron 447450b
update tests
DmitryGron 1fb71dc
update tests
DmitryGron 1dffbf5
update tests
DmitryGron 931818b
Merge branch 'latest' into WS-147-offline-page
DmitryGron 2ee1efc
Merge branch 'latest' into WS-147-offline-page
DmitryGron ee3b816
Merge branch 'latest' into WS-147-offline-page
DmitryGron 88182c9
Merge branch 'latest' into WS-147-offline-page
DmitryGron 55157ca
Merge branch 'latest' into WS-147-offline-page
DmitryGron 4ac3831
Merge branch 'latest' into WS-147-offline-page
DmitryGron 299c7ce
conflict resolved
jinidev bddd422
Merge branch 'latest' into WS-147-offline-page
jinidev 049e894
resolving a conflicts
DmitryGron 7b72090
resolving a conflicts
DmitryGron 9e749a4
resolving a conflicts
DmitryGron 1c7d92a
resolving a conflicts
DmitryGron 7b90ce4
WS-1840 updating offline page for nextjs
DmitryGron 2208eca
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron 94efa25
updates
DmitryGron 4ebc7fc
Merge remote-tracking branch 'origin/latest' into WS-1840-offline-pag…
DmitryGron 8cfc3fe
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron 3d1a82b
adding export to VARIANCE
DmitryGron 5832e58
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron 05b114b
updating bundle size
DmitryGron 05530d7
updating due to lint error
DmitryGron f3528df
updating due to lint error
DmitryGron c83b4aa
updating due to lint error
DmitryGron 96408a9
Update SW version to v0.3.1 and hash for offline page changes
DmitryGron 256ba1a
Add offline page test snapshots
DmitryGron 3089afe
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron 5a8fc1c
Simplify SW install event - remove unnecessary HTML parsing
DmitryGron 8d7da96
Add resource caching to SW install for offline page functionality
DmitryGron 39b3bcc
Fix offline page: cache-first for scripts/styles + fix fetch event li…
DmitryGron 128659f
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron 20faeb6
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron 27805f5
Remove auto-caching of network responses to prevent cache bloat
DmitryGron a5f61c5
reverting bundle size config
DmitryGron 44d62a7
Merge branch 'latest' into WS-1840-offline-page-nextjs
DmitryGron 68bc941
Fix PWA offline page: dynamically extract service from URL
DmitryGron 168f75a
Revert "Fix PWA offline page: dynamically extract service from URL"
jinidev 0d6ff91
adding offline page PWA + browser
DmitryGron 9f31add
conflict resolved
jinidev 893ef9f
remove emoji
jinidev f6f171a
adding offline pwa only
DmitryGron 844dd02
conflict reslved
jinidev 29cb53f
service worker changes to render offline page in PWA apps
jinidev c50e8e2
Merge branch 'latest' of https://github.com/bbc/simorgh into ws-1837-…
jinidev b7de762
some more changes - cleaned sw.js
jinidev bb52f0a
Merge branch 'WS-1840-offline-page-nextjs' of https://github.com/bbc/…
jinidev c78bba5
Merge branch 'WS-1840-offline-page-nextjs' into ws-1837-service-worke…
jinidev aaf9932
Merge branch 'ws-1837-service-worker-changes' of https://github.com/b…
jinidev 9698791
clean up
jinidev 0a8a0f3
clean up- unwanted files removed
jinidev b5f11e9
added isPWA to express rendered apps
jinidev 3a65db7
removed hasOfflineFunctionlity variable
jinidev 6e2c15f
resolving errors
DmitryGron 240c0e6
Merge branch 'WS-1840-offline-page-nextjs' into ws-1837-service-worke…
DmitryGron eaa879e
fixing errors
DmitryGron 518f10b
Added custom hooks
jinidev c6b0783
some tests fixes
jinidev e78659b
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 2fc7f2f
Updated sw.js for unit tests fix
jinidev 54cb50b
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev b6c7b86
Added mock navigator setup in tests
jinidev ef287c7
conflict reso;lved
jinidev 1bbe2d8
tests fix
jinidev 103eac5
Merge branch 'latest' into ws-1837-service-worker-changes
elvinasv 75f7b76
More unit tests fix
jinidev 45ed1a7
lint fixes
jinidev d258fb7
Merge branch 'latest' into ws-1837-service-worker-changes
DmitryGron 49b64eb
testfixes
jinidev aed2769
Merge branch 'ws-1837-service-worker-changes' of https://github.com/b…
jinidev 5c229b2
testing sw.js
jinidev bfc693b
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 969f8eb
testing sw.js -2
jinidev b32c366
testing sw.js -3
jinidev 48b0f95
testing sw.js-4
jinidev 6354778
conflict resolved
jinidev 8a01bd4
tests fix
jinidev 7cc58e6
more fixes
jinidev d79da48
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 85222f2
bypass 404, 503 errors in network requests
jinidev 6b6f594
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 367fe0f
fixing lint issues
jinidev 0519711
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev b2d1363
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev a25a504
some changes in sw.js
jinidev 72ee34b
removing nextjs static assets to avoid loop reloadand some other fixes
jinidev ebfe1d7
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 25c8766
cache was missing
jinidev ea22129
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 037e91c
revert to latest stable version
jinidev e3c3bba
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev d91548a
reveiew comments addressed - docparser , default browser behavious, i…
jinidev e6bd966
more testcases in sw.test.js
jinidev 9fc1803
unit tests for hooks
jinidev d3f680f
removed pwa_installed variable , removed DOMParser
jinidev 8800ec6
test cases fix
jinidev 938ef05
Updated cache name , updated offlinepage resource caching
jinidev c8f3781
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 18d4969
updates on fetchng /next/static files
jinidev b4e6341
conflict resolved
jinidev 91c60fa
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 899169a
conflicts reolved in app.page.tsx
jinidev e38b747
revert back _app.page.tsx
jinidev 646696f
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 068e4fe
PWA service worker changes into _app.page.tsx
jinidev 674faa8
Merge branch 'latest' into ws-1837-service-worker-changes
elvinasv 2f7ca95
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 78e5cd6
Merge branch 'latest' into ws-1837-service-worker-changes
elvinasv f513db3
WS-1838: Add PWA Offline page tracking (#13545)
DmitryGron cfdb08d
sw.js -removed filtering in cachingoffline resource, commented PWASer…
jinidev df00544
refactor: remove comment; remove redundant cacheOfflinePageAndResourc…
elvinasv e04576c
Changed scope of sw.js to /sw.js
jinidev 30d97de
updated nextjsconfig for /sw.js scope , removed pwaserviceworker comp
jinidev efdd97b
reverted scope from/sw.js to /service
jinidev 95f9e61
added scope / in sw registration
jinidev 9288c7f
testing with initial sw.js
jinidev 0db3934
Reverting back to new changes after testing
jinidev 227c73c
refactor: use explicit PWA offline flag
elvinasv 40f570f
refactor: use Service-Worker-Allowed
elvinasv f5f7537
added trailingSlash config
jinidev b6ebef6
removed trailingSlash
jinidev cf189b6
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 7bce52e
feat: add logger
elvinasv 9e3fcca
Merge branch 'ws-1837-service-worker-changes' of github.com:bbc/simor…
elvinasv 6c32f85
refactor: cleanup
elvinasv dc41ab3
feat: add nofollow noindex for the offline page
elvinasv 0df5fa4
test: update hash
elvinasv f0b0c4e
chore: fix warning
elvinasv 2518e51
Merge branch 'latest' of github.com:bbc/simorgh into ws-1837-service-…
elvinasv 4ebfba8
Commenting next-config service-worker-allowed
jinidev 8ddbe92
update hash in test
jinidev 6ef497e
refactor: remove console.logs
elvinasv 017d564
Update src/app/hooks/useServiceWorkerRegistration/index.test.tsx
jinidev bb2970d
Update src/app/hooks/useServiceWorkerRegistration/index.test.tsx
jinidev aede4d4
Updated test cases for serviceworker.tsx
jinidev f04b3b4
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev 07813fe
Merge branch 'latest' into ws-1837-service-worker-changes
elvinasv a0f05fe
Merge branch 'latest' into ws-1837-service-worker-changes
jinidev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,19 +3,64 @@ | |
| /* eslint-disable no-unused-vars */ | ||
| /* eslint-disable no-undef */ | ||
| /* eslint-disable no-restricted-globals */ | ||
| const version = 'v0.3.0'; | ||
| const cacheName = 'simorghCache_v1'; | ||
|
|
||
| const service = self.location.pathname.split('/')[1]; | ||
| const hasOfflinePageFunctionality = false; | ||
| const OFFLINE_PAGE = `/${service}/offline`; | ||
|
|
||
| self.addEventListener('install', event => { | ||
| event.waitUntil(async () => { | ||
| const cache = await caches.open(cacheName); | ||
| if (hasOfflinePageFunctionality) await cache.add(OFFLINE_PAGE); | ||
| }); | ||
| }); | ||
|
|
||
| const version = 'v0.3.2'; | ||
| // Update cache name when changing caching logic / changes in offlinepage.tsx | ||
| const cacheName = 'simorghCache_v2'; | ||
| const pwaClients = new Map(); | ||
| let isPWADeviceOffline = false; | ||
|
|
||
| // -------------------- | ||
| // Helper Functions | ||
| // -------------------- | ||
| const loggerEnabled = true; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: We will disable logging or delete this before merging |
||
| const logger = (...args) => { | ||
| if (!loggerEnabled) return; | ||
| // eslint-disable-next-line no-console | ||
| console.log(`[SW ${version}]`, ...args); | ||
| }; | ||
|
|
||
| const getServiceFromUrl = url => new URL(url).pathname.split('/')[1]; | ||
| const getOfflinePageUrl = service => `/${service}/offline`; | ||
|
|
||
| const cacheResource = async (cache, url) => { | ||
| try { | ||
| const response = await fetch(url); | ||
| if (response.ok) await cache.put(url, response.clone()); | ||
| return response; | ||
| } catch (err) { | ||
| logger(`Failed to cache ${url}:`, err); | ||
| return null; | ||
| } | ||
| }; | ||
|
|
||
| const cacheOfflinePageAndResources = async service => { | ||
| const cache = await caches.open(cacheName); | ||
| const offlinePageUrl = new URL( | ||
| getOfflinePageUrl(service), | ||
| self.location.origin, | ||
| ).href; | ||
|
|
||
| if (await cache.match(offlinePageUrl)) return; | ||
|
|
||
| const resp = await cacheResource(cache, offlinePageUrl); | ||
| if (!resp || !resp.ok) return; | ||
|
|
||
| logger(`Cached offline page for ${service}`); | ||
|
|
||
| const html = await resp.text(); | ||
| const scriptSrcs = [ | ||
| ...html.matchAll(/<script[^>]+src=["']([^"']+)["']/g), | ||
| ].map(m => m[1]); | ||
| const linkHrefs = [...html.matchAll(/<link[^>]+href=["']([^"']+)["']/g)].map( | ||
| m => m[1], | ||
| ); | ||
|
|
||
| const resources = [...scriptSrcs, ...linkHrefs].filter(Boolean); | ||
|
|
||
| logger(`Caching final offline resources for ${service}:`, resources); | ||
| await Promise.allSettled(resources.map(url => cacheResource(cache, url))); | ||
| }; | ||
|
|
||
| const CACHEABLE_FILES = [ | ||
| // Reverb | ||
|
|
@@ -35,24 +80,60 @@ const CACHEABLE_FILES = [ | |
| const WEBP_IMAGE = | ||
| /^https:\/\/ichef(\.test)?\.bbci\.co\.uk\/(news|images|ace\/(standard|ws))\/.+.webp$/; | ||
|
|
||
| // -------------Install event ------- | ||
| self.addEventListener('install', () => { | ||
| logger(`Installing...`); | ||
| self.skipWaiting(); | ||
| }); | ||
|
|
||
| // -------Activate Handler------------- | ||
| self.addEventListener('activate', event => { | ||
| logger(`Activating...`); | ||
| event.waitUntil( | ||
| (async () => { | ||
| const keys = await caches.keys(); | ||
| await Promise.all( | ||
| keys.map(key => key !== cacheName && caches.delete(key)), | ||
| ); | ||
| await self.clients.claim(); | ||
| })(), | ||
| ); | ||
| }); | ||
|
|
||
| // -------Message Event------------- | ||
| self.addEventListener('message', async event => { | ||
| logger('Message received:', event.data); | ||
|
|
||
| if (event.data?.type === 'PWA_STATUS') { | ||
| const clientId = event.source.id; | ||
| const { isPWA } = event.data; | ||
|
|
||
| if (isPWA) { | ||
| pwaClients.set(clientId, true); | ||
| const service = getServiceFromUrl(event.source.url); | ||
| await cacheOfflinePageAndResources(service); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| // -------Fetch Handler------------- | ||
| const fetchEventHandler = async event => { | ||
| logger(`[SW FETCH] Request: ${event.request.url}`); | ||
| const isRequestForCacheableFile = CACHEABLE_FILES.some(cacheableFile => | ||
| new RegExp(cacheableFile).test(event.request.url), | ||
| ); | ||
|
|
||
| const isRequestForWebpImage = WEBP_IMAGE.test(event.request.url); | ||
| const isNavigationMode = event.request.mode === 'navigate'; | ||
|
|
||
| if (isRequestForWebpImage) { | ||
| const req = event.request.clone(); | ||
|
|
||
| // Inspect the accept header for WebP support | ||
|
|
||
| const supportsWebp = | ||
| req.headers.has('accept') && req.headers.get('accept').includes('webp'); | ||
|
|
||
| // if supports webp is false in request header then don't use it | ||
| // if accept header doesn't indicate support for webp remove .webp extension | ||
|
|
||
| if (!supportsWebp) { | ||
| const imageUrlWithoutWebp = req.url.replace('.webp', ''); | ||
| event.respondWith( | ||
|
|
@@ -73,22 +154,66 @@ const fetchEventHandler = async event => { | |
| return response; | ||
| })(), | ||
| ); | ||
| } else if (hasOfflinePageFunctionality && event.request.mode === 'navigate') { | ||
| event.respondWith(async () => { | ||
| try { | ||
| const preloadResponse = await event.preloadResponse; | ||
| if (preloadResponse) { | ||
| return preloadResponse; | ||
| } else if (isNavigationMode) { | ||
| const { url } = event.request; | ||
|
|
||
| event.respondWith( | ||
| (async () => { | ||
| const client = await self.clients.get(event.clientId); | ||
| const isPWA = client && pwaClients.get(client.id); | ||
| const cache = await caches.open(cacheName); | ||
|
|
||
| // TODO: Used for testing - to be removed | ||
| logger('📌 [SW FETCH] Navigation', { | ||
| url: event.request.url, | ||
| clientId: event.clientId, | ||
| isPWA, | ||
| client, | ||
| event, | ||
| pwaClients, | ||
| isPWADeviceOffline, | ||
| }); | ||
| try { | ||
| // Use preload if available | ||
| const preloadResp = await event.preloadResponse; | ||
| if (preloadResp) return preloadResp; | ||
|
|
||
| const networkResp = await fetch(event.request); | ||
| isPWADeviceOffline = false; | ||
| return networkResp; | ||
| } catch (err) { | ||
| // Only show offline page for installed PWA | ||
| if (isPWA) { | ||
| const service = getServiceFromUrl(url); | ||
| const offlineUrl = new URL( | ||
| getOfflinePageUrl(service), | ||
| self.location.origin, | ||
| ).href; | ||
|
|
||
| const cachedOffline = await cache.match(offlineUrl); | ||
| if (cachedOffline) { | ||
| isPWADeviceOffline = true; | ||
| logger('[SW] Serving cached offline page'); | ||
| return cachedOffline; | ||
| } | ||
| } | ||
| // fallback to browser default behavior | ||
| throw err; | ||
| } | ||
| const networkResponse = await fetch(event.request); | ||
| return networkResponse; | ||
| } catch (error) { | ||
| })(), | ||
| ); | ||
| } else if (isPWADeviceOffline) { | ||
| logger(`[SW v${version}] Serving isPWADeviceOffline ${event.request.url}`); | ||
| event.respondWith( | ||
| (async () => { | ||
| const cache = await caches.open(cacheName); | ||
| const cachedResponse = await cache.match(OFFLINE_PAGE); | ||
| return cachedResponse; | ||
| } | ||
| }); | ||
| const cached = await cache.match(event.request); | ||
| if (cached) return cached; | ||
| return fetch(event.request); | ||
| })(), | ||
| ); | ||
| } | ||
|
|
||
| return; | ||
| }; | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.