Turbopack 最佳实践 #
项目结构最佳实践 #
推荐目录结构 #
text
┌─────────────────────────────────────────────────────────────┐
│ 推荐项目结构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ my-project/ │
│ ├── src/ │
│ │ ├── app/ # Next.js App Router │
│ │ │ ├── layout.tsx │
│ │ │ ├── page.tsx │
│ │ │ ├── loading.tsx │
│ │ │ ├── error.tsx │
│ │ │ └── api/ # API 路由 │
│ │ ├── components/ # 共享组件 │
│ │ │ ├── ui/ # 基础 UI 组件 │
│ │ │ └── features/ # 功能组件 │
│ │ ├── lib/ # 工具库 │
│ │ │ ├── api.ts │
│ │ │ └── utils.ts │
│ │ ├── hooks/ # 自定义 Hooks │
│ │ ├── styles/ # 全局样式 │
│ │ ├── types/ # TypeScript 类型 │
│ │ └── config/ # 配置文件 │
│ ├── public/ # 静态资源 │
│ ├── tests/ # 测试文件 │
│ ├── .env.local # 环境变量 │
│ ├── next.config.js # Next.js 配置 │
│ ├── turbo.json # Turbopack 配置 │
│ └── package.json │
│ │
└─────────────────────────────────────────────────────────────┘
模块组织原则 #
text
原则一:按功能分组
├── components/
│ ├── auth/ # 认证相关
│ ├── dashboard/ # 仪表板相关
│ └── shared/ # 共享组件
原则二:就近原则
├── features/
│ └── user/
│ ├── components/
│ ├── hooks/
│ ├── utils/
│ └── index.ts
原则三:依赖方向
├── app/ → 依赖 components, lib
├── components/ → 依赖 lib, hooks
├── lib/ → 无依赖
├── hooks/ → 依赖 lib
性能优化最佳实践 #
1. 合理使用缓存 #
json
// turbo.json
{
"pipeline": {
"build": {
"outputs": [
".next/**",
"!.next/cache/**",
"!.next/trace"
],
"dependsOn": ["^build"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
2. 优化依赖导入 #
typescript
// ❌ 不推荐:导入整个库
import _ from 'lodash';
import moment from 'moment';
// ✅ 推荐:按需导入
import debounce from 'lodash/debounce';
import format from 'date-fns/format';
// ✅ 推荐:使用更轻量的替代品
import { debounce } from 'es-toolkit';
import { format } from 'date-fns';
3. 代码分割策略 #
tsx
// ✅ 推荐:动态导入大型组件
import dynamic from 'next/dynamic';
const Chart = dynamic(
() => import('./Chart'),
{
loading: () => <ChartSkeleton />,
ssr: false,
}
);
const Editor = dynamic(
() => import('./Editor'),
{
loading: () => <EditorSkeleton />,
}
);
// ✅ 推荐:条件加载
const AdminPanel = dynamic(
() => import('./AdminPanel'),
{ ssr: false }
);
export function Dashboard({ isAdmin }: { isAdmin: boolean }) {
return (
<div>
<Chart />
{isAdmin && <AdminPanel />}
</div>
);
}
4. 图片优化 #
tsx
// ✅ 推荐:使用 Next.js Image 组件
import Image from 'next/image';
export function Hero() {
return (
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>
);
}
// ✅ 推荐:响应式图片
export function ResponsiveImage() {
return (
<Image
src="/product.jpg"
alt="Product"
width={500}
height={500}
sizes="(max-width: 768px) 100vw, 50vw"
/>
);
}
5. 字体优化 #
tsx
// app/layout.tsx
import { Inter } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap',
variable: '--font-inter',
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="zh" className={inter.variable}>
<body>{children}</body>
</html>
);
}
缓存策略最佳实践 #
本地缓存配置 #
json
// turbo.json
{
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**"],
"inputs": [
"src/**/*",
"public/**/*",
"package.json",
"next.config.js"
]
}
}
}
远程缓存配置 #
yaml
# .github/workflows/ci.yml
- name: Cache Turbopack
uses: actions/cache@v4
with:
path: |
.turbo
.next/cache
key: ${{ runner.os }}-turbo-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-turbo-${{ hashFiles('**/package-lock.json') }}-
${{ runner.os }}-turbo-
缓存失效策略 #
javascript
// next.config.js
module.exports = {
experimental: {
turbo: {
cache: {
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 天
maxEntries: 1000,
},
},
},
};
团队协作最佳实践 #
1. 统一配置 #
javascript
// next.config.js
module.exports = {
experimental: {
turbo: {
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
resolveAlias: {
'@': './src',
'@components': './src/components',
'@lib': './src/lib',
'@hooks': './src/hooks',
'@utils': './src/utils',
'@styles': './src/styles',
},
},
},
typescript: {
ignoreBuildErrors: false,
},
eslint: {
ignoreDuringBuilds: false,
},
};
2. 共享类型定义 #
typescript
// src/types/api.ts
export interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
export interface PaginatedResponse<T> {
data: T[];
total: number;
page: number;
pageSize: number;
}
// src/types/models.ts
export interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'user';
createdAt: string;
}
3. 代码规范 #
json
// .eslintrc.json
{
"extends": [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-explicit-any": "warn",
"prefer-const": "error",
"no-console": ["warn", { "allow": ["warn", "error"] }]
}
}
json
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
4. Git 工作流 #
yaml
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run type-check
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run test
build:
needs: [lint, type-check, test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
部署最佳实践 #
1. 环境变量管理 #
bash
# .env.local (开发环境)
NODE_ENV=development
NEXT_PUBLIC_API_URL=http://localhost:3001
DATABASE_URL=postgresql://localhost:5432/dev
# .env.production (生产环境)
NODE_ENV=production
NEXT_PUBLIC_API_URL=https://api.example.com
DATABASE_URL=postgresql://prod-db:5432/prod
javascript
// next.config.js
module.exports = {
env: {
NEXT_PUBLIC_BUILD_TIME: new Date().toISOString(),
NEXT_PUBLIC_VERSION: process.env.npm_package_version,
},
};
2. 构建优化 #
json
// package.json
{
"scripts": {
"dev": "next dev --turbo",
"build": "next build",
"start": "next start",
"analyze": "ANALYZE=true next build"
}
}
javascript
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({
experimental: {
turbo: {},
},
output: 'standalone',
compress: true,
});
3. Docker 部署 #
dockerfile
# Dockerfile
FROM node:20-alpine AS base
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
CMD ["node", "server.js"]
yaml
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:password@db:5432/mydb
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
4. Vercel 部署 #
json
// vercel.json
{
"buildCommand": "npm run build",
"devCommand": "npm run dev",
"installCommand": "npm ci",
"framework": "nextjs",
"regions": ["hkg1", "sin1"],
"functions": {
"src/app/api/**/*.ts": {
"memory": 1024,
"maxDuration": 10
}
},
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-XSS-Protection",
"value": "1; mode=block"
}
]
}
]
}
安全最佳实践 #
1. 环境变量安全 #
typescript
// src/lib/env.ts
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
NEXT_PUBLIC_API_URL: z.string().url(),
SECRET_KEY: z.string().min(32),
});
export const env = envSchema.parse(process.env);
2. API 安全 #
typescript
// src/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const response = NextResponse.next();
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('X-Frame-Options', 'DENY');
response.headers.set('X-XSS-Protection', '1; mode=block');
const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/api/protected')) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
return response;
}
export const config = {
matcher: ['/api/:path*', '/dashboard/:path*'],
};
3. 输入验证 #
typescript
// src/lib/validation.ts
import { z } from 'zod';
export const createUserSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
password: z.string().min(8).regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/),
});
// app/api/users/route.ts
import { createUserSchema } from '@/lib/validation';
export async function POST(request: Request) {
const body = await request.json();
const result = createUserSchema.safeParse(body);
if (!result.success) {
return Response.json(
{ errors: result.error.flatten() },
{ status: 400 }
);
}
// 创建用户...
}
监控与日志最佳实践 #
1. 性能监控 #
typescript
// src/lib/analytics.ts
export function reportWebVitals(metric: any) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
timestamp: Date.now(),
});
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/analytics', body);
} else {
fetch('/api/analytics', {
method: 'POST',
body,
keepalive: true,
});
}
}
2. 错误追踪 #
typescript
// app/error.tsx
'use client';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
useEffect(() => {
console.error(error);
fetch('/api/error-report', {
method: 'POST',
body: JSON.stringify({
message: error.message,
stack: error.stack,
timestamp: Date.now(),
}),
});
}, [error]);
return (
<div>
<h2>出错了!</h2>
<button onClick={reset}>重试</button>
</div>
);
}
3. 日志管理 #
typescript
// src/lib/logger.ts
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
class Logger {
private log(level: LogLevel, message: string, data?: any) {
const timestamp = new Date().toISOString();
const logEntry = { timestamp, level, message, data };
if (process.env.NODE_ENV === 'production') {
fetch('/api/logs', {
method: 'POST',
body: JSON.stringify(logEntry),
});
} else {
console[level](logEntry);
}
}
debug(message: string, data?: any) {
this.log('debug', message, data);
}
info(message: string, data?: any) {
this.log('info', message, data);
}
warn(message: string, data?: any) {
this.log('warn', message, data);
}
error(message: string, data?: any) {
this.log('error', message, data);
}
}
export const logger = new Logger();
常见问题与解决方案 #
问题一:构建内存不足 #
bash
# 解决方案:增加 Node.js 内存限制
NODE_OPTIONS="--max-old-space-size=4096" npm run build
问题二:缓存导致的问题 #
bash
# 解决方案:清除缓存
rm -rf .turbo .next node_modules
npm install
npm run build
问题三:热更新不工作 #
javascript
// next.config.js
module.exports = {
experimental: {
turbo: {
watch: {
ignored: ['**/node_modules/**', '**/.git/**'],
},
},
},
};
问题四:大型项目构建慢 #
json
// turbo.json
{
"pipeline": {
"build": {
"outputs": [".next/**"],
"dependsOn": ["^build"],
"outputMode": "new-only"
}
}
}
检查清单 #
开发阶段 #
text
□ 配置 TypeScript 严格模式
□ 配置 ESLint 规则
□ 配置 Prettier 格式化
□ 配置 Git Hooks
□ 配置环境变量
□ 配置路径别名
构建阶段 #
text
□ 检查构建产物大小
□ 检查 Source Map 配置
□ 检查环境变量注入
□ 检查静态资源处理
□ 检查代码分割效果
□ 检查 Tree Shaking 效果
部署阶段 #
text
□ 配置生产环境变量
□ 配置 CDN
□ 配置缓存策略
□ 配置安全头
□ 配置监控告警
□ 配置日志收集
总结 #
Turbopack 是一个强大的打包工具,通过遵循这些最佳实践,你可以:
- 提升开发效率:毫秒级启动和热更新
- 优化构建性能:增量编译和持久缓存
- 改善团队协作:统一配置和规范
- 保障生产质量:安全、监控、日志
继续探索 Turbopack 的更多功能,让你的项目更加高效!
最后更新:2026-03-28