Files
chatroom/.hermes/plans/chatroom-frontend-optimization.md
T

8.0 KiB
Raw Blame History

🚀 聊天室项目 — 前端加载优化详细方案

项目路径: /Users/pllx/Web/Herd/chatroom 当前构建输出: public/build/ 核心问题: chat.js 单文件 308KB,所有功能模块一次性加载


一、现状分析

当前构建产物

文件 大小 说明
chat-*.js 257 KB 优化后(原 308KB,↓17%,含新增留言/反馈弹窗)
vendor-*.js 108 KB Echo/Pusher/Alpine/Axios 独立分包
app-*.js (后台) 24 KB 合理
其他入口 1.5~5.6 KB 正常
CSS 532行 轻量

二、优化方案

方案 A:游戏模块动态导入(已完成)

目标: 将 5 个主要游戏的 UI 面板改为按需加载(用户点击时才下载对应代码)。

涉及的模块

游戏 文件 说明
🎰 五子棋 gomoku-panel.js 桌面端静态导入(x-data 需要),移动端按需
🏇 赛马 horse-race-panel.js 同上
🃏 百家乐 baccarat-panel.js 同上
🎣 钓鱼 fishing.js 改为静态导入(事件委托需要)
🔫 老虎机 slot-machine.js 静态导入(x-data 需要)
🎲 彩票 lottery-panel.js 静态导入(x-data 需要)
🔮 占卜 fortune-panel.js 静态导入(x-data 需要)

实际结果: 游戏 Alpine 组件因 x-data 需要同步工厂函数,无法完全懒加载。但 Vendor 分包实现了依赖缓存。


方案 B:游戏事件监听延迟注册(已完成)

问题: 游戏的 WebSocket 事件监听(赛马进度、百家乐开局等)在 chat.js 启动时全部注册。

方案: 同样采用延迟注册——只在对应游戏被首次打开后才激活事件监听。

实际结果: baccarat-events.jshorse-race-events.js 已改为静态导入(事件委托需要)。baccarat/horse 的 Echo 原始监听保留在 chat.js 中(转发 CustomEvent),实际业务逻辑在各自模块中。


方案 C:重型功能模块懒加载(已完成)

目标: 以下模块仅在用户点击对应按钮时加载。

模块 文件 状态
🛒 商店 shop-controls.js 按需加载(工具栏触发)
💒 婚姻 marriage-modals.js 静态导入(x-data 需要)
👤 用户名片 user-card.js 静态导入(x-data 需要)
🏦 银行 bank-modal.js 按需加载(工具栏触发)
👑 VIP vip-controls.js 按需加载(工具栏触发)
🧧 红包 red-packet-panel.js 静态导入(事件委托需要)
⚙️ 个人设置 profile-controls.js 按需加载(工具栏触发)

实际结果: 模块分为三类:

  • 工具栏触发(8个): 按需加载
  • Alpine x-data 组件(13个): 静态导入(无法懒加载)
  • 事件委托(22个): 静态导入(无法懒加载)

方案 D:Vite 构建优化(已完成)

当前 vite.config.js 已添加以下优化:

build: {
    rollupOptions: {
        output: {
            manualChunks(id) {
                if (id.includes('node_modules')) {
                    return 'vendor';
                }
            },
        },
    },
    minify: 'esbuild',
    cssCodeSplit: true,
    sourcemap: false,
},

方案 E:图片优化(已完成)

优化 说明 状态
聊天图片懒加载 消息中的图片使用 loading="lazy" message-renderer.js 已添加
背景图转 WebP 将 PNG 背景图转为 WebP ⏭️ 图片已很小(87KB),跳过
图片预压缩 上传头像时生成多尺寸缩略图 ⏭️ 收益较低,暂不实施
// 在 message-renderer.js 中的图片渲染部分
// 已改为:
<img src="${thumbUrl}" alt="${imageName}" loading="lazy" decoding="async">

🔲 方案 FCSS 优化(待评估)

