Turbopack 基础使用 #

安装 Turbopack #

系统要求 #

text
Node.js: >= 18.17.0
操作系统: macOS, Linux, Windows
内存: >= 4GB (推荐 8GB+)

方式一:Next.js 项目 #

Next.js 13+ 内置 Turbopack 支持:

bash
# 创建新项目
npx create-next-app@latest my-app

# 进入项目目录
cd my-app

# 使用 Turbopack 启动开发服务器
npm run dev -- --turbo

方式二:独立安装 #

bash
# 全局安装
npm install -g turbo

# 或作为项目依赖
npm install --save-dev turbo

命令行使用 #

基本命令 #

bash
# 开发模式
turbo dev

# 构建生产版本
turbo build

# 监听模式
turbo watch

命令行选项 #

选项 描述 示例
--port 指定端口 turbo dev --port 3001
--host 指定主机 turbo dev --host 0.0.0.0
--config 指定配置文件 turbo dev --config turbo.json
--cache-dir 缓存目录 turbo dev --cache-dir .turbo
--no-cache 禁用缓存 turbo build --no-cache
--profile 性能分析 turbo build --profile

开发服务器 #

bash
# 启动开发服务器
turbo dev

# 指定端口
turbo dev --port 3001

# 允许外部访问
turbo dev --host 0.0.0.0

# 禁用自动打开浏览器
turbo dev --no-open

生产构建 #

bash
# 构建
turbo build

# 分析构建结果
turbo build --analyze

# 生成性能报告
turbo build --profile

Next.js 集成 #

启用 Turbopack #

json
// package.json
{
  "scripts": {
    "dev": "next dev --turbo",
    "build": "next build",
    "start": "next start"
  }
}

配置文件 #

javascript
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      resolveExtensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
      resolveAlias: {
        '@': './src',
        '@components': './src/components',
      },
    },
  },
}

开发体验 #

bash
# 启动开发服务器
npm run dev

# 输出示例
#   ▲ Next.js 14.0.0
#   - Local:        http://localhost:3000
#   - Turbopack:    enabled
#
#   ✓ Ready in 0.5s

项目结构 #

基本结构 #

text
my-project/
├── src/
│   ├── app/
│   │   ├── layout.tsx
│   │   ├── page.tsx
│   │   └── globals.css
│   ├── components/
│   │   ├── Header.tsx
│   │   └── Footer.tsx
│   └── lib/
│       └── utils.ts
├── public/
│   └── images/
├── next.config.js
├── turbo.json
└── package.json

Turbopack 配置文件 #

json
// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

模块解析 #

路径别名 #

javascript
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      resolveAlias: {
        '@': './src',
        '@components': './src/components',
        '@lib': './src/lib',
        '@styles': './src/styles',
        '@hooks': './src/hooks',
        '@utils': './src/utils',
      },
    },
  },
}
tsx
// 使用别名导入
import Header from '@/components/Header';
import { formatDate } from '@utils/date';
import styles from '@styles/Button.module.css';

扩展名解析 #

javascript
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      resolveExtensions: [
        '.tsx',
        '.ts',
        '.jsx',
        '.js',
        '.json',
        '.css',
        '.scss',
      ],
    },
  },
}
tsx
// 导入时可以省略扩展名
import Header from './Header';      // 解析为 Header.tsx
import styles from './Button.css';  // 解析为 Button.css

TypeScript 支持 #

原生支持 #

Turbopack 原生支持 TypeScript,无需额外配置:

tsx
// src/app/page.tsx
interface User {
  id: number;
  name: string;
  email: string;
}

async function fetchUser(id: number): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  return res.json();
}

export default async function Page() {
  const user = await fetchUser(1);
  return <div>Hello, {user.name}</div>;
}

类型检查 #

bash
# 单独运行类型检查
npx tsc --noEmit

# 或在 package.json 中添加脚本
{
  "scripts": {
    "type-check": "tsc --noEmit"
  }
}

