化實戰(zhàn))
簡介本資源是一份面向前端開發(fā)者與Next.js初學者的高質量開源項目學習合集聚焦服務器端渲染SSR、靜態(tài)站點生成SSG、API路由、TypeScript集成、SEO優(yōu)化及性能調優(yōu)等核心實踐場景有效解決React應用在生產(chǎn)環(huán)境部署、首屏性能與搜索引擎可見性方面的典型痛點。壓縮包共90個文件以78份Markdown文檔為主涵蓋框架原理詳解、最佳實踐指南、社區(qū)精選項目說明awesome-nextjs-main及結構化學習筆記輔以3個TypeScript配置/示例文件、2個文本說明文檔含使用指引與附贈資源概覽、2個JSON配置文件及少量圖片與元數(shù)據(jù)文件整體體積僅577KB輕量易用。已有66人下載學習資源結構清晰、即取即用——讀者可快速掌握Next.js目錄約定、pages與app目錄差異、getServerSideProps與generateStaticParams用法、自定義App/Document配置、圖片優(yōu)化與元標簽管理等關鍵能力并獲得可直接參考的工程化組織范式與社區(qū)權威資源索引。 最近正好在做一輪前端技術盤點把散落在 GitHub 各處的 Next.js 優(yōu)秀項目重新過了一遍順手整理成了一個壓縮包里面涵蓋了從框架基礎、React 應用范式、服務端渲染、靜態(tài)站點生成、API 路由、TypeScript 集成到性能優(yōu)化、SEO 友好、開發(fā)工具鏈的完整示例集合。今天就把這份集合的設計思路、核心項目拆解、踩過的坑和篩選標準完整寫出來希望能給正在學習 Next.js 或者準備在公司項目里落地 Next.js 的同學一份可復制的參考資料。這份集合適合誰一類是剛接觸 React 生態(tài)、想直接從全棧框架切入的新人一類是在用 Vite 或 CRA 做 SPA、想遷移到 SSR/SSG 場景的團隊還有一類是已經(jīng)在用 Next.js、但想看看別人在性能優(yōu)化、SEO、類型安全上是怎么處理的進階開發(fā)者。無論你屬于哪一類這份集合里的項目模板、配置文件和踩坑記錄都能幫你少走很多彎路。1. 項目集合的整體設計與選型思路1.1 為什么這個集合以 Next.js 為核心在做整理之前我也認真糾結過一個問題現(xiàn)在 React 生態(tài)里能搭起一個完整應用的方案太多了Vite React Router、Remix、Astro、Next.js為什么最后選了 Next.js 作為整個集合的主軸核心原因有三個。第一個是全棧能力閉環(huán)。一個 Web 應用從數(shù)據(jù)獲取、頁面渲染、路由管理到接口暴露Next.js 一套框架全包了。你在同一個項目里既能寫頁面組件又能寫服務端 API還能做中間件做權限校驗不需要為了 SSR 單獨拉一個 Node 服務也不需要為了 API 單獨搭一個 BFF 層。對于中小團隊而言這種“一個倉庫搞定前后端”的模式部署成本和維護成本是最低的。第二個是渲染策略的靈活性。Next.js 支持服務端渲染SSR、靜態(tài)站點生成SSG、增量靜態(tài)再生ISR、客戶端渲染CSR四種模式混用。也就是說你可以在同一個應用里把高時效性的頁面做成 SSR把幾乎不變的內容做成 SSG把用戶強交互的后臺做成純 CSR。這種按頁面粒度靈活切換的能力是很多框架給不了的。第三個是生態(tài)和招聘市場的雙重背書。React 面試題里 Next.js 出現(xiàn)的頻率越來越高團隊招人時對 Next.js 的期望也在提升。這個集合里的項目雖然全部圍繞 Next.js但又刻意覆蓋了 TypeScript 集成、React Hooks、React Router 對比、基礎組件封裝等內容本質上就是一套完整的 React 全棧學習路徑。1.2 集合目錄結構與模塊劃分整個集合我按功能拆成了四大模塊目錄結構大概長這樣nextjs-starter-collection/ ├── 01-blog-ssg/ # 博客場景SSG SEO 最佳實踐 ├── 02-ecommerce-ssr/ # 電商場景SSR API Routes 購物車 ├── 03-admin-dashboard/ # 后臺管理CSR 狀態(tài)管理 權限 ├── 04-ai-chat-app/ # AI 應用Route Handlers 流式響應 ├── 05-common-components/ # 通用組件省市聯(lián)動 / 表格 / 表單 ├── shared/ │ ├── config/ # 統(tǒng)一 TypeScript / ESLint / Prettier 配置 │ ├── hooks/ # 自定義 Hooks 集合 │ └── utils/ # 通用工具函數(shù) └── docs/ ├── performance-checklist.md └── seo-checklist.md這樣做的好處是每個模塊之間依賴解耦你不需要把整個倉庫跑起來才能看某一個項目。比如只對 SSG 感興趣直接進入01-blog-ssg就能獨立運行只想看通用組件直接看05-common-components就行。1.3 選型時繞不開的 App Router 與 Pages Router 之爭整理集合的過程中我必須在 App Router 和 Pages Router 之間做個決定。最終集合里的項目全部基于 App Router但這不意味著 Pages Router 沒有價值。Pages Router 的模型更簡單文件即頁面getServerSideProps/getStaticProps是獨立的、學習曲線平緩的 API。而 App Router 引入了 Server Components 的概念組件默認在服務端執(zhí)行只有明確標注use client的組件才會在客戶端運行。這套模型剛開始確實有點反直覺我見過不少同事第一天用 App Router 時在服務端組件里寫useEffect或者onClick然后收到一屏幕報錯。但為什么我還是選擇了 App Router因為它代表了 Next.js 未來的方向React 官方也在持續(xù)往 Server Components 方向推進。尤其在做性能優(yōu)化時Server Components 能讓你把數(shù)據(jù)請求直接寫在服務端組件里減少客戶端 JavaScript 體積和請求往返這種收益是 Pages Router 很難實現(xiàn)的。如果你還在用 Pages Router也不用焦慮先跑通現(xiàn)有項目等有重構窗口再遷移不急。2. 核心能力拆解SSR、SSG 與動態(tài)渲染策略2.1 用生活類比講透 SSR 與 SSG 的本質區(qū)別很多新手搞不清楚服務端渲染和靜態(tài)站點生成到底差在哪。我常用一個吃飯的例子類比客戶端渲染CSR像是給你一份菜譜和一堆食材你自己回家洗菜、切菜、炒菜瀏覽器拿到的是空 HTML然后 JavaScript 運行起來后才把內容填充進去。優(yōu)點是靈活缺點是首屏慢搜索引擎抓取時經(jīng)常什么都看不到。服務端渲染SSR像是你在餐廳點菜后廚現(xiàn)場給你炒好端上來。每次請求來臨時服務端實時執(zhí)行數(shù)據(jù)獲取、模板渲染輸出完整 HTML。優(yōu)點是首屏有真實內容缺點是每次請求都要服務端跑一遍壓力大、響應時間受上游接口影響。靜態(tài)站點生成SSG像是餐廳提前把菜做好、裝盤放在保溫柜里客人一來直接端走。構建時把頁面渲染成靜態(tài) HTML部署到 CDN 上訪問時幾乎零成本。缺點是沒辦法反映實時數(shù)據(jù)。Next.js 的聰明之處在于不逼你二選一而是支持混用。這也是我在集合的01-blog-ssg和02-ecommerce-ssr兩個項目里刻意展示的對比場景。2.2 App Router 下 SSG 的完整配置示例在 App Router 里做 SSG 其實非常簡單關鍵點是generateStaticParams配合構建時的預渲染。我以博客項目為例// app/blog/[slug]/page.tsx import { getPostBySlug, getAllPostSlugs } from /lib/posts; export async function generateStaticParams() { const posts await getAllPostSlugs(); return posts.map((post) ({ slug: post.slug, })); } export const dynamicParams false; export default async function BlogPostPage({ params, }: { params: { slug: string }; }) { const post await getPostBySlug(params.slug); return ( article h1{post.title}/h1 div dangerouslySetInnerHTML{{ __html: post.contentHtml }} / /article ); }這里有兩個容易被忽略的細節(jié)。第一個是dynamicParams false它告訴 Next.js凡是在generateStaticParams里沒有聲明過的路徑直接返回 404。如果項目里只有 100 篇文章構建時就會生成 100 個靜態(tài)頁面外界無論如何都訪問不到第 101 篇。第二個是數(shù)據(jù)獲取函數(shù)放在組件內部直接await這是 Server Components 的用法不需要額外封裝getStaticProps代碼更干凈。2.3 SSR 與 ISR 的靈活切換如果頁面數(shù)據(jù)更新頻率高于構建頻率純 SSG 就不合適了。電商項目里商品價格、庫存是常變的我在這類頁面用了 ISR也就是增量靜態(tài)再生// app/products/[id]/page.tsx export const revalidate 60; export default async function ProductPage({ params, }: { params: { id: string }; }) { const product await fetchProduct(params.id); return ProductDetail product{product} /; }只需要導出一個revalidate常量Next.js 就會在每 60 秒內復用靜態(tài)頁面超過 60 秒后第一次請求觸發(fā)重新渲染并生成新的靜態(tài)緩存。這種方案比純 SSR 省下大量服務端計算壓力又比純 SSG 保證了數(shù)據(jù)新鮮度適合大多數(shù)內容型、商品型站點。2.4 實測結論三種渲染策略的性能對比我在這份集合的文檔里記錄了同一臺 4 核 8G 服務器上的壓測結果渲染方式首屏 HTML 生成耗時1000 并發(fā)下 P95 響應時間適合場景CSR純前端耗時服務端壓力極小860ms后臺管理、強交互應用SSR80-200ms2.4s高實時性、個性化頁面SSG/ISR構建時生成運行時近 0ms120ms博客、文檔站、營銷頁結果非常明顯能用 SSG/ISR 解決的場景盡量不要用 SSR。這也是面試中經(jīng)常被問到的“你會怎么設計一個高并發(fā)頁面”的標準答案方向。3. API 路由與全棧能力落地3.1 Route Handlers 的基本寫法與進階應用Next.js 的 API 能力在 App Router 里叫 Route Handlers寫法是在app/api目錄下創(chuàng)建route.ts文件。集合里的 AI 聊天項目用到了一個比較典型的流式響應示例// app/api/chat/route.ts import { NextRequest, NextResponse } from next/server; export async function POST(request: NextRequest) { const { prompt } await request.json(); const stream await fetchAIStream(prompt); return new NextResponse(stream, { headers: { Content-Type: text/event-stream, Cache-Control: no-cache, no-transform, }, }); }這里我想多說一句流式響應的價值。傳統(tǒng)接口是等 AI 完整生成答案后一次性返回用戶可能要等十幾秒才看到第一個字。用text/event-stream做流式響應后用戶可以像使用 ChatGPT 一樣一個字一個字地看到生成過程體感上快很多。如果你在做 AI 應用這個模式幾乎是必選方案。3.2 什么時候用 Route Handlers什么時候用 Server ActionsNext.js 14 之后引入了 Server Actions很多人開始糾結寫接口到底用 Route Handlers 還是 Server Actions我的判斷標準很簡單如果表單提交后的邏輯是直接操作服務端數(shù)據(jù)且不需要外部調用優(yōu)先用 Server Actions如果這個接口要暴露給第三方、移動端或者多個前端復用就用 Route Handlers。Server Actions 的寫法在開發(fā)效率上很有優(yōu)勢// app/actions/user.ts use server; export async function updateUserName(formData: FormData) { const name formData.get(name); await db.user.update({ where: { id: 1 }, data: { name } }); }然后前端組件里直接import { updateUserName } from /app/actions/user以action{updateUserName}的方式綁定到表單上即可不需要手寫 fetch、手動管理請求狀態(tài)代碼量降了一大截。但 Server Actions 的缺點是外部無法直接調用它更多是應用內部的事件處理機制而不是通用 API。3.3 中間件的正確使用姿勢中間件是 Next.js 全棧能力里很容易被低估的部分。它運行在 Edge 環(huán)境適合做輕量的請求攔截比如登錄態(tài)校驗、地域重定向、A/B 測試。我在后臺管理項目里加了一個示例// middleware.ts import { NextResponse } from next/server; import type { NextRequest } from next/server; export function middleware(request: NextRequest) { const token request.cookies.get(token)?.value; const isLoginPage request.nextUrl.pathname.startsWith(/login); if (!token !isLoginPage) { const loginUrl new URL(/login, request.url); return NextResponse.redirect(loginUrl); } return NextResponse.next(); } export const config { matcher: [/dashboard/:path*], };注意中間件里不要做數(shù)據(jù)庫查詢這類重操作它跑在邊緣節(jié)點上環(huán)境是受限的只適合做校驗和轉發(fā)。具體的用戶信息查詢應該放在服務端組件或 Route Handlers 里。3.4 API 錯誤處理與類型安全寫 Route Handlers 時最容易被忽略的是錯誤處理。默認情況下如果服務端代碼拋異常Next.js 會返回一個 500但響應體不是 JSON 格式前端直接res.json()會報錯。我習慣在集合里統(tǒng)一封裝一個錯誤處理函數(shù)// shared/utils/api-error.ts import { NextResponse } from next/server; export function apiError(message: string, status: number 400) { return NextResponse.json( { error: message }, { status } ); }然后每個 Route Handler 里再用 try-catch 包住業(yè)務邏輯錯誤分支統(tǒng)一走apiError。這樣前端拿到的一定是結構化的{ error: string }處理起來非常統(tǒng)一。這個做法雖然簡單但在團隊協(xié)作中能省下不少聯(lián)調時間。4. TypeScript 集成與工程化配置細節(jié)4.1 集合里為什么強制使用 TypeScript我見過太多 React 項目JavaScript 階段跑得好好的一上 TypeScript 就各種報錯然后團隊又退回 JS。問題不在 TypeScript 本身而在“半吊子”使用方式——只在文件名上加了.tsx類型全部用any兜底最后 TypeScript 成了裝飾品。這份集合里的所有項目都是完整的 TypeScript 工程我并不是為了趕時髦而是因為 Next.js 對 TypeScript 的支持已經(jīng)非常成熟。尤其 App Router 模式下組件的 props、API 的入?yún)⒊鰠ⅰh(huán)境變量都可以做到全鏈路類型推導。舉個例子頁面組件里params、searchParams的類型都是框架自動推導的類型安全能幫你在編譯期攔截大量低級錯誤而不是等到運行時才發(fā)現(xiàn)字段拼錯了。4.2 tsconfig.json 關鍵配置與 paths 別名Next.js 創(chuàng)建項目時會自動生成一份tsconfig.json但默認配置比較保守。我在共享配置里做了幾個調整{ compilerOptions: { target: ES2022, lib: [dom, dom.iterable, esnext], allowJs: false, skipLibCheck: true, strict: true, noEmit: true, esModuleInterop: true, module: esnext, moduleResolution: bundler, resolveJsonModule: true, isolatedModules: true, jsx: preserve, incremental: true, plugins: [{ name: next }], paths: { /*: [./*] } }, include: [next-env.d.ts, **/*.ts, **/*.tsx, .next/types/**/*.ts], exclude: [node_modules] }這里要特別提醒一點baseUrl不要再單獨設置了。TypeScript 官方已經(jīng)明確baseUrl選項在 TypeScript 7.0 中會被移除推薦直接用paths配合相對路徑來解析模塊。早期很多教程會讓你寫baseUrl: .然后paths里寫/*: [*]這在舊版沒問題但新項目完全沒必要。我的配置里直接用/*: [./*]就能實現(xiàn)/components/xxx的絕對路徑導入干凈又面向未來。4.3 環(huán)境變量的類型安全實踐Next.js 的環(huán)境變量默認是字符串類型而且只有在變量名以NEXT_PUBLIC_開頭時才會暴露給瀏覽器端。我習慣在共享配置里加一個類型聲明文件// env.d.ts declare namespace NodeJS { interface ProcessEnv { DATABASE_URL: string; REDIS_URL: string; NEXT_PUBLIC_API_BASE_URL: string; JWT_SECRET: string; } }這樣你在代碼里寫process.env.DATABASE_URL時編輯器會自動補全和類型檢查少了哪個環(huán)境變量編譯期就能發(fā)現(xiàn)不用等到部署上線后接口報錯才開始排查。這個習慣很值得在團隊里推廣。4.4 TypeScript 與 React 面試高頻考點的關系整理這份集合時我也留意到很多 React 面試題都在問 Hooks 和生命周期相關的問題比如 class 組件的componentDidMount和函數(shù)組件的useEffect有什么區(qū)別。這類問題的答案在集合的代碼里體現(xiàn)得很明顯Server Components 里根本不能用生命周期因為服務端不跑useEffect客戶端組件的useEffect替代了componentDidMount和componentDidUpdate的組合。理解了這一層你對 Next.js 的 App Router 才算真正入門。另外React 的生命周期和 Vue 的生命周期差異也是面試中常見的問題。兩者的核心差異在于心智模型Vue 生命周期更強調“組件從創(chuàng)建到銷毀的各個階段”React 函數(shù)組件更強調“渲染結果與狀態(tài)的同步關系”。在 Next.js 里Server Components 又進一步模糊了生命周期的概念因為很多數(shù)據(jù)獲取直接從組件內部異步執(zhí)行你根本不需要關心在哪個生命周期階段去請求。5. 性能優(yōu)化與 SEO 友好實踐5.1 性能優(yōu)化三板斧圖片、代碼分割、緩存集合里的每個項目都跑過了 Lighthouse 性能檢測核心指標都在 90 分以上。我總結了三個最有效的優(yōu)化手段。第一是圖片優(yōu)化。用next/image組件替代原生img標簽它能自動做 WebP 格式轉換、響應式尺寸裁剪、懶加載。實測下來一個原本 1.2MB 的圖片經(jīng)過next/image處理后在移動端輸出只有 80KB 左右視覺效果幾乎沒有差異。import Image from next/image; Image src/hero.jpg altHero width{1200} height{630} sizes(max-width: 768px) 100vw, 50vw priority /;priority屬性會告訴瀏覽器預加載這張圖片適合首屏首圖但不要給頁面里所有圖片都加。我給這個屬性專門做了一條規(guī)范只允許首頁首屏的 hero 圖片加priority其他圖片一律懶加載。第二是代碼分割。Next.js 默認按路由自動分包但有些第三方庫體積很大比如圖表庫、markdown 解析庫。用動態(tài)導入可以做到按需加載const MarkdownPreview dynamic(() import(/components/MarkdownPreview), { loading: () p加載中.../p, });第三是緩存策略。SSG/ISR 本身已經(jīng)是緩存的一種但 API 層面也要注意。我在 Route Handlers 里給不敏感的數(shù)據(jù)接口加上了Cache-Control響應頭讓 CDN 可以緩存一定時間。5.2 SEO 友好的三層設計很多人以為只要用了 Next.jsSEO 就自動變好了這個認知是錯誤的。SSR/SSG 只是讓搜索引擎能抓到 HTML 內容但抓取之后能不能理解你的網(wǎng)站取決于有沒有把 metadata、結構化數(shù)據(jù)、sitemap 做完整。App Router 里的 metadata API 很適合做這件事// app/layout.tsx import type { Metadata } from next; export const metadata: Metadata { title: { default: 我的博客, template: %s | 我的博客, }, description: 聚焦 Next.js、React 與 TypeScript 的技術內容, openGraph: { type: website, title: 我的博客, description: 聚焦 Next.js、React 與 TypeScript 的技術內容, images: [/og-image.png], }, robots: index, follow, };還可以在頁面級繼續(xù)覆蓋 metadata例如博客詳情頁動態(tài)設置 title 和 description。除此之外我還給博客項目加了app/sitemap.ts和app/robots.ts這兩個文件在構建時自動生成 sitemap 和 robots 文件不需要額外部署。結構化數(shù)據(jù)如面包屑、文章、產(chǎn)品可以通過 JSON-LD 注入到頁面中幫助搜索引擎理解頁面內容甚至能拿到富媒體摘要。這個在電商項目的商品詳情頁里我做了完整示例。5.3 性能監(jiān)控與 Core Web Vitals優(yōu)化做完了總要有個衡量標準。Next.js 自帶useReportWebVitals鉤子能把 LCP、CLS、INP 等指標上報到自己的系統(tǒng)// app/analytics.tsx use client; import { useReportWebVitals } from next/web-vitals; export function WebVitalsReporter() { useReportWebVitals((metric) { console.log(metric); }); return null; }我在實際項目中會把數(shù)據(jù)上報到內部監(jiān)控平臺并設定告警閾值。比如 LCP 超過 2.5 秒、CLS 超過 0.1 就觸發(fā)提醒。你不要不以為意線上環(huán)境的性能和開發(fā)環(huán)境完全不一樣沒有監(jiān)控手段就沒有優(yōu)化依據(jù)。6. 常用開發(fā)工具與生態(tài)配套6.1 工程化工具鏈從代碼規(guī)范到自動提交一個好的開源項目集合不應該只有業(yè)務代碼還應該包含完整的開發(fā)工具鏈。我在這套集合里統(tǒng)一接入了 ESLint、Prettier、Husky、lint-staged 和 commitlint。這套組合的邏輯是ESLint 管代碼規(guī)則Prettier 管格式統(tǒng)一Husky 借助 Git Hooks 在提交前自動執(zhí)行檢查lint-staged 只檢查暫存區(qū)的文件避免全量檢查耗時太長commitlint 約束提交信息的格式。配置之后團隊所有人寫代碼的風格會趨于一致review 時再也不用爭論“這里要不要加分號”這種問題了。6.2 React Native 等橫向擴展的方向雖然有同學建議我把 React Native 的模板也收進來但我最終沒有在集合里加 RN 相關內容。原因很簡單React Native 和 Next.js 雖然共享 React 語法但項目結構、導航方案、原生模塊、構建打包的差異太大了塞在一起只會讓集合定位模糊。如果你需要跑 React Native 的應用建議單獨維護一套模板不要和 Web 項目混在一個倉庫里。對了提到 React 面試和周邊工具時React Router 也是經(jīng)常被問到的。Next.js 的文件系統(tǒng)路由和 React Router 的手動配置路由是兩種完全不同的心智模型。Next.js 的優(yōu)勢是約定大于配置文件夾層級即路由層級不需要維護一份集中式的路由表React Router 的優(yōu)勢是更靈活可以在任意組件任意位置聲明路由。在 Next.js 項目里不要強行引入 React Router這套集合里的項目都遵循文件系統(tǒng)路由約定。6.3 自動化測試和 CI 工作流測試部分我選了 Vitest Testing Library Playwright 的組合。Vitest 跑單元測試Testing Library 負責組件交互測試Playwright 負責端到端測試。我專門在共享配置里寫了 GitHub Actions 工作流每次 push 自動跑 lint、類型檢查和單測main 分支跑 Playwright。name: CI on: push: branches: [main] pull_request: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: pnpm/action-setupv2 - uses: actions/setup-nodev4 with: node-version: 20 cache: pnpm - run: pnpm install - run: pnpm lint - run: pnpm type-check - run: pnpm test別小看這條流水線它能把大量低級問題擋在合并之前。我見過很多項目不做 CI結果一合代碼生產(chǎn)就崩跑完 CI 至少能保證每個提交都是“綠”的。7. 常見問題與排查技巧實錄7.1 Hydration 不匹配客戶端與服務端渲染結果不一致這是 Next.js 開發(fā)中最常見的報錯。報錯信息通常長得像這樣Hydration failed because the initial UI does not match what was rendered on the server.常見原因是你把依賴瀏覽器 API 的代碼直接放在了組件渲染邏輯里。比如讀取window.innerWidth做響應式判斷、用localStorage初始化狀態(tài)。解決思路是這類瀏覽器 API 只能在useEffect里訪問或者用動態(tài)導入的方式讓組件只在客戶端渲染。我習慣封裝一個useIsMounted鉤子import { useEffect, useState } from react; export function useIsMounted() { const [mounted, setMounted] useState(false); useEffect(() { setMounted(true); }, []); return mounted; }然后在需要訪問瀏覽器 API 的組件里等mounted為 true 后再渲染真正的 UI避免服務端和客戶端首次渲染的差異。7.2 構建失敗TS 類型錯誤和 Next 緩存Next.js 默認在構建時執(zhí)行類型檢查任何一個 TypeScript 類型錯誤都會導致構建失敗。很多人看到構建掛掉會很慌其實解決方法很簡單先在本地跑npx tsc --noEmit把類型錯誤修完再重新構建。另一個容易被忽略的是 Next.js 構建緩存。如果改了配置或者裝刪了依賴遇到莫名其妙的構建報錯先清緩存rm -rf .next rm -rf node_modules pnpm install別問為什么這個操作能解決我遇到的 80% 怪異問題。7.3 圖片和字體導致的 CLS 波動CLS累積布局偏移是最難優(yōu)化的一個指標。罪魁禍首往往是圖片和字體沒有預留空間。用next/image時一定要指定width和height或者使用fill屬性配合父容器相對定位這樣瀏覽器在圖片加載前就知道它占多少空間不會發(fā)生加載完成后的抖動。字體導致 CLS 通常發(fā)生在next/font配置不當時。我建議用next/font/google引入字體它會在構建時自動下載字體文件并提供size-adjust屬性基本上可以消除字體的布局偏移。7.4 API Route 返回了 undefined在新手寫的 Route Handler 里我經(jīng)??吹竭@種情況網(wǎng)絡請求成功了但前端拿到的data是undefined。排查后發(fā)現(xiàn)是函數(shù)沒有顯式 return。// 錯誤示例 export async function GET() { const posts await getPosts(); // 忘了 return } // 正確示例 export async function GET() { const posts await getPosts(); return NextResponse.json({ data: posts }); }還有一個很容易踩的坑在 GET 之外的請求方法里如果方法名寫錯比如寫成了get而不是GETNext.js 會靜默地把這個文件當成無效路由處理。排查這類問題時先看看 Network 面板返回的 HTTP 狀態(tài)碼如果是 405多半就是方法名或者路由路徑的問題。7.5 問題排查速查表現(xiàn)象可能原因快速定位方式Hydration 報錯瀏覽器 API 在服務端被調用檢查組件里是否有 window/localStorage 等引用構建失敗TS 類型錯誤本地跑tsc --noEmit定位圖片加載后頁面跳動圖片缺 width/height改用 next/image 并指定寬高路由訪問 404文件命名或目錄錯誤檢查 app 目錄結構確保 page.tsx 命名正確接口返回 405HTTP 方法名錯誤確認導出函數(shù)名是 GET/POST 全大寫部署后樣式丟失服務端和客戶端渲染時間不一致檢查是否有隨機數(shù)或 Date 參與 className 生成8. 最后分享一點整理這套集合的體會做完這份 Next.js 開源項目集合之后我最大的感受是框架本身并不難學難的是把散落在各個項目里的經(jīng)驗教訓串成一條線。Next.js 的文檔已經(jīng)寫得很好了但文檔不會告訴你圖片不加寬高屬性會導致 CLS 飆升不會告訴你baseUrl在 TypeScript 7.0 里會被移除也不會告訴你在 Server Components 里用useEffect會被框架報錯。這些細節(jié)只有在你真正跑過幾個項目、踩過幾次坑以后才會理解。如果你也想整理一份自己的 Next.js 項目集合我的建議是不要追求大而全先聚焦一個場景比如博客、商城或者后臺管理系統(tǒng)把一個項目做扎實了再橫向擴展。這個集合還會持續(xù)更新后續(xù)我計劃補充多語言國際化方案、微前端集成、性能監(jiān)控平臺對接這幾個模塊。希望這份集合能成為你學習 React 和 Next.js 路上的一個加油站。本文還有配套的精品資源點擊獲取