diff --git a/README.md b/README.md index 8a61486..6e46bab 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ vp run ready # format + lint + typecheck + test + build ## 测试部署 -测试站部署在 Vercel,项目根目录保持为仓库根目录。Vercel 会按 `vercel.json` 构建主站及其传递依赖,并发布 `apps/website/dist`。主站源码、静态资源、API 契约源码、UBB 或相关构建配置发生变化时才会部署;测试、探测数据、生成文档和 README 等非构建输入不会触发主站部署。Vue Router 使用 history 模式,所有未命中静态文件的请求都会回退到 `index.html`。 +测试站部署在 Vercel,项目根目录保持为仓库根目录。Vercel 会按 `vercel.json` 构建主站及其传递依赖,并发布 `apps/website/dist`。主站源码、静态资源、API 契约源码、UBB 或相关构建配置发生变化时才会部署;测试、探测数据、生成文档和 README 等非构建输入不会触发主站部署。Vue Router 使用 history 模式,只有业务路由未命中时回退到 `index.html`;缺失静态资源、Service Worker、Manifest 和固定 PWA 文件保留真实错误响应。 用户文档使用独立的 Vercel 项目 `cc98-docs`,根目录是 `apps/docs`。只有文档内容、文档站配置、静态资源或相关依赖发生变化时才部署文档站。PR 会生成文档预览,`main` 分支发布到 `https://cc98-docs.vercel.app`。 diff --git a/apps/docs/content/guide/getting-started.md b/apps/docs/content/guide/getting-started.md index e575b15..b31c3ab 100644 --- a/apps/docs/content/guide/getting-started.md +++ b/apps/docs/content/guide/getting-started.md @@ -14,7 +14,7 @@ 支持 PWA 的浏览器可以把 CC98 安装到桌面或主屏幕。安装入口通常位于地址栏或浏览器菜单中,名称可能是“安装应用”“添加到主屏幕”或“创建快捷方式”。安装后会以独立窗口打开,账号和外观设置仍由当前浏览器管理。 -页面提示新版本已经准备好时,点击“刷新”即可切换版本。选择“稍后”不会影响当前页面,下次发现更新时还会再次提示。 +页面提示新版本已经准备好时,点击“立即更新”即可切换版本。选择“稍后”不会影响当前页面,下次发现更新时还会再次提示。如果页面显示“页面资源加载失败”,说明目标页面所需资源没有加载成功,可能是网络波动或网站刚刚更新。联网后点击“重新加载”即可重试。重新加载前,请先保存尚未提交的内容。 ## 认识顶部导航 diff --git a/apps/website/build/runtime-cache.ts b/apps/website/build/runtime-cache.ts new file mode 100644 index 0000000..b84fe03 --- /dev/null +++ b/apps/website/build/runtime-cache.ts @@ -0,0 +1,45 @@ +interface AppAssetResponseContext { + request: Request; + response: Response; +} + +function validateAppAssetResponse({ request, response }: AppAssetResponseContext): Response | null { + if (response.status !== 200) return null; + + const contentType = response.headers.get("Content-Type")?.toLowerCase() ?? ""; + const pathname = new URL(request.url).pathname.toLowerCase(); + + if (pathname.endsWith(".js")) { + return contentType.includes("javascript") || contentType.includes("ecmascript") + ? response + : null; + } + if (pathname.endsWith(".css")) { + return contentType.startsWith("text/css") ? response : null; + } + if (/\.(?:woff2?|ttf)$/.test(pathname)) { + return contentType.startsWith("font/") || + contentType.startsWith("application/font-") || + contentType.startsWith("application/x-font-") || + contentType.startsWith("application/octet-stream") + ? response + : null; + } + return null; +} + +export function createAppAssetCachePlugin() { + const cacheWillUpdate = async (context: AppAssetResponseContext): Promise => + validateAppAssetResponse(context); + + const cachedResponseWillBeUsed = async (context: { + request: Request; + cachedResponse?: Response; + }): Promise => { + const { request, cachedResponse } = context; + if (!cachedResponse) return null; + return validateAppAssetResponse({ request, response: cachedResponse }); + }; + + return { cacheWillUpdate, cachedResponseWillBeUsed }; +} diff --git a/apps/website/src/components/PwaStatusBanner.vue b/apps/website/src/components/PwaStatusBanner.vue index 31a1a70..91b052c 100644 --- a/apps/website/src/components/PwaStatusBanner.vue +++ b/apps/website/src/components/PwaStatusBanner.vue @@ -1,27 +1,90 @@