tsconfig.json #

json
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "preserve",
    "strict": true,
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

CSS 处理 #

CSS Modules #

css
/* Button.module.css */
.button {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.primary {
  background-color: #0070f3;
  color: white;
}

.secondary {
  background-color: #6c757d;
  color: white;
}
tsx
// Button.tsx
import styles from './Button.module.css';

interface ButtonProps {
  variant?: 'primary' | 'secondary';
  children: React.ReactNode;
}

export function Button({ variant = 'primary', children }: ButtonProps) {
  return (
    <button className={`${styles.button} ${styles[variant]}`}>
      {children}
    </button>
  );
}

全局样式 #

css
/* globals.css */
:root {
  --primary-color: #0070f3;
  --text-color: #333;
  --background: #fff;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  color: var(--text-color);
  background: var(--background);
}
tsx
// layout.tsx
import './globals.css';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="zh">
      <body>{children}</body>
    </html>
  );
}

CSS 预处理器 #

javascript
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      rules: {
        '*.scss': {
          loaders: ['sass-loader'],
        },
        '*.less': {
          loaders: ['less-loader'],
        },
      },
    },
  },
}
scss
// styles.module.scss
$primary: #0070f3;

.button {
  background: $primary;
  
  &:hover {
    background: darken($primary, 10%);
  }
}

静态资源 #

图片处理 #

tsx
// 使用 Next.js Image 组件
import Image from 'next/image';

export function Logo() {
  return (
    <Image
      src="/images/logo.png"
      alt="Logo"
      width={200}
      height={100}
      priority
    />
  );
}

静态文件 #

text
public/
├── images/
│   ├── logo.png
│   └── hero.jpg
├── fonts/
│   └── custom.woff2
└── favicon.ico
tsx
// 引用静态资源
<img src="/images/logo.png" alt="Logo" />

// 字体
@font-face {
  font-family: 'CustomFont';
  src: url('/fonts/custom.woff2') format('woff2');
}

热模块替换(HMR) #

自动 HMR #

Turbopack 自动处理 HMR:

tsx
// Counter.tsx
import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>
        Increment
      </button>
    </div>
  );
}

修改代码后,组件会自动更新,状态保持不变。

HMR 性能 #

text
┌─────────────────────────────────────────────────────────────┐
│                    HMR 时间对比                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   Webpack:     ████████████████████████████  3000ms        │
│                                                              │
│   Vite:        ████████  200ms                              │
│                                                              │
│   Turbopack:   █  10ms                                       │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Fast Refresh #

React Fast Refresh 自动保留组件状态:

tsx
// 修改前
export function Greeting({ name }: { name: string }) {
  return <h1>Hello, {name}!</h1>;
}

// 修改后 - 状态保持
export function Greeting({ name }: { name: string }) {
  return <h1>Welcome, {name}!</h1>;
}

环境变量 #

定义环境变量 #

bash
# .env.local
DATABASE_URL=postgresql://localhost:5432/mydb
API_KEY=your-api-key
NEXT_PUBLIC_API_URL=https://api.example.com

使用环境变量 #

tsx
// 服务端
async function connectDB() {
  const url = process.env.DATABASE_URL;
  // 连接数据库
}

// 客户端(需要 NEXT_PUBLIC_ 前缀)
const apiUrl = process.env.NEXT_PUBLIC_API_URL;

export function DataFetcher() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetch(apiUrl).then(res => res.json()).then(setData);
  }, []);
  
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}

环境变量类型 #

typescript
// env.d.ts
namespace NodeJS {
  interface ProcessEnv {
    DATABASE_URL: string;
    API_KEY: string;
    NEXT_PUBLIC_API_URL: string;
    NODE_ENV: 'development' | 'production' | 'test';
  }
}

开发工具 #

浏览器 DevTools #

Turbopack 提供开发工具集成:

