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 是一个强大的打包工具,通过遵循这些最佳实践,你可以:

  1. 提升开发效率:毫秒级启动和热更新
  2. 优化构建性能:增量编译和持久缓存
  3. 改善团队协作:统一配置和规范
  4. 保障生产质量:安全、监控、日志

继续探索 Turbopack 的更多功能,让你的项目更加高效!

最后更新:2026-03-28