Pagefold

Network and cache hooks

Hooks around the request, its errors and the cache.

These hooks fire while Pagefold gets the next page. This is the order, and what ends each path:

#What happensHookIf it goes wrong
1The request is sentfetch:requestA network error fails the visit
2The request takes longer than timeoutfetch:timeoutThe visit fails
3The response arrives with a status that failOnStatus rejectsfetch:errorThe visit fails
4The response body is emptynoneThe visit fails
5The page is stored in the cachecache:set

“The visit fails” means visit:fail fires and, by default, the browser loads the page normally, so the visitor never gets stuck. If the visit is aborted because the visitor clicked another link, no hook fires: it is a normal event, not a failure.

fetch:request

Just before the request. Arguments: { url, options }, where options are the fetch options (headers, method, body, signal). The default calls fetch(url, options) and returns the Response.

Use before to change the request, or replace to use your own function:

pagefold.hooks.before('fetch:request', (visit, { options }) => {
  options.headers = { ...options.headers, Authorization: `Bearer ${token()}` }
})

The signal in options is connected to the visit, so aborting the visit aborts the request.

Use replace when you need to change how the request is made, for example to send cookies to another subdomain. Remember to pass the arguments on and to return the Response:

pagefold.hooks.replace('fetch:request', (visit, { url, options }) =>
  fetch(url, { ...options, credentials: 'include' })
)

fetch:error

The response status counts as a failure (failOnStatus, by default only 500). Arguments: { url, status, response }. It is awaited before the visit fails.

// A 404 is shown like any page, but a 500 or a 503 sends the visitor to the browser's own page
new Pagefold({ failOnStatus: (status) => status >= 500 })

pagefold.hooks.on('fetch:error', (visit, { status, url }) => {
  reportError(`Page ${url} answered ${status}`)
})

fetch:timeout

The request exceeded the timeout option (milliseconds, 0 means no limit). Arguments: { url }. Awaited before the visit fails.

Without a timeout a slow server leaves the visitor looking at the old page with nothing happening. A limit of a few seconds turns that into a normal page load, which at least shows the browser’s own progress:

new Pagefold({ timeout: 8000 })

cache:set and cache:clear

A page was stored in the cache: { page }. The cache was emptied. These are not awaited.

pagefold.hooks.on('cache:set', (visit, { page }) => {
  console.log('cached', page.url)
})

Which hook for which job

I want to…Use
Add a header or a token to every requestbefore on fetch:request
Send cookies, or use my own fetchreplace on fetch:request
Log or report pages that failon for fetch:error and fetch:timeout
Decide what counts as a failurethe failOnStatus option
Know when a page was storedon for cache:set
Read or edit the stored pagespagefold.cache, see Caching and history

Failing visits

A visit that fails in fetch:error, fetch:timeout or a network error ends in visit:fail, and by default the browser loads the page normally. See Visit hooks.