v0.8.2 部署缓存确定性:静态资源补齐 Cache-Control(哈希产物 immutable,入口/SW no-cache),SW 导航强制校验并升级缓存版本

This commit is contained in:
root
2026-11-01 22:32:36 +08:00
parent 2ee5f5760f
commit 5909eabba8
9 changed files with 23 additions and 13 deletions
+8
View File
@@ -0,0 +1,8 @@
# v0.8.2 部署缓存确定性
## 优化
- 服务端静态托管补齐缓存策略:带内容哈希的 /assets/ 产物永久缓存(immutable),index.html 与 sw.js 改为 no-cache 每次校验——部署后任何浏览器/缓存层都会立刻拿到新包。
- PWA Service Worker 页面导航请求强制重新校验(cache: no-cache),缓存存储升级至 v2 自动清理旧条目。
## 说明
- 配合 v0.8.1 的启动竞态修复使用;部署命令不变,部署后普通刷新即可拿到新包(无需强制刷新)。
@@ -1,2 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./web-DCGLAtF7.js","./index-COEpAapF.js","./index-BWain5t9.css"])))=>i.map(i=>d[i]);
import{r as s,_ as i}from"./index-COEpAapF.js";var t;(function(e){e.Documents="DOCUMENTS",e.Data="DATA",e.Library="LIBRARY",e.Cache="CACHE",e.External="EXTERNAL",e.ExternalStorage="EXTERNAL_STORAGE"})(t||(t={}));var a;(function(e){e.UTF8="utf8",e.ASCII="ascii",e.UTF16="utf16"})(a||(a={}));const E=s("Filesystem",{web:()=>i(()=>import("./web-DCGLAtF7.js"),__vite__mapDeps([0,1,2]),import.meta.url).then(e=>new e.FilesystemWeb)});export{t as Directory,a as Encoding,E as Filesystem};
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./web-BQsFOvf-.js","./index-COxaR0MK.js","./index-BWain5t9.css"])))=>i.map(i=>d[i]);
import{r as s,_ as i}from"./index-COxaR0MK.js";var t;(function(e){e.Documents="DOCUMENTS",e.Data="DATA",e.Library="LIBRARY",e.Cache="CACHE",e.External="EXTERNAL",e.ExternalStorage="EXTERNAL_STORAGE"})(t||(t={}));var a;(function(e){e.UTF8="utf8",e.ASCII="ascii",e.UTF16="utf16"})(a||(a={}));const E=s("Filesystem",{web:()=>i(()=>import("./web-BQsFOvf-.js"),__vite__mapDeps([0,1,2]),import.meta.url).then(e=>new e.FilesystemWeb)});export{t as Directory,a as Encoding,E as Filesystem};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -8,7 +8,7 @@
<link rel="icon" href="./icons/icon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="./icons/icon-192.png" />
<title>实习工作日志</title>
<script type="module" crossorigin src="./assets/index-COEpAapF.js"></script>
<script type="module" crossorigin src="./assets/index-COxaR0MK.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-BWain5t9.css">
</head>
<body>
+2 -2
View File
@@ -1,4 +1,4 @@
const CACHE = 'intern-log-v1'
const CACHE = 'intern-log-v2'
const CORE = ['./', './index.html']
self.addEventListener('install', event => {
@@ -22,7 +22,7 @@ self.addEventListener('fetch', event => {
// 页面导航:网络优先,离线回退缓存的应用壳
if (req.mode === 'navigate') {
event.respondWith(
fetch(req)
fetch(req, { cache: 'no-cache' })
.then(resp => {
const clone = resp.clone()
caches.open(CACHE).then(c => c.put('./index.html', clone))
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "intern-log",
"private": true,
"version": "0.8.1",
"version": "0.8.2",
"type": "module",
"scripts": {
"dev": "vite",
+2 -2
View File
@@ -1,4 +1,4 @@
const CACHE = 'intern-log-v1'
const CACHE = 'intern-log-v2'
const CORE = ['./', './index.html']
self.addEventListener('install', event => {
@@ -22,7 +22,7 @@ self.addEventListener('fetch', event => {
// 页面导航:网络优先,离线回退缓存的应用壳
if (req.mode === 'navigate') {
event.respondWith(
fetch(req)
fetch(req, { cache: 'no-cache' })
.then(resp => {
const clone = resp.clone()
caches.open(CACHE).then(c => c.put('./index.html', clone))
+4 -2
View File
@@ -331,16 +331,18 @@ async function handle(req, res) {
if (rel === '/' || rel === '') rel = '/index.html'
const file = path.normalize(path.join(DIST_DIR, rel))
if (!file.startsWith(DIST_DIR)) { json(res, 403, { error: 'forbidden' }); return }
// 带内容哈希的构建产物可永久缓存;入口与 SW 每次校验,保证部署后立刻拿到新包
const cacheControl = rel.startsWith('/assets/') ? 'public, max-age=31536000, immutable' : 'no-cache'
fs.readFile(file, (err, data) => {
if (err) {
fs.readFile(path.join(DIST_DIR, 'index.html'), (e2, d2) => {
if (e2) { json(res, 404, { error: 'not found' }); return }
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-cache' })
res.end(d2)
})
return
}
res.writeHead(200, { 'Content-Type': MIME[path.extname(file).toLowerCase()] || 'application/octet-stream' })
res.writeHead(200, { 'Content-Type': MIME[path.extname(file).toLowerCase()] || 'application/octet-stream', 'Cache-Control': cacheControl })
res.end(data)
})
return