2acc005809
PWA install flow was wired but unusable: pwaUtil.install() calls
deferred.prompt(), but Chrome only fires beforeinstallprompt when a
valid Service Worker is registered + a manifest is linked. The project
had both intent (manifest, usePwaInstall hook) but no live SW —
public/sw.js was a stale workbox build artifact from a previous
attempt with hardcoded chunk URLs that no longer matched any build.
What this commit does:
1. Add @ducanh2912/next-pwa@10.2.9 as devDependency.
2. Wrap nextConfig with withPWA({...}):
- dest: "public" SW outputs to public/sw.js
- disable: true skip SW generation in dev (HMR-friendly)
- register: false don't auto-inject registration
- workboxOptions.skipWaiting: true + clientsClaim: true — new SW
takes over immediately
3. Add --webpack flag to dev/build/dev:proxy scripts.
@ducanh2912/next-pwa is webpack-only; Turbopack (Next 16 default)
doesn't load webpack plugins. Per user decision to accept the perf
trade-off in exchange for a working PWA.
4. Delete stale public/sw.js (workbox will regenerate it at build
time with the correct chunk URLs).
5. Add src/app/_components/core/sw-register.tsx: a no-UI client
component that registers /sw.js in production. Mounted at the end
of <body> in layout.tsx. disable: true means dev mode skips
registration (no /sw.js to fetch anyway).
After this commit + pnpm build, public/sw.js is regenerated with
correct chunk URLs, registered on first prod load, and Chrome fires
beforeinstallprompt — usePwaInstall + pwaUtil.install() then trigger
the native install prompt end-to-end.
43 lines
1.9 KiB
TypeScript
43 lines
1.9 KiB
TypeScript
import type { NextConfig } from "next";
|
||
import withPWAInit from "@ducanh2912/next-pwa";
|
||
|
||
/**
|
||
* Next.js 16 临时绕过 `/_global-error` prerender 的 workStore bug
|
||
* 标记根 layout 不参与静态预渲染(global-error 会在请求时渲染)
|
||
* https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config
|
||
*
|
||
* 默认部署模型:`.next/` + `public/` + `next start`(或 Vercel 零配置)
|
||
* - `pnpm build` 产出 .next/(含 build manifest / chunks / 路由表 / 静态预渲染)
|
||
* - 脚本侧:scripts/deploy/_deploy_lib.sh 同步 .next/ + public/
|
||
* - 服务器启动:`cd <path> && next start -H 0.0.0.0 -p 3000`
|
||
* 或用 PM2:`pm2 start "next start" --name cozsweet`
|
||
*
|
||
* PWA 集成:`@ducanh2912/next-pwa` 在 build 阶段用 workbox 生成 public/sw.js。
|
||
* - `dest: "public"` SW 输出到 public/sw.js
|
||
* - `disable: true` + dev NODE_ENV 跳过 dev —— 避免 HMR + 老 SW cache 冲突
|
||
* - `register: false` 不自动注入注册脚本 —— App Router 下走 <SwRegister /> 客户端组件更可控
|
||
* - `skipWaiting: true` 新 SW 立即接管(避免旧 SW 卡住页面)
|
||
*
|
||
* 已知 trade-off:`@ducanh2912/next-pwa` 是 webpack-only 插件,与 Turbopack 不兼容。
|
||
* scripts 中加 `--webpack` flag 取消 Turbopack。等未来 next-pwa 支持 Turbopack 时再切回。
|
||
* (Serwist 同样 webpack-only —— 见 node_modules/next/dist/docs/.../progressive-web-apps.md)
|
||
*/
|
||
const nextConfig: NextConfig = {
|
||
experimental: {
|
||
// 关闭静态优化以规避 16.2.7 global-error prerender bug
|
||
staticGenerationRetryCount: 0,
|
||
},
|
||
};
|
||
|
||
const withPWA = withPWAInit({
|
||
dest: "public",
|
||
disable: true, // 仅当 NODE_ENV === "development" 时跳过 SW 生成
|
||
register: false,
|
||
workboxOptions: {
|
||
// skipWaiting + clientsClaim 嵌在 workboxOptions(GenerateSWOptions 字段)
|
||
skipWaiting: true,
|
||
clientsClaim: true,
|
||
},
|
||
});
|
||
|
||
export default withPWA(nextConfig); |