Next.js App Router 使用笔记
Next.js App Router 使用笔记
这个站用的 Next.js 16 + App Router。选择 App Router 主要是看中它的 Server Components 和 Streaming,但在实际使用中有些地方和预期不太一样。
Root Layout 和 Client Components
按照设计,大部分交互组件(播放器、光标、菜单)都是 "use client",而内容展示部分(博客列表、API 路由)保持 Server Components。
但实际写下来发现,"use client" 的传播比想象中更广。如果一个 Client Component 里 import 了一个 Server Component,Server Component 也会被隐式地变成 Client Component。解决方法是把 Server Component 作为 children 传入,而不是直接在 Client Component 里引用。
API Routes
App Router 的 API 路由写法和 Pages Router 差别很大。新版的 route handler 签名变成了:
export async function GET(
request: Request,
{ params }: { params: Promise<{ slug: string }> }
)
params 变成 Promise 了,需要 await。这个改动在文档里不太起眼,但迁移时容易漏掉。
还有一点:原本在 Pages Router 里可以用 req.query 直接拿参数,App Router 里得自己 new URL(request.url).searchParams.get()。多写几行代码,但意图更明确。
中间件
用了 middleware 做 mc.w-en.cc 子域名的重定向。一开始没注意 matcher 配置,默认匹配所有路径导致静态资源请求也被中间件拦截了。加上 _next/static 排除规则就好了。
中间件还有一个容易忽略的点——它在 Edge Runtime 里运行,不能使用 Node.js 原生模块。所以重定向逻辑需要保持轻量。
构建缓存问题
开发过程中遇到的最棘手的不是代码问题,而是构建缓存。Next.js 16 的 Turbopack 会在 .next 里缓存编译结果,如果缓存状态和源文件不一致,可能会出现 "明明改了代码但页面没变" 的情况。
有几次删了 .next 重建后还是加载旧代码,排查发现是残留的 Node 进程占住了端口,一直返回旧的渲染结果。用任务管理器把 node 进程全杀了再重启才解决。
构建体积
目前全站构建时间在 2 秒左右,静态页面 17 个,动态路由若干。生产构建的体积方面,主要的权重在 Three.js 和 GSAP 两个库上。考虑过动态导入按需加载,但目前首页的粒子系统在首屏就需要用到 Three.js,拆包收益不大。