この記事の要点
この記事の重要ポイント
网站上的“安装应用”横幅,就像现在的新闻订阅弹窗一样。它确实方便,但太常在无视用户上下文的时刻出现。
这次更新聚焦于两个核心问题:博客的 运行时稳定性 (修复Three.js崩溃)与 用户体验 (重塑PWA流程)。
1. “先参与后安装”的PWA策略
浏览器原生提供“安装应用”功能,但有明显缺点:它往往在页面刚加载时触发,打断了用户,甚至在用户读第一句话之前就出现。
默认提示的问题
从搜索结果进入博客的用户,目的在于阅读而不是安装。这种弹窗式打断只会提高跳出率与认知负担。
解决方案:延时介入
我实现了 被动(受动)安装UI 。规则很简单: “只向真正感兴趣的用户提出建议。”
生命周期可视化
下面是决定是否显示提示的逻辑:
sequenceDiagram
participant User
participant Browser
participant PWA as PWA Component
User->>Browser: 打开博客文章
Browser->>PWA: 触发 "beforeinstallprompt"
PWA->>Browser: Prevent Default(阻止横幅)
PWA->>PWA: 启动30秒计时器 ⏳
rect rgb(30, 30, 30)
note right of User: 正在阅读文章...
end
alt 30秒内离开
PWA */}>User: 不做任何事(尊重专注)
else 停留超过30秒
PWA->>User: 显示“安装应用”吐司 📱
User->>PWA: 点击安装
PWA->>Browser: prompt()
end
页面加载完成,用户开始阅读。
浏览器触发 `beforeinstallprompt`。通过 `preventDefault()` 阻止原生横幅。
启动30秒计时器,期间用户离开则不做任何事。
若仍在阅读,则在右下角显示克制的吐司提示。
实现细节
在 PWAInstallToast.astro 组件中控制事件。
// 保留事件以便稍后触发
window.addEventListener("beforeinstallprompt", (e) => {
e.preventDefault();
deferredPrompt = e;
// 若最近没有关闭记录...
if (!sessionStorage.getItem("pwa-install-dismissed")) {
// 仅对高参与用户延迟提示(30秒)
setTimeout(showToast, 30000);
}
}); 这一小改动让关系从“请安装!”变成了“你喜欢的话,也有应用版哦”。
2. 解决 “Module Not Defined” 崩溃
更新过程中,我遇到了一个会导致构建崩溃的严重错误。
ReferenceError: module is not defined
at .../node_modules/three/build/three.module.js 原因:手动别名的副作用
我曾在 astro.config.mjs 里手动添加别名,试图“优化”依赖:
// 错误配置示例
resolve: {
alias: {
"react": "path/to/react", // <--- 这就是崩溃原因
"three": "path/to/three" }
}
这会强制Vite将 react 与 three 解析到固定路径,导致 @react-three/fiber(依赖特定版本)期待的路径冲突。
graph TD
subgraph "修复前(崩溃)"
A[Astro/Vite] */}|别名| B[React (v18.x 于 /path/A)]
A */}|Node 解析| C[React (v18.x 于 /path/B)]
D[@react-three/fiber] */} C
style C fill:#f96,stroke:#333,stroke-width:2px,color:#fff
style B fill:#f96,stroke:#333,stroke-width:2px,color:#fff
end
subgraph "修复后(生效)"
X[Astro/Vite] */}|去重| Y[React(单实例)]
Z[@react-three/fiber] */} Y
style Y fill:#9f9,stroke:#333,stroke-width:2px,color:#000
end
结果就是 多个React实例 被加载,或者在ESM环境中 module 引用被破坏。
解决方案:相信 dedupe
真正的解决方案比“优化”更简单:删除手动别名,交给Vite的 dedupe 设置,从而确保只打包一个库。
vite: {
resolve: {
// 手动别名完全删除!
dedupe: ["react", "react-dom", "three"]
},
optimizeDeps: {
exclude: ["amazon-paapi", "sharp"],
include: ["@react-three/fiber", "@react-three/drei"]
}
} 应用后,pnpm build 立刻以 Exit Code 0 成功。
3. 清理开发时的无关警告
另一个麻烦是开发时Pagefind搜索引擎不断抛出404错误。Pagefind是构建后运行的静态搜索工具,因此在dev模式下没有 pagefind.js。
于是,我更新了 SearchDialog.astro,在开发模式下显式跳过加载。
// SearchDialog.astro
if (!pagefind) {
// 开发中跳过Pagefind加载,避免404
if (import.meta.env.DEV) {
return;
}
// 尝试导入...
}
结论
稳定性与UX往往不是取决于你添加了什么,而是 删除了什么 (手动别名、即时弹窗)。这些修复让HonoGear更稳定,也更尊重用户注意力。
[!TIP] 教训 :在React/Vite/Astro混合栈里遇到奇怪的“ReferenceError”或“Module not found”,先检查
astro.config.mjs。十之八九是解析冲突导致的。
接下来我会把重点放在内容扩充与新的“智能搜索”功能增强上。






⚠️ コメントのルール
※違反コメントはAIおよび管理者により予告なく削除されます
まだコメントがありません。最初のコメントを投稿しましょう!