1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00
next.js/client/next-prefetcher.js
Arunoda Susiripala 36abdc77c5 Prefetch pages with Service Workers (#375)
* Register the service worker.

* Update prefetcher code to do prefetching.

* Implement the core prefetching API.
support "import <Link>, { prefetch } from 'next/prefetch'"

* Implement a better communication system with the service worker.

* Add a separate example for prefetching

* Fix some typos.

* Initiate service worker support even prefetching is not used.
This is pretty important since initiating will reset the cache.
If we don't do this, it's possible to have old cached resources
after the user decided to remove all of the prefetching logic.
In this case, even the page didn't prefetch it'll use the
previously cached pages. That because of there might be a already running
service worker.

* Use url module to get pathname.

* Move prefetcher code to the client from pages
Now we also do a webpack build for the prefetcher code.

* Add prefetching docs to the README.md

* Fix some typo.

* Register service worker only if asked to prefetch
We also clean the cache always, even we initialize
the service worker or not.
2016-12-15 11:13:40 -08:00

101 lines
2.2 KiB
JavaScript

/* global self */
const CACHE_NAME = 'next-prefetcher-v1'
self.addEventListener('install', () => {
console.log('Installing Next Prefetcher')
})
self.addEventListener('activate', (e) => {
console.log('Activated Next Prefetcher')
e.waitUntil(Promise.all([
resetCache(),
notifyClients()
]))
})
self.addEventListener('fetch', (e) => {
e.respondWith(getResponse(e.request))
})
self.addEventListener('message', (e) => {
switch (e.data.action) {
case 'ADD_URL': {
console.log('CACHING ', e.data.url)
sendReply(e, cacheUrl(e.data.url))
break
}
case 'RESET': {
console.log('RESET')
sendReply(e, resetCache())
break
}
default:
console.error('Unknown action: ' + e.data.action)
}
})
function sendReply (e, result) {
const payload = { action: 'REPLY', actionType: e.data.action, replyFor: e.data.id }
result
.then((result) => {
payload.result = result
e.source.postMessage(payload)
})
.catch((error) => {
payload.error = error.message
e.source.postMessage(payload)
})
}
function cacheUrl (url) {
const req = new self.Request(url, {
mode: 'no-cors'
})
return self.caches.open(CACHE_NAME)
.then((cache) => {
return self.fetch(req)
.then((res) => cache.put(req, res))
})
}
function getResponse (req) {
return self.caches.open(CACHE_NAME)
.then((cache) => cache.match(req))
.then((res) => {
if (res) {
console.log('CACHE HIT: ' + req.url)
return res
} else {
console.log('CACHE MISS: ' + req.url)
return self.fetch(req)
}
})
}
function resetCache () {
let cache
return self.caches.open(CACHE_NAME)
.then((c) => {
cache = c
return cache.keys()
})
.then(function (items) {
const deleteAll = items.map((item) => cache.delete(item))
return Promise.all(deleteAll)
})
}
function notifyClients () {
return self.clients.claim()
.then(() => self.clients.matchAll())
.then((clients) => {
const notifyAll = clients.map((client) => {
return client.postMessage({ action: 'NEXT_PREFETCHER_ACTIVATED' })
})
return Promise.all(notifyAll)
})
}