feat(pwa): add precached files

This commit is contained in:
Julien Oculi 2024-07-16 23:52:06 +02:00
parent 2ded36b38b
commit f2b39d0288
5 changed files with 77 additions and 20 deletions

18
dev.ts
View file

@ -11,14 +11,14 @@ await dev(import.meta.url, './main.ts', {
server: {
cert: await Deno.readTextFile('./cert/cohabit.localhost.pem'),
key: await Deno.readTextFile('./cert/cohabit.localhost-key.pem'),
hostname,
onListen: (({ port }) => {
console.log(
`\n\t%c Server started %c %chttps://${hostname}:${port}\n`,
'font-weight: bold; background-color: blue',
'',
'color: blue; text-decoration: underline'
)
})
hostname,
onListen: (({ port }) => {
console.log(
`\n\t%c Server started %c %chttps://${hostname}:${port}\n`,
'font-weight: bold; background-color: blue',
'',
'color: blue; text-decoration: underline',
)
}),
},
})

View file

@ -2,7 +2,7 @@ import { requestApi } from ':src/utils.ts'
export default function RegisterServiceWorker() {
if ('serviceWorker' in navigator) {
import('./StartServiceWorker.tsx').then(async (mod) => {
import(':islands/StartServiceWorker.tsx').then(async (mod) => {
const href = mod.default()
const registration = await navigator.serviceWorker.register(href, {
scope: '/',

View file

@ -4,7 +4,7 @@ const IS_SW = 'onpushsubscriptionchange' in self
export default function StartServiceWorker() {
if (IS_SW) {
main()
main(location.origin)
}
return new URL(import.meta.url).pathname
}

View file

@ -0,0 +1,54 @@
import { SessionHandlers } from ':src/session/mod.ts'
import { respondApi } from ':src/utils.ts'
import { expandGlob } from '$std/fs/mod.ts'
export type PrecacheResponse = { version: string; files: string[] }
// Updated only at server start
const version = crypto.randomUUID()
export const handler: SessionHandlers = {
async GET() {
try {
const files: string[] = ['/', '/imports/markdown_css']
const paths = ['/static/**', '/_fresh/static/**']
const routes = '/routes/*'
//Pre-cache routes
for await (const route of expandGlob(routes, { root: '.' })) {
if (!route.isDirectory) continue
if (route.name === 'api') continue
if (route.name === 'imports') continue
files.push(strip(routes, route))
}
// Pre-cache files
for (const path of paths) {
for await (const entry of expandGlob(path, { root: '.' })) {
if (entry.isFile) {
files.push(strip(path, entry))
}
}
}
return respondApi<'success', PrecacheResponse>('success', {
version,
files,
})
} catch (error) {
return respondApi('error', error)
}
},
}
function strip(root: string, { path }: { path: string }) {
return path
// Force unix/web separator
.replaceAll('\\', '/')
.replace(
// Remove root slash and glob *
root.slice(1).replaceAll('*', ''),
'/',
)
}

View file

@ -1,17 +1,21 @@
/// <reference no-default-lib="true"/>
/// <reference lib="webworker" />
import type { PrecacheResponse } from '../../routes/api/serviceworker/precache.tsx'
// Force load service worker types
const self = globalThis as unknown as ServiceWorkerGlobalScope
const cacheName = 'v1' //TODO dynamique cache key
const _preCachedPaths = ['/', '/css/*', '/assets/*'] //TODO pre-cache these paths
export async function main(origin: string) {
const cacheConfig = await fetch(
new URL('/api/serviceworker/precache', origin),
).then((response) => response.json() as Promise<PrecacheResponse>)
const cacheName = cacheConfig.version
export function main() {
self.addEventListener('install', (event) => {
//TODO handle installation
event.waitUntil(
addToCache([]),
//precache static files and routes index
addToCache(cacheName, cacheConfig.files)
)
})
@ -35,9 +39,8 @@ export function main() {
}
})
}
async function addToCache(ressources: string[]) {
const cache = await caches.open(cacheName) //TODO dynamique cache key
await cache.addAll(ressources)
//TODO list statics
async function addToCache(cacheName: string, ressources: string[]) {
const cache = await caches.open(cacheName)
await cache.addAll(ressources)
}