feat: create logger; update cached articles on load
This commit is contained in:
parent
ed2364ebe8
commit
4daa099b22
5 changed files with 108 additions and 28 deletions
|
@ -17,7 +17,9 @@ export interface Props {
|
||||||
import type { AppConfig } from '../pages/index.astro';
|
import type { AppConfig } from '../pages/index.astro';
|
||||||
import { getPostCard, renderPost } from '../utils/library'
|
import { getPostCard, renderPost } from '../utils/library'
|
||||||
import { cozify } from '../utils/sanitizer';
|
import { cozify } from '../utils/sanitizer';
|
||||||
|
import { logError, logInfo } from '../utils/logger.mjs';
|
||||||
const cache = await caches.open('cozy-reader');
|
const cache = await caches.open('cozy-reader');
|
||||||
|
const baseUrl = window.location.origin;
|
||||||
let url= new URL(window.location.href);
|
let url= new URL(window.location.href);
|
||||||
// only cached unencoded url param
|
// only cached unencoded url param
|
||||||
const urlParam = url.searchParams.get('url')
|
const urlParam = url.searchParams.get('url')
|
||||||
|
@ -26,16 +28,15 @@ export interface Props {
|
||||||
}
|
}
|
||||||
const { skipSave } = deserialize<Props>('preferences');
|
const { skipSave } = deserialize<Props>('preferences');
|
||||||
const { routerOutlet } = deserialize<AppConfig>('app-config');
|
const { routerOutlet } = deserialize<AppConfig>('app-config');
|
||||||
const includesAppURL = urlParam?.includes(window.location.origin)
|
const includesAppURL = urlParam?.includes(baseUrl) ?? false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const responseFromNetwork = await fetch (url);
|
if (url.href.slice(0, url.href.length - 1) !== baseUrl && !skipSave && !includesAppURL) {
|
||||||
if (responseFromNetwork && !skipSave && !includesAppURL) {
|
logInfo('adding one to cache', {context: 'cozy-reader', data: url})
|
||||||
console.info('[cozy-reader]: adding one to cache', url.pathname)
|
await cache.add(url);
|
||||||
await cache.put(url, responseFromNetwork);
|
|
||||||
}
|
}
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
console.error('[cozy-reader]: ', error)
|
logError('ERR', {context: 'cozy-reader', data: error})
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachedRequests = (await cache.keys())
|
const cachedRequests = (await cache.keys())
|
||||||
|
@ -44,7 +45,7 @@ export interface Props {
|
||||||
const urlParam = urlObj.searchParams.get('url');
|
const urlParam = urlObj.searchParams.get('url');
|
||||||
|
|
||||||
return urlObj.search !== ''
|
return urlObj.search !== ''
|
||||||
&& !urlParam?.startsWith(window.location.origin)
|
&& !urlParam?.startsWith(baseUrl)
|
||||||
&& urlParam !== ''
|
&& urlParam !== ''
|
||||||
&& urlParam !== 'null';
|
&& urlParam !== 'null';
|
||||||
});
|
});
|
||||||
|
@ -63,9 +64,19 @@ export interface Props {
|
||||||
let responseText;
|
let responseText;
|
||||||
|
|
||||||
const fullResponse = await cache.match(url)
|
const fullResponse = await cache.match(url)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const responseFromNetwork = await fetch(url, {method: 'GET'});
|
||||||
|
if (responseFromNetwork && url.slice(0, url.length - 1) !== baseUrl && !skipSave && !includesAppURL) {
|
||||||
|
logInfo('updating cached', {context: 'cozy-reader', data: url})
|
||||||
|
await cache.put(url, responseFromNetwork);
|
||||||
|
}
|
||||||
|
} catch(error) {
|
||||||
|
logError('failed to update cached', {context: 'cozy-reader', data: {url, error}})
|
||||||
|
}
|
||||||
|
|
||||||
fullResponse?.text().then(async data => {
|
fullResponse?.text().then(async data => {
|
||||||
responseText = data;
|
responseText = data;
|
||||||
const { baseUrl } = deserialize<AppConfig>('app-config');
|
|
||||||
const cleanedResponse = await cozify(responseText, baseUrl)
|
const cleanedResponse = await cozify(responseText, baseUrl)
|
||||||
const html = document.createElement('html');
|
const html = document.createElement('html');
|
||||||
html.innerHTML = cleanedResponse;
|
html.innerHTML = cleanedResponse;
|
||||||
|
@ -82,6 +93,7 @@ export interface Props {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
localStorage.setItem('scrollPosition', window.scrollY.toString());
|
localStorage.setItem('scrollPosition', window.scrollY.toString());
|
||||||
scrollTo(0,0);
|
scrollTo(0,0);
|
||||||
|
logInfo('using cached response', {context: 'cozy-reader', data: url})
|
||||||
renderPost(cleanedResponse, url, routerOutlet)
|
renderPost(cleanedResponse, url, routerOutlet)
|
||||||
}
|
}
|
||||||
const item = document.createElement('li');
|
const item = document.createElement('li');
|
||||||
|
@ -105,8 +117,8 @@ export interface Props {
|
||||||
const fullResponse = await cache.match(url)
|
const fullResponse = await cache.match(url)
|
||||||
fullResponse?.text().then(async (data) => {
|
fullResponse?.text().then(async (data) => {
|
||||||
const responseText = data;
|
const responseText = data;
|
||||||
const { baseUrl } = deserialize<AppConfig>('app-config');
|
|
||||||
const cleanedResponse = await cozify(responseText, baseUrl);
|
const cleanedResponse = await cozify(responseText, baseUrl);
|
||||||
|
logInfo('using cached response', {context: 'cozy-reader', data: url})
|
||||||
renderPost(cleanedResponse, url, routerOutlet, true);
|
renderPost(cleanedResponse, url, routerOutlet, true);
|
||||||
if (isHome) {
|
if (isHome) {
|
||||||
const scrollPosition = localStorage.getItem('scrollPosition');
|
const scrollPosition = localStorage.getItem('scrollPosition');
|
||||||
|
|
|
@ -11,7 +11,6 @@ export const prerender = false;
|
||||||
|
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
routerOutlet: 'router-outlet',
|
routerOutlet: 'router-outlet',
|
||||||
baseUrl: Astro.url.origin
|
|
||||||
};
|
};
|
||||||
export type AppConfig = typeof appConfig;
|
export type AppConfig = typeof appConfig;
|
||||||
|
|
||||||
|
|
47
src/sw.js
47
src/sw.js
|
@ -4,20 +4,35 @@
|
||||||
* @see https://ayco.io/n/@ayco/astro-sw
|
* @see https://ayco.io/n/@ayco/astro-sw
|
||||||
*/
|
*/
|
||||||
const cacheName = `${__prefix ?? 'app'}-v${__version ?? '000'}`
|
const cacheName = `${__prefix ?? 'app'}-v${__version ?? '000'}`
|
||||||
|
// const forceLogging = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: remove this once astro-sw allows importing utils
|
||||||
|
*/
|
||||||
|
function logInfo(message, {context, force, data} = {}) {
|
||||||
|
context = context !== ''
|
||||||
|
? `[${context}]: `
|
||||||
|
: ''
|
||||||
|
|
||||||
|
if (force || isDev) {
|
||||||
|
console.info(`!!! ${context}${message}`, data ?? '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const addResourcesToCache = async (resources) => {
|
const addResourcesToCache = async (resources) => {
|
||||||
const cache = await caches.open(cacheName);
|
const cache = await caches.open(cacheName);
|
||||||
console.log('[cozy-sw]: adding resources to cache...', resources)
|
logInfo('adding resources to cache...', { force: forceLogging, context: 'cozy-sw', data: resources })
|
||||||
await cache.addAll(resources);
|
await cache.addAll(resources);
|
||||||
};
|
};
|
||||||
|
|
||||||
const putInCache = async (request, response) => {
|
const putInCache = async (request, response) => {
|
||||||
const cache = await caches.open(cacheName);
|
const cache = await caches.open(cacheName);
|
||||||
console.log('[cozy-sw]: adding one response to cache...', request.url)
|
logInfo('adding one response to cache...', { force: forceLogging, context: 'cozy-sw', data: request.url })
|
||||||
// if exists, replace
|
// if exists, replace
|
||||||
|
|
||||||
const keys = await cache.keys();
|
const keys = await cache.keys();
|
||||||
if(keys.includes(request)) {
|
if (keys.includes(request)) {
|
||||||
cache.delete(request);
|
cache.delete(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,21 +50,21 @@ const cacheAndRevalidate = async ({ request, preloadResponsePromise, fallbackUrl
|
||||||
// get network response for revalidation of stale assets
|
// get network response for revalidation of stale assets
|
||||||
const responseFromNetwork = await fetch(request.clone());
|
const responseFromNetwork = await fetch(request.clone());
|
||||||
if (responseFromNetwork) {
|
if (responseFromNetwork) {
|
||||||
console.info('[cozy-sw]: fetched updated assets', responseFromNetwork.url);
|
logInfo('updated cached resource...', { force: forceLogging, context: 'cozy-sw', data: responseFromNetwork.url })
|
||||||
putInCache(request, responseFromNetwork.clone());
|
putInCache(request, responseFromNetwork.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseFromCache) {
|
if (responseFromCache) {
|
||||||
console.info('[cozy-sw]: using cached response', responseFromCache.url);
|
logInfo('using cached response...', { force: forceLogging, context: 'cozy-sw', data: responseFromCache.url })
|
||||||
return responseFromCache;
|
return responseFromCache;
|
||||||
} else{
|
} else {
|
||||||
console.info('[cozy-sw]: using network response', responseFromNetwork.url);
|
logInfo('using network response...', { force: forceLogging, context: 'cozy-sw', data: responseFromNetwork.url })
|
||||||
return responseFromNetwork;
|
return responseFromNetwork;
|
||||||
}
|
}
|
||||||
} catch(error) {
|
} catch (error) {
|
||||||
console.info('[cozy-sw]: failed to fetch updated assets', request.url);
|
logInfo('failed to fetch updated resource', { force: forceLogging, context: 'cozy-sw', data: request.url })
|
||||||
if (responseFromCache) {
|
if (responseFromCache) {
|
||||||
console.info('[cozy-sw]: using cached response', responseFromCache.url);
|
logInfo('using cached response', { force: forceLogging, context: 'cozy-sw', data: responseFromCache.url })
|
||||||
return responseFromCache;
|
return responseFromCache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,18 +78,18 @@ const cacheAndRevalidate = async ({ request, preloadResponsePromise, fallbackUrl
|
||||||
const preloadResponse = await preloadResponsePromise;
|
const preloadResponse = await preloadResponsePromise;
|
||||||
if (preloadResponse) {
|
if (preloadResponse) {
|
||||||
putInCache(request, preloadResponse.clone());
|
putInCache(request, preloadResponse.clone());
|
||||||
console.info('[cozy-sw]: using preload response', preloadResponse.url);
|
logInfo('using preload response', { force: forceLogging, context: 'cozy-sw', data: preloadResponse.url })
|
||||||
return preloadResponse;
|
return preloadResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try to get the resource from the network for 5 seconds
|
// Try to get the resource from the network for 5 seconds
|
||||||
const responseFromNetwork = await fetch(request.clone(), {signal: AbortSignal.timeout(5000)});
|
const responseFromNetwork = await fetch(request.clone(), { signal: AbortSignal.timeout(5000) });
|
||||||
// response may be used only once
|
// response may be used only once
|
||||||
// we need to save clone to put one copy in cache
|
// we need to save clone to put one copy in cache
|
||||||
// and serve second one
|
// and serve second one
|
||||||
putInCache(request, responseFromNetwork.clone());
|
putInCache(request, responseFromNetwork.clone());
|
||||||
console.info('[cozy-sw]: using network response', responseFromNetwork.url);
|
logInfo('using network response', { force: forceLogging, context: 'cozy-sw', data: responseFromNetwork.url })
|
||||||
return responseFromNetwork;
|
return responseFromNetwork;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -82,7 +97,7 @@ const cacheAndRevalidate = async ({ request, preloadResponsePromise, fallbackUrl
|
||||||
// Try the fallback
|
// Try the fallback
|
||||||
const fallbackResponse = await cache.match(fallbackUrl);
|
const fallbackResponse = await cache.match(fallbackUrl);
|
||||||
if (fallbackResponse) {
|
if (fallbackResponse) {
|
||||||
console.info('[cozy-sw]: using fallback cached response', fallbackResponse.url);
|
logInfo('using fallback cached response...', { force: forceLogging, context: 'cozy-sw', data: fallbackResponse.url })
|
||||||
return fallbackResponse;
|
return fallbackResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,12 +119,12 @@ const enableNavigationPreload = async () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.addEventListener('activate', (event) => {
|
self.addEventListener('activate', (event) => {
|
||||||
console.log('[cozy-sw]: activating...', event)
|
logInfo('activating service worker...', { force: forceLogging, context: 'cozy-sw' })
|
||||||
event.waitUntil(enableNavigationPreload());
|
event.waitUntil(enableNavigationPreload());
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('install', (event) => {
|
self.addEventListener('install', (event) => {
|
||||||
console.log('[cozy-sw]: installing...', event)
|
logInfo('installing service worker...', { force: forceLogging, context: 'cozy-sw' })
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
addResourcesToCache([
|
addResourcesToCache([
|
||||||
...(__assets ?? [])
|
...(__assets ?? [])
|
||||||
|
|
54
src/utils/logger.mjs
Normal file
54
src/utils/logger.mjs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
const isDev = import.meta.env.DEV;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* force?: true
|
||||||
|
* context?: string,
|
||||||
|
* data?: any
|
||||||
|
* }} LogOptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} message
|
||||||
|
* @param {LogOptions} options
|
||||||
|
*/
|
||||||
|
export function logMessage(message, {context, force, data} = {}) {
|
||||||
|
context = context !== ''
|
||||||
|
? `[${context}]: `
|
||||||
|
: ''
|
||||||
|
|
||||||
|
if (force || isDev) {
|
||||||
|
console.log(`!!! ${context}${message}`, data ?? '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} message
|
||||||
|
* @param {LogOptions} options
|
||||||
|
*/
|
||||||
|
export function logInfo(message, {context, force, data} = {}) {
|
||||||
|
context = context !== ''
|
||||||
|
? `[${context}]: `
|
||||||
|
: ''
|
||||||
|
|
||||||
|
if (force || isDev) {
|
||||||
|
console.info(`!!! ${context}${message}`, data ?? '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} message
|
||||||
|
* @param {LogOptions} options
|
||||||
|
*/
|
||||||
|
export function logError(message, {context, force, data} = {}) {
|
||||||
|
context = context !== ''
|
||||||
|
? `[${context}]: `
|
||||||
|
: ''
|
||||||
|
|
||||||
|
if (force || isDev) {
|
||||||
|
console.error(`!!! ${context}${message}`, data ?? '');
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue