Skip to content

开发工具与调试

🙋 高效的开发体验是提升生产力的关键。Next.js 15 带来了哪些开发工具改进?

Turbopack#

Next.js 15 将 Turbopack 设为开发模式的默认打包器。它使用 Rust 编写,比 Webpack 快得多。

默认启用#

Terminal window
# 开发模式自动使用 Turbopack
pnpm dev
# 输出显示使用的打包器
# ▲ Next.js 15.x
# - Local: http://localhost:3000
# - Turbopack (default)

性能对比#

操作WebpackTurbopack提升
冷启动12s2s6x
HMR500ms50ms10x
路由切换200ms30ms6x

数据来自中型项目(~500 组件)

回退到 Webpack#

如果项目有自定义 Webpack 配置且无法迁移:

Terminal window
# 使用 Webpack
pnpm dev --webpack

或在 package.json 中配置:

{
"scripts": {
"dev": "next dev --webpack"
}
}

Turbopack 配置#

next.config.ts
// Next.js 15.x
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
turbopack: {
// 自定义文件处理规则
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
// 模块别名
resolveAlias: {
'old-package': 'new-package',
},
// 文件扩展名解析顺序
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
},
}
export default nextConfig

Fast Refresh#

Fast Refresh 是 Next.js 的热更新机制,可以在保持组件状态的情况下实时预览代码更改。

工作原理#

components/Counter.tsx
// Next.js 15.x
'use client'
import { useState } from 'react'
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div>
<p>计数: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}

修改这个组件时:

  1. ✅ 修改 JSX 结构 → 状态保持,UI 更新
  2. ✅ 修改样式 → 状态保持,样式更新
  3. ❌ 修改 hooks 逻辑 → 状态重置

保持状态的技巧#

// 使用 key 强制重新挂载
;<Counter key={Date.now()} />
// 使用 useEffect 依赖追踪变化
useEffect(() => {
console.log('组件已更新')
}, [])

Fast Refresh 失效的情况#

🔶 以下情况会导致完全刷新:

  1. 组件导出的不是 React 组件
  2. 文件同时导出组件和非组件
  3. 使用 Class 组件
  4. 错误的模块边界
// ❌ 这会导致 Fast Refresh 失效
export default function Component() { ... }
export const config = { ... } // 非组件导出
// ✅ 拆分到不同文件
// component.tsx
export default function Component() { ... }
// config.ts
export const config = { ... }

错误处理与调试#

错误叠加层#

开发模式下,Next.js 提供详细的错误信息叠加层:

app/page.tsx
// 故意引入错误
export default function Page() {
const user = null
return <p>{user.name}</p> // TypeError!
}

错误叠加层显示:

console 调试#

Server Component 的 console 输出在终端,Client Component 的在浏览器:

// Server Component - 终端输出
export default async function Page() {
console.log('服务端日志') // 👈 终端
const data = await fetch('...')
return <div>{data}</div>
}
// Client Component - 浏览器输出
'use client'
export default function Button() {
console.log('客户端日志') // 👈 浏览器控制台
return <button onClick={() => console.log('点击')}>按钮</button>
}

断点调试#

VS Code 配置#

.vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node",
"request": "attach",
"port": 9229,
"restart": true,
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Next.js: debug client-side",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000"
}
]
}

启动调试:

Terminal window
# 开启 Node.js 调试端口
NODE_OPTIONS='--inspect' pnpm dev

浏览器调试#

  1. 打开 Chrome DevTools (F12)
  2. Sources 面板找到 webpack://_N_E/turbopack://
  3. 设置断点

React DevTools#

安装 React Developer Tools 浏览器扩展。

🎯 功能

// 添加 displayName 便于调试
const MyComponent = () => <div>内容</div>
MyComponent.displayName = 'MyComponent'
// 或使用具名函数
export default function MyComponent() {
return <div>内容</div>
}

性能监控#

内置性能指标#

app/layout.tsx
// Next.js 15.x
import { SpeedInsights } from '@vercel/speed-insights/next'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
{children}
<SpeedInsights />
</body>
</html>
)
}

自定义性能追踪#

app/page.tsx
// Next.js 15.x
import { unstable_noStore as noStore } from 'next/cache'
export default async function Page() {
noStore() // 禁用缓存以测试真实性能
const start = performance.now()
const data = await fetch('https://api.example.com/slow-endpoint')
const duration = performance.now() - start
console.log(`API 请求耗时: ${duration}ms`)
return <div>...</div>
}

Bundle 分析#

Terminal window
# 安装分析工具
pnpm add -D @next/bundle-analyzer
next.config.ts
// Next.js 15.x
import type { NextConfig } from 'next'
import bundleAnalyzer from '@next/bundle-analyzer'
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
})
const nextConfig: NextConfig = {
// 配置项
}
export default withBundleAnalyzer(nextConfig)
Terminal window
# 运行分析
ANALYZE=true pnpm build

生成可视化报告,显示每个模块的体积占比。

常用开发技巧#

1. 快速重启#

Terminal window
# 清除 .next 缓存后重启
rm -rf .next && pnpm dev

2. 环境变量热更新#

Terminal window
# .env.local 修改后需要重启
# 使用 dotenv-cli 可以避免
pnpm add -D dotenv-cli
{
"scripts": {
"dev": "dotenv -e .env.local -- next dev"
}
}

3. 模拟慢网络#

// 开发环境模拟延迟
async function getData() {
if (process.env.NODE_ENV === 'development') {
await new Promise((r) => setTimeout(r, 2000)) // 2秒延迟
}
return fetch('...')
}

4. 条件日志#

lib/logger.ts
export const log = (...args: unknown[]) => {
if (process.env.NODE_ENV === 'development') {
console.log('[DEV]', ...args)
}
}
// 使用
import { log } from '@/lib/logger'
log('调试信息', { data })

常见问题#

🤔 Q: Turbopack 报错怎么办?

Turbopack 仍在快速迭代,某些 Webpack 配置可能不兼容。临时方案是回退到 Webpack:

Terminal window
pnpm dev --webpack

然后检查 Turbopack 兼容性文档 寻找替代方案。

🤔 Q: Fast Refresh 不生效?

检查组件是否:

🤔 Q: 如何调试生产构建?

Terminal window
# 生产模式构建
pnpm build
# 启动生产服务器
pnpm start
# 使用 source map(需配置)

下一篇将深入 TypeScript 配置,包括路径别名、严格模式和类型增强。

-EOF-