frontend-performance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFrontend Performance Optimization
前端性能优化
Diagnose and fix performance issues in Next.js applications.
诊断并修复Next.js应用中的性能问题。
Quick Diagnostics
快速诊断
Run Lighthouse CLI
运行Lighthouse CLI
bash
undefinedbash
undefinedPerformance audit (headless)
Performance audit (headless)
npx lighthouse http://localhost:3000 --output=json --output-path=./lighthouse.json --chrome-flags="--headless" --only-categories=performance
npx lighthouse http://localhost:3000 --output=json --output-path=./lighthouse.json --chrome-flags="--headless" --only-categories=performance
Parse key metrics
Parse key metrics
cat lighthouse.json | jq '{
score: .categories.performance.score,
FCP: .audits["first-contentful-paint"].displayValue,
LCP: .audits["largest-contentful-paint"].displayValue,
TBT: .audits["total-blocking-time"].displayValue,
CLS: .audits["cumulative-layout-shift"].displayValue
}'
cat lighthouse.json | jq '{
score: .categories.performance.score,
FCP: .audits["first-contentful-paint"].displayValue,
LCP: .audits["largest-contentful-paint"].displayValue,
TBT: .audits["total-blocking-time"].displayValue,
CLS: .audits["cumulative-layout-shift"].displayValue
}'
Find slow scripts
Find slow scripts
cat lighthouse.json | jq '.audits["bootup-time"].details.items | .[0:8]'
cat lighthouse.json | jq '.audits["bootup-time"].details.items | .[0:8]'
Main thread breakdown
Main thread breakdown
cat lighthouse.json | jq '.audits["mainthread-work-breakdown"].details.items'
**Important**: Always test production builds (`next build && next start`), not dev mode. Dev mode has 2-10x overhead from HMR, source maps, and no optimizations.cat lighthouse.json | jq '.audits["mainthread-work-breakdown"].details.items'
**重要提示**:请始终测试生产构建版本(`next build && next start`),而非开发模式。开发模式由于HMR、源映射以及未启用优化,会产生2-10倍的性能开销。Bundle Analysis
包分析
bash
undefinedbash
undefinedInstall
Install
bun add -d @next/bundle-analyzer
bun add -d @next/bundle-analyzer
Run analysis
Run analysis
ANALYZE=true bun run build
Configure in `next.config.js`:
```js
import bundleAnalyzer from '@next/bundle-analyzer'
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
})
export default withBundleAnalyzer(nextConfig)ANALYZE=true bun run build
在`next.config.js`中配置:
```js
import bundleAnalyzer from '@next/bundle-analyzer'
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
})
export default withBundleAnalyzer(nextConfig)Common Fixes
常见修复方案
1. optimizePackageImports
1. optimizePackageImports
For libraries with many exports (icons, utilities, animation libraries):
js
// next.config.js
const nextConfig = {
experimental: {
optimizePackageImports: [
'framer-motion',
'lucide-react',
'@phosphor-icons/react',
'lodash',
'date-fns',
'@heroicons/react',
],
},
}This ensures tree-shaking works correctly - only imports you use get bundled.
针对包含大量导出的库(图标、工具类、动画库):
js
// next.config.js
const nextConfig = {
experimental: {
optimizePackageImports: [
'framer-motion',
'lucide-react',
'@phosphor-icons/react',
'lodash',
'date-fns',
'@heroicons/react',
],
},
}此配置确保Tree Shaking正常工作 - 仅打包你实际使用的导入内容。
2. Framer Motion - Variants Pattern
2. Framer Motion - 变体模式
WRONG - Creates N animation controllers:
tsx
// Each element has its own animation state - expensive!
{items.map((item, i) => (
<motion.div
key={i}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: i * 0.05 }} // Individual delays
>
{item}
</motion.div>
))}RIGHT - Single controller with staggerChildren:
tsx
// Parent controls all children - efficient!
const containerVariants = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.05,
},
},
}
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { type: 'spring' as const, damping: 15 }
},
}
<motion.div
variants={containerVariants}
initial="hidden"
animate="visible"
>
{items.map((item, i) => (
<motion.div key={i} variants={itemVariants}>
{item}
</motion.div>
))}
</motion.div>Also avoid:
- in animations - very expensive
filter: blur() - Too many infinite animations (reduce or use CSS)
- Individual props on children when using variants
transition
错误示例 - 创建N个动画控制器:
tsx
// Each element has its own animation state - expensive!
{items.map((item, i) => (
<motion.div
key={i}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: i * 0.05 }} // Individual delays
>
{item}
</motion.div>
))}正确示例 - 单个控制器配合staggerChildren:
tsx
// Parent controls all children - efficient!
const containerVariants = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.05,
},
},
}
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { type: 'spring' as const, damping: 15 }
},
}
<motion.div
variants={containerVariants}
initial="hidden"
animate="visible"
>
{items.map((item, i) => (
<motion.div key={i} variants={itemVariants}>
{item}
</motion.div>
))}
</motion.div>同时需避免:
- 在动画中使用- 性能开销极大
filter: blur() - 过多无限循环动画(减少使用或改用CSS实现)
- 使用变体模式时,为子元素单独设置属性
transition
3. Move Heavy Computation Server-Side
3. 重计算逻辑移至服务端
Keep these out of client bundles:
- Syntax highlighting: use server-side, not
shikiprism-react-renderer - Markdown parsing: render on server
- Date formatting libraries: consider
Intl.DateTimeFormat - Large data transformations: API routes or server components
避免将以下内容打包到客户端:
- 语法高亮:使用服务端的,而非客户端的
shikiprism-react-renderer - Markdown解析:在服务端渲染
- 日期格式化库:考虑使用
Intl.DateTimeFormat - 大型数据转换:通过API路由或服务端组件处理
4. Image Optimization
4. 图片优化
tsx
// Always use next/image
import Image from 'next/image'
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // For LCP images
placeholder="blur" // Reduces CLS
/>tsx
// Always use next/image
import Image from 'next/image'
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // For LCP images
placeholder="blur" // Reduces CLS
/>5. Font Optimization
5. 字体优化
tsx
// app/layout.tsx
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap', // Prevents FOIT
preload: true,
})tsx
// app/layout.tsx
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap', // Prevents FOIT
preload: true,
})6. External Packages (Server Only)
6. 外部包(仅服务端使用)
Prevent server-only packages from being bundled:
js
// next.config.js
const nextConfig = {
serverExternalPackages: ['sharp', 'canvas'],
}防止仅服务端使用的包被打包到客户端:
js
// next.config.js
const nextConfig = {
serverExternalPackages: ['sharp', 'canvas'],
}Performance Targets
性能指标目标
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP | ≤2.5s | 2.5-4s | >4s |
| FCP | ≤1.8s | 1.8-3s | >3s |
| TBT | ≤200ms | 200-600ms | >600ms |
| CLS | ≤0.1 | 0.1-0.25 | >0.25 |
| 指标 | 优秀 | 待改进 | 较差 |
|---|---|---|---|
| LCP | ≤2.5s | 2.5-4s | >4s |
| FCP | ≤1.8s | 1.8-3s | >3s |
| TBT | ≤200ms | 200-600ms | >600ms |
| CLS | ≤0.1 | 0.1-0.25 | >0.25 |
Debugging Workflow
调试流程
- Run production Lighthouse - Get baseline metrics
- Check bootup-time audit - Find slow scripts
- Run bundle analyzer - Identify large chunks
- Fix largest issues first - Usually 1-2 packages cause most problems
- Re-test - Verify improvements
- 运行生产环境Lighthouse - 获取基准指标
- 查看bootup-time审计结果 - 定位缓慢脚本
- 运行包分析工具 - 识别体积较大的代码块
- 优先修复最大问题 - 通常1-2个包是主要性能瓶颈
- 重新测试 - 验证优化效果
Quick Wins Checklist
快速优化检查清单
- Test production build, not dev
- Add for icon/utility libraries
optimizePackageImports - Use Framer Motion variants pattern
- Remove from animations
filter: blur() - Add to LCP images
priority - Use with
next/fontdisplay: swap - Move heavy libraries to server components
- 测试生产构建版本,而非开发模式
- 为图标/工具类库添加配置
optimizePackageImports - 使用Framer Motion变体模式
- 移除动画中的
filter: blur() - 为LCP图片添加属性
priority - 使用并设置
next/fontdisplay: swap - 将大型库移至服务端组件