Animación de hoja de papel al pasar página y URLs versionadas para saltar la caché del proxy

- Lector por páginas: animaciones Pasar hoja (la hoja se curva al levantarla, con sombra), deslizar y
  fundido; hacia atrás la página anterior vuelve y se coloca encima.
- app.js, style.css y sw.js se sirven con ?v=<hash> para que ni el proxy ni el navegador den una copia vieja.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-01 12:41:22 -06:00
co-authored by Claude Opus 5.5
parent 86999b5725
commit 29af893917
5 changed files with 237 additions and 14 deletions
+9
View File
@@ -765,10 +765,19 @@ const requireUser = req => {
}
const MIME = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8', '.svg': 'image/svg+xml', '.webmanifest': 'application/manifest+json', '.png': 'image/png' }
// index.html enlaza app.js y style.css con ?v=<hash del contenido>: si un proxy delante cambia el
// no-cache por una caché larga (Nginx Proxy Manager con «Cache Assets»), cada versión nueva tiene otra
// URL y el navegador no se queda con la vieja. Los archivos no cambian mientras el contenedor vive.
const assetVersion = name => crypto.createHash('sha256').update(fs.readFileSync(path.join(PUBLIC_DIR, name))).digest('hex').slice(0, 10)
const INDEX_HTML = fs.readFileSync(path.join(PUBLIC_DIR, 'index.html'), 'utf8')
.replace('src="/app.js"', `src="/app.js?v=${assetVersion('app.js')}"`)
.replace('href="/style.css"', `href="/style.css?v=${assetVersion('style.css')}"`)
.replace('<meta name="sw-version" content="">', `<meta name="sw-version" content="${assetVersion('sw.js')}">`)
function serveStatic(res, pathname) {
let file = path.join(PUBLIC_DIR, path.normalize(pathname).replace(/^(\.\.[/\\])+/, ''))
if (!file.startsWith(PUBLIC_DIR) || !fs.existsSync(file) || fs.statSync(file).isDirectory()) file = path.join(PUBLIC_DIR, 'index.html')
res.writeHead(200, { 'Content-Type': MIME[path.extname(file)] || 'application/octet-stream', 'Cache-Control': 'no-cache' })
if (file === path.join(PUBLIC_DIR, 'index.html')) return res.end(INDEX_HTML)
fs.createReadStream(file).pipe(res)
}