Merge branch 'dev' into test
This commit is contained in:
+22
-7
@@ -1,4 +1,5 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
import withPWAInit from "@ducanh2912/next-pwa";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Next.js 16 临时绕过 `/_global-error` prerender 的 workStore bug
|
* Next.js 16 临时绕过 `/_global-error` prerender 的 workStore bug
|
||||||
@@ -11,12 +12,15 @@ import type { NextConfig } from "next";
|
|||||||
* - 服务器启动:`cd <path> && next start -H 0.0.0.0 -p 3000`
|
* - 服务器启动:`cd <path> && next start -H 0.0.0.0 -p 3000`
|
||||||
* 或用 PM2:`pm2 start "next start" --name cozsweet`
|
* 或用 PM2:`pm2 start "next start" --name cozsweet`
|
||||||
*
|
*
|
||||||
* 已知 trade-off:@ducanh2912/next-pwa 是 webpack-only 插件,与 Turbopack 不兼容。
|
* PWA 集成:`@ducanh2912/next-pwa` 在 build 阶段用 workbox 生成 public/sw.js。
|
||||||
* 本轮按用户指令采用"默认构建",**移除了 next-pwa 插件**(`public/manifest.json` +
|
* - `dest: "public"` SW 输出到 public/sw.js
|
||||||
* `public/favicon.ico` 仍由 Next.js metadata 加载;install prompt 仍由
|
* - `disable: true` + dev NODE_ENV 跳过 dev —— 避免 HMR + 老 SW cache 冲突
|
||||||
* `usePwaInstall` hook 监听 `beforeinstallprompt` 浏览器 API 提供)。
|
* - `register: false` 不自动注入注册脚本 —— App Router 下走 <SwRegister /> 客户端组件更可控
|
||||||
* Service Worker 暂不再自动生成;如未来需要,请改用 Next 16 原生 PWA 方案
|
* - `skipWaiting: true` 新 SW 立即接管(避免旧 SW 卡住页面)
|
||||||
* (`src/app/manifest.ts` + 手写 `public/sw.js` + client `useEffect` 注册)。
|
*
|
||||||
|
* 已知 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 = {
|
const nextConfig: NextConfig = {
|
||||||
experimental: {
|
experimental: {
|
||||||
@@ -25,4 +29,15 @@ const nextConfig: NextConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
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);
|
||||||
+4
-3
@@ -3,9 +3,9 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev --webpack",
|
||||||
"dev:proxy": "HTTPS_PROXY=http://127.0.0.1:7891 next dev",
|
"dev:proxy": "HTTPS_PROXY=http://127.0.0.1:7891 next dev --webpack",
|
||||||
"build": "next build",
|
"build": "next build --webpack",
|
||||||
"start": "next start -p 9135",
|
"start": "next start -p 9135",
|
||||||
"build:start": "npm run build && npm run start",
|
"build:start": "npm run build && npm run start",
|
||||||
"lint": "eslint",
|
"lint": "eslint",
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@ducanh2912/next-pwa": "^10.2.9",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
|
|||||||
Generated
+2267
-9
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,34 @@
|
|||||||
|
"use client";
|
||||||
|
/**
|
||||||
|
* Service Worker 注册器
|
||||||
|
*
|
||||||
|
* 背景:`@ducanh2912/next-pwa` 配置 `register: false`,不自动注入注册脚本。
|
||||||
|
* App Router 下手动注册更可控 —— 不污染 SSR / hydration,可显式做生产 / 开发分流。
|
||||||
|
*
|
||||||
|
* 挂载位置:layout body 末尾,全站生效。
|
||||||
|
*
|
||||||
|
* 行为:
|
||||||
|
* - dev (`NODE_ENV === "development"`):跳过注册
|
||||||
|
* 1. next-pwa `disable: true` 时 dev 不生成 sw.js,注册会 404
|
||||||
|
* 2. dev HMR + 老 SW cache 互相干扰,开发体验差
|
||||||
|
* - 生产:调 `navigator.serviceWorker.register("/sw.js", { scope: "/" })`
|
||||||
|
* - `scope: "/"` 与 manifest.scope 一致
|
||||||
|
* - `updateViaCache: "none"` 强制每次都拉新版 SW(next-pwa 默认就是这行为,显式更清晰)
|
||||||
|
*/
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
export function SwRegister() {
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window === "undefined") return;
|
||||||
|
if (!("serviceWorker" in navigator)) return;
|
||||||
|
if (process.env.NODE_ENV !== "production") return;
|
||||||
|
|
||||||
|
void navigator.serviceWorker.register("/sw.js", {
|
||||||
|
scope: "/",
|
||||||
|
updateViaCache: "none",
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 无 UI —— 纯副作用组件
|
||||||
|
return null;
|
||||||
|
}
|
||||||
+6
-1
@@ -3,6 +3,7 @@ import { SessionProvider } from "@/providers/session-provider";
|
|||||||
import { geistSans, geistMono, athelas } from "@/core/fonts";
|
import { geistSans, geistMono, athelas } from "@/core/fonts";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
|
||||||
|
import { SwRegister } from "@/app/_components/core/sw-register";
|
||||||
import { RootProviders } from "@/providers/root-providers";
|
import { RootProviders } from "@/providers/root-providers";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
@@ -49,7 +50,11 @@ export default function RootLayout({
|
|||||||
<body className="min-h-full flex flex-col">
|
<body className="min-h-full flex flex-col">
|
||||||
{/* NextAuth SessionProvider:为所有客户端组件提供 useSession() 上下文 */}
|
{/* NextAuth SessionProvider:为所有客户端组件提供 useSession() 上下文 */}
|
||||||
<SessionProvider>
|
<SessionProvider>
|
||||||
<RootProviders>{children}</RootProviders>
|
<RootProviders>
|
||||||
|
{children}
|
||||||
|
{/* PWA Service Worker 注册器 —— 生产构建挂载 /sw.js(@ducanh2912/next-pwa 生成) */}
|
||||||
|
<SwRegister />
|
||||||
|
</RootProviders>
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
* 不引入 Facebook SDK(window.FB)—— 减少前端 bundle 体积,Graph API
|
* 不引入 Facebook SDK(window.FB)—— 减少前端 bundle 体积,Graph API
|
||||||
* 单次 HTTP 调用即可拿到所有字段。SDK 加载慢、还要管 init。
|
* 单次 HTTP 调用即可拿到所有字段。SDK 加载慢、还要管 init。
|
||||||
*
|
*
|
||||||
* 端点:`https://graph.facebook.com/me?fields=id,name,email,picture.type=large&access_token=...`
|
* 端点:`https://graph.facebook.com/me?fields=id,name,email,picture.type(large)&access_token=...`
|
||||||
* - `picture.type=large` 返回 ~200px 头像 URL(默认 square 50px 太小)
|
* - `picture.type(large)` 返回 ~200px 头像 URL(默认 square 50px 太小)
|
||||||
* - 不指定 version 走最新稳定版
|
* - 不指定 version 走最新稳定版
|
||||||
* - 不需要 appId / appSecret(accessToken 自身就是凭证)
|
* - 不需要 appId / appSecret(accessToken 自身就是凭证)
|
||||||
*/
|
*/
|
||||||
@@ -31,9 +31,9 @@ const GRAPH_ME_URL = "https://graph.facebook.com/me";
|
|||||||
/**
|
/**
|
||||||
* 拉取字段集合:
|
* 拉取字段集合:
|
||||||
* - id / name / email —— 给本地 FacebookUserData DTO
|
* - id / name / email —— 给本地 FacebookUserData DTO
|
||||||
* - picture.type=large —— 头像 URL(默认 square 50px 太小)
|
* - picture.type(large) —— 头像 URL(默认 square 50px 太小)
|
||||||
*/
|
*/
|
||||||
const FIELDS = "id,name,email,picture.type=large";
|
const FIELDS = "id,name,email,picture.type(large)";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用 accessToken 调 Facebook Graph `/me` 拉用户资料。
|
* 用 accessToken 调 Facebook Graph `/me` 拉用户资料。
|
||||||
|
|||||||
Reference in New Issue
Block a user