I like to build tools that don’t just work — 彼らは My team has been in the trenches of Next.js long enough to know exactly what hurts. 私がまとめた最新のものの一つは、 — あなたの Next.js アプリで完全な PWA サポートを接続するドロップイン パッケージで、髪を切らないでください。 あなたの道から抜け出せ next-pwa-pack バックストーリー(原題:Why I Wrote This Thing) クライアントが「PWAサポート」を言ったたびに、私は自分を抱きしめた。 私は既存の図書館を試してみました. 魔法が多すぎます. コンフィグのトン. または完全に互換性がありません。 というわけで、完全に受け入れられましたので、 App Router サーバーサイドキャッシュの復元 App Routerの統合 タブの間のシンクシングが簡単。 バックエンドからキャッシュを管理するためのクリーンAPI。 代わりに、私は手動でサービスワーカーを書くようになった。キャッシュTLSを調節する。更新論理を扱う。ストールクライアントを管理する。キャッシュを毎回手動で削除する。 そして、ユーザーがアップデートを重ねるまで、アップデートを見ないまで私を起動させないでください。 僕は単純で予測可能で戦闘テストされたものが必要だったので、それを作った。 建物 タグ: What Went Into It NEXTパッケージ NEXTパッケージ ステップ1は、最低限のサービスワーカーを書くことでした。 HTMLをTTLでキャッシュします。 静的資産を扱う オフラインで動作する、本物のPWAのように。 その後、クライアントがサービスワーカーと話せるようにメッセージングシステムを追加しました - たとえば、キャッシュを破ったり、キャッシュを完全に無効にしたりします。 次に、いくつかの脚本を書きました: sw.js、manifest.json、offline.html をプロジェクトに自動コピーします。 revalidatePWA と呼ばれるサーバーアクションを注入し、どこでも使用できます(API ルート、サーバーアクション、サーバーコンポーネント - 選択してください)。 App RouterとSSR/Edgeの完全なサポートのために、私はより高い順序の機能にすべてを包み込んだ: One import, one call - 完了しました。 withPWA タブ同期も構築しましたので、ユーザーは 3 タブでアプリを開いて、マジックで同期して更新することを期待します。 + より イベント ウィル localStorage storage 結果? 単に機能するパッケージ. ブラックマジックを構成しない. アプリのコア部分を書き換えることはありません。 What You Get With ♪ next-pwa-pack NEXTパッケージ 一度インストールすると、あなたは: サービス従業員の登録は箱の外で - ボイラープレートなし。 オフラインフォールバックとカスタマイズ可能なoffline.html 自動コピーされたファイルを調整できます(マニフェスト、SW、等)。 Cache control API — clear, update, disable, all programmatically. Cache control API — clear, update, disable, all programmatically. Cache control API — clear, update, disable, all programmatically. タブ間の同期 — 複数のタブ設定で固定コンテンツはありません。 現地開発中のリアルタイムPWA状態のためのDevel Panel。 Server-side revalidation support via server actions, API routes, or external webhook integrations.サーバー側の再検証をサポートします。 パッケージはこちらからご覧いただけます↓ https://github.com/dev-family/next-pwa-pack インストールしたらどうなるか インストール スクリプトは PWA boilerplate を自動コピーします。 : /public sw.js - キャッシュロジックを備えたサービスワーカー。 offline.html - オフラインモード用のファールバックページ。 manifest.json - あなたのアプリに適合するように変更します。 ⚠️既存のファイルは上書きされません - それはあなたの設定を尊重します。 手動でコピーを起動したい場合: node node_modules/next-pwa-pack/scripts/copy-pwa-files.mjs # or npx next-pwa-pack/scripts/copy-pwa-files.mjs サーバーアクション あなたにも追加されています。 または あなたのフォルダ構造に応じてファイル: revalidatePWA app/actions.ts src/app/actions.ts "use server"; export async function revalidatePWA(urls: string[]) { const baseUrl = process.env.NEXT_PUBLIC_HOST || "http://localhost:3000"; const res = await fetch(`${baseUrl}/api/pwa/revalidate`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ urls, secret: process.env.REVALIDATION_SECRET, }), }); return res.json(); } ファイルが表示されない場合は、以下を実行できます。 node node_modules/next-pwa-pack/scripts/copy-pwa-server-actions.mjs あなたの設定 manifest.json トップ > ジョン インストール後、カスタマイズすることを忘れないでください。 : /public/manifest.json { "name": "My App", "short_name": "App", "description": "My amazing PWA app", "start_url": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#000000", "icons": [ { "src": "/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icons/icon-512x512.png", "sizes": "512x512", "type": "image/png" } ] } あなたのアイコンをダウンロード トップページへ トップページへ トップページへ トップページへ トップページへ トップページへ トップページへ トップページへ public/icons/ スピードスタート:Wire It Up Wrap your layout in the 魔法が突っ込む: PWAProvider import { PWAProvider } from "next-pwa-pack"; export default function layout({ children }) { return <PWAProvider>{children}</PWAProvider>; } 再認証をサーバー側から動作させたい場合は、ミドルウェアを更新する必要があります。 // /middleware.ts import { withPWA } from "next-pwa-pack/hoc/withPWA"; function originalMiddleware(request) { // your logic here return response; } export default withPWA(originalMiddleware, { revalidationSecret: process.env.REVALIDATION_SECRET!, sseEndpoint: "/api/pwa/cache-events", webhookPath: "/api/pwa/revalidate", }); export const config = { matcher: ["/", "/(ru|en)/:path*", "/api/pwa/:path*"], }; HOCオプション: オリジナルMiddleware: your base middleware (e.g. for i18n or auth) revalidationSecret: secret token to lock down cache revalidation. シークレット・トークンは、キャッシュの再認証をロックダウンします。 sseEndpoint: SSE ストリーム パス(衝突した場合に変更) webhookPath: endpoint to hit for triggering cache refresh (used by revalidatePWA) INSIDE THE PWAProvider PWAPプロバイダー THE 帽子の下にたくさんのものをバンドル - そしてあなたは桜の部品も選ぶことができます: PWAProvider RegisterSW 従業員登録( ) エラーを優雅に処理します. 必要に応じてパスを上回ることができます: /sw.js <PWAProvider swPath="/custom/sw.js">{children}</PWAProvider> CacheCurrentPage ナビゲーション(SPAスタイルの移行を含む)をキャッシュし、現在のページの HTML をキャッシュします。 SWRevalidateListener localStorage イベントの時刻表と、タブ間のキャッシュリフレッシュを起動します。 SSERevalidateListener Listen to server-sent events from the バックエンドが「これらのURLを再認証する」と言ったとき、このオーディオはクライアントがそうすることを確認します。 sseEndpoint DevPWAStatus Dev-only パネルでは、以下のようになります。 <PWAProvider devMode>{children}</PWAProvider> ショー: オンライン/offline Cache バージョン 更新可用性 ツール: clear cache, unregister SW, refresh, disable/enable cache サービススタッフが実際にやっていること コア ハンドル: sw.js HTML キャッシュ Pages cached with TTL (default: 10 min — tweakable in sw.js) TTL が終了したときの自動再認証 Offline fallback if HTML is missing (HTMLが欠けている場合) 静的資産 JS、CSS、画像は永遠にキャッシュされます。 キャッシュのみ GET requests メッセージサポート クライアントからのこれらのアクションをサポートします: CACHE_CURRENT_HTMLについて トップ > URL DISABLE_CACHE / ENABLE_CACHE 船 - 待機 CLEAR_STATIC_CACHE オフラインモード ネットワークとキャッシュの両方が失敗した場合のoffline.htmlサービス オンラインに戻るときにリフレッシュしようとします。 利用 ミドルウェア withPWA ワンパワ ここはどこ それは、SSRとEdge Middlewareにキャッシュ再認証を提供します - SSEのサポートとすべて。 next-pwa-pack export default withPWA(originalMiddleware, { revalidationSecret: process.env.REVALIDATION_SECRET!, sseEndpoint: "/api/pwa/cache-events", webhookPath: "/api/pwa/revalidate", }); Params: オリジナルMiddleware:既存のミドルウェアの論理(auth、i18n、等) revalidationSecret: so no one else can poke your cache あなたのキャッシュを再確認する sseEndpoint: 他の何かがこのルートを使用している場合のオーバーレイド webhookPath: 特定の URL を再認証するためにサーバーまたは外部システムによって使用される。 リアルワールド使用ケース データ変更後のキャッシュの更新 import { updateSWCache } from "next-pwa-pack"; // After creating a blog post: const handleCreatePost = async (data) => { await createPost(data); updateSWCache(["/blog", "/dashboard"]); }; サーバーからのキャッシュの更新 import { revalidatePWA } from "../actions"; await createPost(data); await revalidatePWA(["/my-page"]); 「Cache on Logout」 import { clearAllCache } from "next-pwa-pack"; const handleLogout = async () => { await logout(); await clearAllCache(); router.push("/login"); }; すべてのクライアントキャッシュアクション import { clearAllCache, reloadServiceWorker, updatePageCache, unregisterServiceWorkerAndClearCache, updateSWCache, disablePWACache, enablePWACache, clearStaticCache, usePWAStatus, } from "next-pwa-pack"; // Examples: await clearAllCache(); await reloadServiceWorker(); await updatePageCache("/about"); await unregisterServiceWorkerAndClearCache(); await clearStaticCache(); updateSWCache(["/page1", "/page2"]); disablePWACache(); enablePWACache(); const { online, hasUpdate, swInstalled, update } = usePWAStatus(); API Route for External Cache Triggers(外部キャッシュトリガーのためのAPIルート) 外部からキャッシュ更新を起動したい場合は(例えば、管理パネルから)、以下に使用できる API ルートがあります。 // app/api/webhook/revalidate/route.ts import { NextRequest, NextResponse } from "next/server"; import { revalidatePWA } from "@/app/actions"; import { revalidateTag } from "next/cache"; import { FetchTags } from "@/app/api/endpoints/backend"; export async function POST(request: NextRequest) { try { const { tags, secret, urls } = await request.json(); if (secret !== process.env.REVALIDATION_SECRET) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const validTags = Object.values(FetchTags); const invalidTags = tags?.filter((tag) => !validTags.includes(tag)) || []; if (invalidTags.length > 0) { return NextResponse.json( { error: `Invalid tags: ${invalidTags.join(", ")}` }, { status: 400 } ); } let successful = 0; let failed = 0; if (tags?.length) { const tagResults = await Promise.allSettled( tags.map((tag) => revalidateTag(tag)) ); successful = tagResults.filter((r) => r.status === "fulfilled").length; failed = tagResults.filter((r) => r.status === "rejected").length; } if (urls?.length) { await revalidatePWA(urls); } return NextResponse.json({ success: true, message: "Cache revalidation completed", tags, urls, successful, failed, timestamp: new Date().toISOString(), }); } catch (error) { console.error("Webhook revalidation error:", error); return NextResponse.json({ error: "Internal server error" }, { status: 500 }); } } Hit it with: POST https://your-app.com/api/webhook/revalidate { "tags": ["faq"], "secret": "1234567890", "urls": ["/ru/question-answer"] } デバッグ & DevTools こちらは、デバッグするときにチェックできるもの: DevTools → Application → Service Workers を参照してください。 従業員が登録されていることを確認する Cache Storage → html-cache-v2 をチェックして、ページがキャッシュされているかどうかを確認します。 ネットワーク → オフラインでオフラインをシミュレートし、リロードしてください. You should see offline.html. Console logs from the service worker help too: [PWA] Service Worker registered [SW] Cached: /about [SW] Revalidated and updated cache for: /blog GOTCHAS & NOTES 船に乗る前に知っておくべきこと: セキュリティ PWA は生産に HTTPS が必要です。 GETリクエストのみがキャッシュされます。 敏感なデータを隠さないでください。 実績 パッケージは、アプリのパフォーマンスベースラインに触れません。 繰り返しの負荷を大幅に改善します。 CONFIG TTL は sw.js (デフォルト: 10 分) で設定されます。 URL を CACHE_EXCLUDE でキャッシュから除外できます。 manifest.json はあなたのアプリに適合する必要があります。 revalidatePWA アクションは編集可能で、必要に応じてカスタマイズします。 withPWA と PWAProvider は、以下のオプションを両方受け入れています。 export default function PWAProvider({ children, swPath, devMode = false, serverRevalidation = { enabled: true, sseEndpoint: "/api/pwa/cache-events" }, }: PWAProviderProps) { 次は何 書かれている for ( ) It should work on しかも、あまりテストされていません。 next-pwa-pack Next.js 15 Next.js 13 App Router 予定されている特徴: TTL configur via options (no editing sw.js) PUSH 通知 パターンベースのキャッシュコントロール キャッシュ効率のためのパフォーマンスメトリクス それがそれ。 手動でサービススタッフと喧嘩することに疲れたら、 あなたは1回のコーヒー休憩でゼロから完全なPWAサポートに移動します。 next-pwa-pack 質問、バグ、またはフィードバック? 問題を開くか、私たちにチャレンジしてください。 ↓↓ github.com/dev-family/next-pwa-pack トップページ