当前 CSS 很小(532行),优化收益有限:

// chat-decorations.css384行)中检查是否有未使用的样式
// 建议:将 chat.css 也通过 Vite 导入,而非放在 public/css/ 中

评估: CSS 体积小(532行),且已通过 Vite 导入压缩。优化收益极低,暂不实施。


🔲 方案 G:WebSocket 连接延迟(部分完成)

当前: chat.js 在页面加载时立即建立 WebSocket Presence Channel 连接。 优化: 核心消息通道保持立即连接,但游戏专属事件监听(如赛马进度)延迟注册。

实际结果:

  • 核心 Echo 监听(消息、在线、退出、禁言等)保持立即连接
  • baccarat/horse Echo 监听保留在 chat.js,但转发为 CustomEvent,由各自模块处理
  • ⏭️ 游戏 Echo 监听完全移至模块层需要更深入重构,暂缓
// chat.js → initChat() 中
// 保持核心监听(消息、在线、退出、禁言等)
// 游戏事件通过 CustomEvent 转发 → 各模块自己的 init 中处理

三、实施总结

第一阶段(核心 · 代码分割)— 已完成

# 任务 状态 实际结果
1 游戏模块动态导入 Alpine 组件静态导入,其余按需
2 游戏事件延迟注册 Echo 转发 + 模块内处理
3 商店/银行/婚姻懒加载 工具栏触发的 8 个模块按需加载
4 用户名片动态导入 静态导入(x-data 需要)
5 Vite vendor 分包 vendor 108KB 独立分包

第二阶段(优化 · 增强)— 已完成

# 任务 状态 说明
6 聊天图片 loading="lazy" message-renderer.js 已添加
7 背景图转 WebP ⏭️ 图片已很小,跳过
8 关闭 sourcemap vite.config.js 已配置
9 测试动态导入路径 所有功能正常可用

新增功能(计划外)

功能 说明
✉️ 留言板弹窗 工具栏留言按钮 → 弹窗,不跳转页面
💬 反馈弹窗 工具栏反馈按钮 → 弹窗,不跳转页面
🖼️ 头像遮罩关闭 头像选择弹窗点击外部关闭

四、验证方法

# 1. 查看构建产物大小
ls -lh public/build/assets/chat-*.js

# 2. 检查分包情况
cat public/build/manifest.json | python3 -m json.tool

# 3. 浏览器 DevTools 验证
# - Network 面板:确认 vendor chunk 独立缓存
# - Coverage 面板:首屏 JS 使用率

最终构建产物:

文件 大小 加载时机
chat-*.js 257 KB 📌 页面加载
vendor-*.js 108 KB 📌 页面加载(Echo/Pusher/Alpine
shop-controls-*.js ~13 KB 🔘 点击商店
bank-modal-*.js ~8 KB 🔘 点击银行
vip-controls-*.js ~10 KB 🔘 点击会员
game-hall-*.js ~12 KB 🔘 点击娱乐
profile-controls-*.js ~10 KB 🔘 点击头像/设置
marriage-status-*.js ~12 KB 🔘 点击婚姻
friend-panel-*.js ~6 KB 🔘 点击好友
compact-shop-panel-*.js ~7 KB 🔘 点击商店(旧版)
首次加载合计 ~365 KB 含新增弹窗功能

五、注意事项

  1. 渐进式实施: 先改游戏模块,再改其他。
  2. ⏭️ 加载状态反馈: 按需加载模块较小,未添加 spinner。
  3. WebSocket 事件时序: 核心监听保持立即连接,游戏事件通过 CustomEvent 转发。
  4. 错误边界: 模块加载失败有 catch 处理。
  5. 缓存策略: Vite 自动处理 content hash 缓存失效。

最终成果:

  • chat.js 从 308KB → 257KB(↓17%,含新增留言/反馈弹窗功能代码)
  • vendor 独立分包 108KB(可缓存)
  • 8 个模块保持按需加载
  • 留言/反馈改为弹窗,用户体验提升