kopia lustrzana https://gitlab.com/rysiekpl/libresilient
now displaying a user-facing HTML error page when a navigation request fails (ref. #36)
rodzic
58cb74cb2b
commit
e443e26aae
|
@ -1317,15 +1317,15 @@ self.addEventListener('activate', async event => {
|
|||
*/
|
||||
let still_loading_messages = {
|
||||
title: "Still loading",
|
||||
body: "The content is still being loaded, thank you for your patience.<br/><br/>This page will auto-reload in a few seconds. If it does not, please <a href='./'>click here</a>."
|
||||
body: "The resource is still being loaded, thank you for your patience.<br/><br/>This page will auto-reload in a few seconds. If it does not, please <a href='./'>click here</a>."
|
||||
}
|
||||
let success_messages = {
|
||||
title: "Loaded, redirecting!",
|
||||
body: "The content has loaded, you are being redirected."
|
||||
body: "The resource has loaded, you are being redirected."
|
||||
}
|
||||
let failure_messages = {
|
||||
title: "Loading failed.",
|
||||
body: "We're sorry, we were unable to load this page."
|
||||
body: "We're sorry, we were unable to load this resource."
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1395,7 +1395,13 @@ let getUserFacingHTML = (init_msgs, success_msgs=false, failure_msgs=false) => {
|
|||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
<h1 id="header">${init_msgs.title}<span id="throbber1">•</span><span id="throbber2">•</span><span id="throbber3">•</span></h1>
|
||||
<h1 id="header">${init_msgs.title}`
|
||||
|
||||
if (success_msgs !== false) {
|
||||
html += `<span id="throbber1">•</span><span id="throbber2">•</span><span id="throbber3">•</span>`
|
||||
}
|
||||
|
||||
html += `</h1>
|
||||
<p id="working">attempts: <span id="status">1</span></p>
|
||||
<p id="text">${init_msgs.body}</p>
|
||||
<p id="errors"></p>
|
||||
|
@ -1466,6 +1472,7 @@ let getUserFacingHTML = (init_msgs, success_msgs=false, failure_msgs=false) => {
|
|||
|
||||
self.addEventListener('fetch', async event => {
|
||||
return void event.respondWith(async function () {
|
||||
|
||||
// initialize the SW; this is necessary as SW can be stopped at any time
|
||||
// and restarted when an event gets triggered -- `fetch` is just such an event.
|
||||
//
|
||||
|
@ -1475,6 +1482,7 @@ self.addEventListener('fetch', async event => {
|
|||
//
|
||||
// the good news is that the config.json should have been cached already
|
||||
await initServiceWorker()
|
||||
|
||||
// if event.resultingClientId is available, we need to use this
|
||||
// otherwise event.clientId is what we want
|
||||
// ref. https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/resultingClientId
|
||||
|
@ -1541,82 +1549,121 @@ self.addEventListener('fetch', async event => {
|
|||
// get handled by plugins in case of an error
|
||||
let lrPromise = getResourceThroughLibResilient(url, init, clientId)
|
||||
|
||||
// is the stillLoadingScreen enabled, and are we navigating, or just fetching some resource?
|
||||
if ( ( self.LibResilientConfig.stillLoadingTimeout > 0 ) && ( event.request.mode === 'navigate' ) ) {
|
||||
// are we navigating, or just fetching some resource?
|
||||
if ( event.request.mode === 'navigate' ) {
|
||||
|
||||
self.log('service-worker', `handling a navigate request; still-loading timeout: ${self.LibResilientConfig.stillLoadingTimeout}.`)
|
||||
// this is the promise we will want to return in the end
|
||||
let finalPromise = null
|
||||
|
||||
let slPromise, slTimeoutId
|
||||
[slPromise, slTimeoutId] = promiseTimeout(self.LibResilientConfig.stillLoadingTimeout, true)
|
||||
// navigating! is the still-loading screen enabled?
|
||||
if ( self.LibResilientConfig.stillLoadingTimeout > 0 ) {
|
||||
|
||||
// make sure to clear the timeout related to slPromise
|
||||
// in case we manage to get the content through the plugins
|
||||
lrPromise
|
||||
.then(()=>{
|
||||
self.log('service-worker', `content retrieved; still-loading timeout cleared.`)
|
||||
clearTimeout(slTimeoutId)
|
||||
})
|
||||
// it is enabled!
|
||||
self.log('service-worker', `handling a navigate request; still-loading timeout: ${self.LibResilientConfig.stillLoadingTimeout}.`)
|
||||
|
||||
// return a Promise that races the "still loading" screen promise against the LibResilient plugins
|
||||
return Promise.race([
|
||||
// regular fetch-through-plugins
|
||||
lrPromise,
|
||||
let slPromise, slTimeoutId
|
||||
[slPromise, slTimeoutId] = promiseTimeout(self.LibResilientConfig.stillLoadingTimeout, true)
|
||||
|
||||
// the "still loading screen"
|
||||
//
|
||||
// this will delay a specified time, and ten return a Response
|
||||
// with very basic HTML informing the user that the page is still loading,
|
||||
// a Refresh header set, and a link for the user to reload the screen manually
|
||||
slPromise
|
||||
.then(()=>{
|
||||
// make sure to clear the timeout related to slPromise
|
||||
// in case we manage to get the content through the plugins
|
||||
lrPromise
|
||||
.then(()=>{
|
||||
self.log('service-worker', `content retrieved; still-loading timeout cleared.`)
|
||||
clearTimeout(slTimeoutId)
|
||||
})
|
||||
|
||||
// inform
|
||||
self.log('service-worker', 'handling a navigate request is taking too long, showing the still-loading screen')
|
||||
// prepare a Promise that races the "still loading" screen promise against the LibResilient plugins
|
||||
finalPromise = Promise.race([
|
||||
// regular fetch-through-plugins
|
||||
lrPromise,
|
||||
|
||||
// we need to create a new Response object
|
||||
// with all the headers added explicitly,
|
||||
// since response.headers is immutable
|
||||
var responseInit = {
|
||||
status: 202,
|
||||
statusText: "Accepted",
|
||||
headers: {},
|
||||
url: url
|
||||
};
|
||||
responseInit.headers['Content-Type'] = "text/html"
|
||||
// refresh: we want a minimum of 1s; stillLoadingTimeout is in ms!
|
||||
//responseInit.headers['Refresh'] = Math.ceil( self.LibResilientConfig.stillLoadingTimeout / 1000 )
|
||||
//responseInit.headers['ETag'] = ???
|
||||
//responseInit.headers['X-LibResilient-ETag'] = ???
|
||||
responseInit.headers['X-LibResilient-Method'] = "still-loading"
|
||||
// the "still loading screen"
|
||||
//
|
||||
// this will delay a specified time, and ten return a Response
|
||||
// with very basic HTML informing the user that the page is still loading,
|
||||
// a Refresh header set, and a link for the user to reload the screen manually
|
||||
slPromise
|
||||
.then(()=>{
|
||||
|
||||
// get the still-loading page contents
|
||||
let stillLoadingHTML = getUserFacingHTML(
|
||||
still_loading_messages,
|
||||
success_messages,
|
||||
failure_messages
|
||||
)
|
||||
// inform
|
||||
self.log('service-worker', 'handling a navigate request is taking too long, showing the still-loading screen')
|
||||
|
||||
let blob = new Blob(
|
||||
[stillLoadingHTML],
|
||||
{type: "text/html"}
|
||||
)
|
||||
// we need to create a new Response object
|
||||
// with all the headers added explicitly,
|
||||
// since response.headers is immutable
|
||||
var responseInit = {
|
||||
status: 202,
|
||||
statusText: "Accepted",
|
||||
headers: {},
|
||||
url: url
|
||||
};
|
||||
responseInit.headers['Content-Type'] = "text/html"
|
||||
responseInit.headers['X-LibResilient-Method'] = "still-loading"
|
||||
|
||||
return new Response(
|
||||
blob,
|
||||
responseInit
|
||||
)
|
||||
})
|
||||
])
|
||||
// get the still-loading page contents
|
||||
let stillLoadingHTML = getUserFacingHTML(
|
||||
still_loading_messages,
|
||||
success_messages,
|
||||
failure_messages
|
||||
)
|
||||
|
||||
let blob = new Blob(
|
||||
[stillLoadingHTML],
|
||||
{type: "text/html"}
|
||||
)
|
||||
|
||||
return new Response(
|
||||
blob,
|
||||
responseInit
|
||||
)
|
||||
})
|
||||
])
|
||||
|
||||
// okay, no still-loading screen, but this is still a navigate request, so we want to display something to the user
|
||||
} else {
|
||||
self.log('service-worker', `handling a navigate request, but still-loading screen is disabled.`)
|
||||
finalPromise = lrPromise
|
||||
}
|
||||
|
||||
// return finalPromise, with a catch!
|
||||
return finalPromise.catch((e)=>{
|
||||
// inform
|
||||
self.log('service-worker', 'handling a failed navigate request, showing the user-facing error screen')
|
||||
|
||||
// we need to create a new Response object
|
||||
// with all the headers added explicitly,
|
||||
// since response.headers is immutable
|
||||
var responseInit = {
|
||||
status: 404,
|
||||
statusText: "Not Found",
|
||||
headers: {},
|
||||
url: url
|
||||
};
|
||||
responseInit.headers['Content-Type'] = "text/html"
|
||||
responseInit.headers['X-LibResilient-Method'] = "failed"
|
||||
|
||||
// get the still-loading page contents
|
||||
// it only needs to display the failure messages
|
||||
let stillLoadingHTML = getUserFacingHTML(
|
||||
failure_messages
|
||||
)
|
||||
|
||||
let blob = new Blob(
|
||||
[stillLoadingHTML],
|
||||
{type: "text/html"}
|
||||
)
|
||||
|
||||
return new Response(
|
||||
blob,
|
||||
responseInit
|
||||
)
|
||||
})
|
||||
|
||||
// nope, just fetching a resource
|
||||
} else {
|
||||
if ( event.request.mode === 'navigate' ) {
|
||||
self.log('service-worker', `handling a navigate request, but still-loading screen is disabled.`)
|
||||
} else {
|
||||
self.log('service-worker', 'handling a regular request; still-loading screen will not be used.')
|
||||
}
|
||||
// no need for the whole "still loading screen" flow
|
||||
return lrPromise;
|
||||
// no need for a still-loading screen, no need for an user-facing error screen if the request fails
|
||||
self.log('service-worker', 'handling a regular request; still-loading screen will not be used.')
|
||||
return lrPromise
|
||||
}
|
||||
}())
|
||||
});
|
||||
|
|
Ładowanie…
Reference in New Issue