Files
cozsweet-frontend-nextjs/src/app/layout.tsx
T
admin 2acc005809 feat(pwa): wire up @ducanh2912/next-pwa + register SW in layout
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.
2026-06-16 19:36:03 +08:00

63 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Metadata, Viewport } from "next";
import { SessionProvider } from "@/providers/session-provider";
import { geistSans, geistMono, athelas } from "@/core/fonts";
import "./globals.css";
import { SwRegister } from "@/app/_components/core/sw-register";
import { RootProviders } from "@/providers/root-providers";
export const metadata: Metadata = {
title: "cozsweet",
description: "cozsweet frontend (Next.js)",
// PWA:链接到 public/manifest.json(由 @ducanh2912/next-pwa 体系使用)
manifest: "/manifest.json",
// iOS Safari "添加到主屏" 元数据
appleWebApp: {
capable: true,
statusBarStyle: "default",
title: "cozsweet",
},
// iOS 触屏图标
icons: {
icon: "/favicon.ico",
apple: "/favicon.ico",
},
};
/**
* Next.js 14+ 推荐:viewport 相关元数据独立导出。
* 之前放在 `metadata.themeColor` 会在 Next.js 16 触发 deprecation 警告。
* 详见 https://nextjs.org/docs/app/api-reference/functions/generate-viewport
*/
export const viewport: Viewport = {
// 浏览器顶栏 / Android PWA 顶栏颜色
themeColor: "#f84d96",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
// suppressHydrationWarningnext/font + Tailwind v4 偶发类名差异;详见
// `src/app/api/auth/[...nextauth]/route.ts` 的"水合闪屏"说明。
<html
lang="en"
suppressHydrationWarning
className={`${geistSans.variable} ${geistMono.variable} ${athelas.variable} h-full antialiased`}
>
<body className="min-h-full flex flex-col">
{/* NextAuth SessionProvider:为所有客户端组件提供 useSession() 上下文 */}
<SessionProvider>
<RootProviders>
{children}
{/* PWA Service Worker 注册器 —— 生产构建挂载 /sw.js@ducanh2912/next-pwa 生成) */}
<SwRegister />
</RootProviders>
</SessionProvider>
</body>
</html>
);
}