tsx
// React DevTools 可以正常使用
// 组件树、Props、State 都可以查看

调试配置 #

json
// .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Next.js: debug full stack",
      "type": "node-terminal",
      "request": "launch",
      "command": "npm run dev"
    }
  ]
}

日志输出 #

bash
# 开发模式日志
turbo dev --log-level verbose

# 输出示例
# [turbopack] Compiling...
# [turbopack] Compiled successfully in 50ms
# [turbopack] HMR update: /src/app/page.tsx

常见问题排查 #

问题一:端口被占用 #

bash
# 错误
Error: Port 3000 is already in use

# 解决方案
turbo dev --port 3001

问题二:缓存问题 #

bash
# 清除缓存
rm -rf .turbo
rm -rf .next

# 重新启动
turbo dev

问题三:模块找不到 #

bash
# 错误
Module not found: Can't resolve '@/components/Header'

# 解决方案:检查路径别名配置
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      resolveAlias: {
        '@': './src',
      },
    },
  },
}

问题四:类型错误 #

bash
# 运行类型检查
npx tsc --noEmit

# 常见原因
# 1. tsconfig.json 配置错误
# 2. 缺少类型定义
# 3. 路径别名未同步

性能优化 #

缓存策略 #

json
// turbo.json
{
  "pipeline": {
    "build": {
      "outputs": [".next/**", "!.next/cache/**"],
      "dependsOn": ["^build"]
    }
  }
}

按需编译 #

Turbopack 自动按需编译:

text
┌─────────────────────────────────────────────────────────────┐
│                    按需编译                                  │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   访问 /page-a  ──► 只编译 page-a 相关模块                   │
│                                                              │
│   访问 /page-b  ──► 只编译 page-b 相关模块                   │
│                                                              │
│   其他页面     ──► 不编译                                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

减少依赖 #

javascript
// 避免导入整个库
import _ from 'lodash';  // ❌ 导入整个库

// 只导入需要的函数
import debounce from 'lodash/debounce';  // ✅ 只导入需要的

实战示例 #

示例一:创建组件 #

tsx
// src/components/Card.tsx
interface CardProps {
  title: string;
  description: string;
  image?: string;
}

export function Card({ title, description, image }: CardProps) {
  return (
    <div className="card">
      {image && <img src={image} alt={title} />}
      <h3>{title}</h3>
      <p>{description}</p>
    </div>
  );
}
css
/* Card.module.css */
.card {
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  padding: 16px;
  transition: box-shadow 0.2s;
}

.card:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.card img {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-radius: 4px;
}

.card h3 {
  margin: 12px 0 8px;
  font-size: 18px;
}

.card p {
  color: #666;
  font-size: 14px;
}

示例二:API 路由 #

typescript
// src/app/api/users/route.ts
import { NextResponse } from 'next/server';

interface User {
  id: number;
  name: string;
  email: string;
}

const users: User[] = [
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob', email: 'bob@example.com' },
];

export async function GET() {
  return NextResponse.json(users);
}

export async function POST(request: Request) {
  const body = await request.json();
  const newUser: User = {
    id: users.length + 1,
    ...body,
  };
  users.push(newUser);
  return NextResponse.json(newUser, { status: 201 });
}

示例三:数据获取 #

tsx
// src/app/users/page.tsx
interface User {
  id: number;
  name: string;
  email: string;
}

async function getUsers(): Promise<User[]> {
  const res = await fetch('/api/users', {
    cache: 'no-store',
  });
  return res.json();
}

export default async function UsersPage() {
  const users = await getUsers();
  
  return (
    <div>
      <h1>Users</h1>
      <ul>
        {users.map(user => (
          <li key={user.id}>
            {user.name} - {user.email}
          </li>
        ))}
      </ul>
    </div>
  );
}

下一步 #

现在你已经掌握了 Turbopack 的基础使用方法,接下来学习 配置详解 深入了解各种配置选项!

最后更新:2026-03-28