本文记录 JavaGuide 当前的性能现状、CDN/Nginx 配置约定、已经完成的优化和后续待讨论事项。
- 电脑端卡顿不像是单纯 CDN 问题,更偏向客户端渲染、解析和执行成本高。
- 老款 Intel Mac 卡、M 系列 Mac 流畅,符合“下载不慢,但老 CPU 处理页面吃力”的特征。
- 重点问题集中在大站点客户端搜索索引、Mermaid 图表、长文页面 DOM/代码块、全站客户端组件初始化。
腾讯云 EdgeOne 已按以下思路调整:
- HTML 不缓存,避免发布后用户拿旧 HTML 引用新旧不匹配的 JS/CSS。
- hash 静态资源使用长期缓存:
/assets/*.js/assets/*.css- 建议
Cache-Control: public, max-age=31536000, immutable
- 图片资源使用较长缓存:
jpg/jpeg/png/gif/bmp/svg/webp/ico- 建议 30 天缓存。
- EdgeOne 节点缓存 TTL 已调整为遵循源站
Cache-Control。 - EdgeOne 无
Cache-Control头时已调整为不缓存。 - EdgeOne 浏览器缓存 TTL 已设置为遵循源站
Cache-Control。 - HTML 不再使用 CDN stale,发布后新访问应尽快拿到新 HTML。
已验证过的线上响应特征:
- 首页 HTML 使用不缓存策略。
/assets/app-*.js可命中 CDN,且适合一年 immutable。favicon.ico和图片类资源适合 30 天缓存。
后端 Nginx 需要和 CDN 策略保持一致:
- HTML/JSON 不长期缓存。
- hash JS/CSS 使用一年强缓存和
immutable。 - 图片 30 天缓存。
- 开启 gzip;如果环境支持,可在 CDN 层开启 Brotli。
- 静态资源不要设置会破坏 CDN 压缩、转换或缓存的头。
- 扩展名省略的 VuePress 路由,例如
/ai/、/database/mysql/,也要返回 HTML 不缓存头,不能只匹配*.html。
当前站点使用 Vite/VuePress 内容 hash 资源,发布时必须保留旧的 /assets/* 文件一段时间。
原因:
- 已打开页面的 SPA 运行时可能还引用上一版 chunk。
- CDN 或浏览器可能短时间内仍持有旧 HTML。
- 如果部署脚本先执行
rm -rf /www/wwwroot/javaguide.cn/*,旧 hash JS/CSS 会被删除;旧 HTML 或旧客户端再请求这些文件时会 404,表现为动态 import 失败、路由跳转失败或页面白屏。
推荐发布方式:
set -e
SITE_DIR="/www/wwwroot/javaguide.cn"
DIST_DIR="/github/dist"
VERIFY_FILE="/www/wwwroot/googleca8171acadbdab54.html"
mkdir -p "$SITE_DIR/assets"
# HTML、sitemap、manifest 等非 assets 文件跟随新版本删除旧文件。
rsync -av --delete \
--exclude='assets/' \
"$DIST_DIR/" "$SITE_DIR/"
# hash 资源只增量覆盖,不在每次部署时删除旧文件。
rsync -av \
"$DIST_DIR/assets/" "$SITE_DIR/assets/"
cp "$VERIFY_FILE" "$SITE_DIR/"部署后 CDN 刷新建议:
- 优先刷新 HTML、sitemap、manifest 等入口文件。
- 不建议每次都刷新整个根目录;如果必须刷新根目录,前提是源站仍保留旧 assets。
- 旧 assets 可用定时任务按 30-60 天清理,避免无限增长。
- 移除本地客户端搜索配置。
- 接入 DocSearch 配置入口:
DOCSEARCH_APP_IDDOCSEARCH_API_KEYDOCSEARCH_INDEX_NAME
- 没有 DocSearch key 时关闭搜索,避免生成本地
searchIndex.js。 - clean build 后已确认
docs/.vuepress/.temp/internal/searchIndex.js不再生成。 - Algolia 应用:
- 当前新应用 ID:
XXQ4GI90SC - 当前前端索引名:
javaguide - 当前前端 Search-Only API Key 已验证可用,掩码记录为:
3b514f...ef027b
- 当前新应用 ID:
- 官方 DocSearch Crawler 当前存在抽取不稳定问题:
- Crawler 能访问页面,但 UI 中
recordExtractor没有稳定产出 records。 - 线上连续抓取还可能受 CDN/安全策略影响,导致部分页面拿不到完整正文。
- Crawler 能访问页面,但 UI 中
- 新增兜底索引脚本:
pnpm docsearch:index- 脚本位置:
scripts/docsearch-index.mjs - 推荐从本地构建产物
dist生成索引,而不是在线抓取。 - 原因:
dist就是最终部署产物,索引内容和发布内容一致,也不会受 CDN/反爬/缓存影响。 - 推荐流程:
- 脚本位置:
pnpm docs:build
DOCSEARCH_APP_ID=XXQ4GI90SC \
DOCSEARCH_INDEX_NAME=javaguide \
DOCSEARCH_SOURCE_DIR=dist \
DOCSEARCH_ADMIN_API_KEY=你的写入索引专用 Key \
pnpm docsearch:index- 注意:
DOCSEARCH_ADMIN_API_KEY只用于本地/CI 写索引,不能提交到仓库,不能放到前端环境变量里。- 前端
DOCSEARCH_API_KEY必须使用XXQ4GI90SC应用下的 Search-Only API Key,不能继续用旧应用U3RN7F5WI0的 key。 - 前端本地/部署构建环境变量示例:
DOCSEARCH_APP_ID=XXQ4GI90SC
DOCSEARCH_INDEX_NAME=javaguide
DOCSEARCH_API_KEY=3b514f...ef027b- 上面的
DOCSEARCH_API_KEY文档中只保留掩码;实际构建时使用完整 Search-Only API Key。 - 2026-05-14 已用本地
dist成功写入javaguide索引,索引 records 约 4.7 万条。
- 普通页面不再读取
localStorage、查询 DOM、读取scrollHeight或注入样式。 - 只有命中受保护路径时才执行加锁逻辑。
- 从受保护页面切走时清理之前加过的锁样式。
- 新增懒加载 Mermaid 包装组件。
- 页面初始只展示轻量占位。
- 图表接近视口后再加载原 Mermaid 组件和
mermaid.esm.min。 - RocketMQ 页面本地烟测:
- 初始 Mermaid 占位数量为 13。
- 初始 SVG 渲染数量为 0。
- 这说明 Mermaid 不再抢占首屏初始化;滚动触发渲染仍建议在未加锁页面继续定期抽测。
LayoutToggle改为延后到浏览器空闲时加载。UnlockContent保持异步组件注册。GlobalUnlock保持同步,避免受保护内容短暂露出。
- 关闭
photoSwipe图片预览插件。 - 原因:图片点击放大不是文档阅读首屏刚需,但会额外带来初始 JS 请求。
- 如果后续仍需要图片放大能力,建议实现“点击图片后再懒加载预览库”。
- 当前轻量图片预览组件
ClickImagePreview已改为 mounted 后再渲染 Teleport。 - 原因:Teleport 作为 root component 直接参与 SSR hydration 时,会导致 VuePress 首页被水合为空注释,表现为页面白屏且只剩
Hydration completed but contains mismatches。
- 当前主题配置中已设置
print: false,Theme Hope 的 TOC 打印按钮不会渲染。 - Theme Hope 的打印按钮本身只是调用
globalThis.print(),不引入额外大依赖。 - 对比构建显示,关闭打印按钮对 gzip 后 JS 体积影响只有几十到数百字节,属于噪声级别。
- 结论:打印按钮不是当前电脑端卡顿的主要原因。
- 注意:用户主动触发浏览器打印或打印预览时,超长页面仍可能因为分页、样式计算和大 DOM 导致短暂卡顿,但这只发生在打印流程中,不影响普通阅读首屏和滚动。
- 已禁用 Theme Hope 的
plugins.copyright。 - 原因:
@vuepress/plugin-copyright当前客户端代码在挂载时会执行document.querySelector("#app").style...,没有空判断;线上部署后出现过Cannot read properties of null (reading 'style'),会导致页面白屏。 - 影响:禁用后不再自动给复制内容追加“原文链接/版权信息”;页脚 Copyright 展示不受影响。
- 验证:clean build 通过,新的
app-*.js中已不再包含querySelector("#app")、userSelect、setupCopyright相关代码。
命令:
pnpm docs:build:clean
pnpm exec prettier --check docs/.vuepress/client.ts docs/.vuepress/components/DeferredLayoutToggle.vue PERFORMANCE_NOTES.md docs/.vuepress/components/LazyMermaid.vue docs/.vuepress/theme.ts docs/.vuepress/components/unlock/GlobalUnlock.vue结果:
- VuePress clean build 通过。
- Prettier 检查通过。
searchIndex.js未生成。photoswipe.esm不再出现在构建产物和客户端配置中。app-*.jsgzip 后约 70 KB。client-*.jsgzip 后约 129 KB。- 本地烟测确认
LayoutToggle会延后出现,不参与首屏同步渲染。
构建产物中仍然较大的页面 chunk 包括:
aqs.htmljava-concurrent-questions-03.htmljava8-common-new-features.htmlrocketmq-questions.htmlshell-intro.html
这些主要是长文、代码块、表格和图表内容本身带来的页面 chunk 成本。
- 处理老机器上的长文阅读卡顿:
- 结论:CDN 主要解决下载慢,Intel Mac 等老机器卡顿更可能来自长文页面的 HTML 解析、Vue hydration、DOM 渲染、代码块和图表执行成本。
- 目标:降低
aqs.html、java-concurrent-questions-03.html、java8-common-new-features.html、rocketmq-questions.html、shell-intro.html等重页面在老电脑上的主线程压力。 - 约束:长文拆分属于内容结构调整,执行前需要单独讨论。
- 讨论超长文章是否拆页:
- 保留原 URL 还是做跳转。
- 是否按问题组、章节或主题拆分。
- 对 SEO、外链、阅读路径的影响。
- 讨论 Mermaid 是否进一步按文章治理:
- 单页 Mermaid 数量过多的文章是否改为图片或拆分。
- 高频访问文章是否做单独优化。
- 评估图片预览能力是否恢复为按点击懒加载。
- 评估是否对代码块非常多的页面做折叠、分页或局部渲染。
- 不要长期缓存 HTML,否则发布后可能出现旧 HTML 引用不存在或不匹配的新 JS/CSS。
- hash 资源可以长期缓存,前提是构建产物文件名带内容 hash。
- 长文拆分属于内容结构调整,执行前需要单独讨论。