Turbopack 高级用法 #

Monorepo 支持 #

什么是 Monorepo? #

Monorepo 是一种将多个项目放在同一个仓库中管理的开发策略:

text
┌─────────────────────────────────────────────────────────────┐
│                    Monorepo 结构                             │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   my-monorepo/                                               │
│   ├── apps/                                                  │
│   │   ├── web/          # Web 应用                          │
│   │   ├── admin/        # 管理后台                          │
│   │   └── docs/         # 文档站点                          │
│   ├── packages/                                              │
│   │   ├── ui/           # UI 组件库                         │
│   │   ├── utils/        # 工具函数库                        │
│   │   └── config/       # 共享配置                          │
│   ├── turbo.json        # Turbopack 配置                    │
│   └── package.json      # 根 package.json                   │
│                                                              │
└─────────────────────────────────────────────────────────────┘

配置 Monorepo #

根目录配置 #

json
// package.json
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "devDependencies": {
    "turbo": "^2.0.0"
  },
  "scripts": {
    "dev": "turbo dev",
    "build": "turbo build",
    "test": "turbo test",
    "lint": "turbo lint"
  }
}

Turbopack 配置 #

json
// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "globalEnv": ["NODE_ENV"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {
      "outputs": []
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"]
    },
    "clean": {
      "cache": false
    }
  }
}

应用配置 #

json
// apps/web/package.json
{
  "name": "@my-org/web",
  "version": "1.0.0",
  "dependencies": {
    "@my-org/ui": "*",
    "@my-org/utils": "*",
    "next": "^14.0.0",
    "react": "^18.2.0"
  },
  "scripts": {
    "dev": "next dev --turbo",
    "build": "next build",
    "start": "next start"
  }
}

包配置 #

json
// packages/ui/package.json
{
  "name": "@my-org/ui",
  "version": "1.0.0",
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./styles.css": "./dist/styles.css"
  },
  "scripts": {
    "build": "tsup src/index.ts --format esm,cjs --dts",
    "dev": "tsup src/index.ts --format esm,cjs --watch"
  },
  "peerDependencies": {
    "react": "^18.0.0"
  }
}

任务编排 #

json
// turbo.json
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"],
      "inputs": ["src/**/*", "test/**/*"]
    },
    "lint": {
      "dependsOn": ["^build"],
      "outputs": []
    },
    "type-check": {
      "dependsOn": ["^build"],
      "outputs": []
    }
  }
}

并行执行 #

bash
# 并行构建所有包
turbo build --parallel

# 并行测试
turbo test --parallel

# 过滤特定包
turbo build --filter=@my-org/web
turbo build --filter='./apps/*'

增量构建 #

bash
# 只构建变化的包
turbo build --filter=...[origin/main]

# 只构建依赖变化的包
turbo build --filter=...{HEAD}

远程缓存 #

配置远程缓存 #

bash
# 登录 Vercel
turbo login

# 关联项目
turbo link

# 配置团队
turbo config set team my-team

远程缓存配置 #

json
// turbo.json
{
  "remoteCache": {
    "enabled": true,
    "signature": true
  }
}

CI/CD 集成 #

yaml
# .github/workflows/ci.yml
name: CI

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Cache Turbopack
        uses: actions/cache@v4
        with:
          path: .turbo
          key: ${{ runner.os }}-turbo-${{ hashFiles('**/package-lock.json') }}
      
      - name: Build
        run: npm run build
        env:
          TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
          TURBO_TEAM: ${{ vars.TURBO_TEAM }}

自定义远程缓存 #

javascript
// custom-cache-server.js
const express = require('express');
const { createClient } = require('@vercel/blob');

const app = express();
const blob = createClient({
  token: process.env.BLOB_READ_WRITE_TOKEN,
});

app.put('/v8/artifacts/:hash', async (req, res) => {
  const { hash } = req.params;
  await blob.put(`artifacts/${hash}`, req);
  res.json({ status: 'ok' });
});

app.get('/v8/artifacts/:hash', async (req, res) => {
  const { hash } = req.params;
  const blob = await blob.get(`artifacts/${hash}`);
  if (!blob) {
    return res.status(404).json({ error: 'Not found' });
  }
  blob.pipe(res);
});

app.listen(3001);
bash
# 配置自定义缓存服务器
turbo config set api-url http://localhost:3001

自定义插件 #

插件架构 #

text
┌─────────────────────────────────────────────────────────────┐
│                    插件系统                                  │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   ┌─────────────────────────────────────────────────────┐  │
│   │                  Plugin Interface                     │  │
│   │  ┌───────────┐ ┌───────────┐ ┌───────────┐         │  │
│   │  │  name     │ │  version  │ │  hooks    │         │  │
│   │  └───────────┘ └───────────┘ └───────────┘         │  │
│   └─────────────────────────────────────────────────────┘  │
│                           │                                  │
│                           ▼                                  │
│   ┌─────────────────────────────────────────────────────┐  │
│   │                  Plugin Hooks                         │  │
│   │  ┌───────────┐ ┌───────────┐ ┌───────────┐         │  │
│   │  │  onInit   │ │  onBuild  │ │  onEmit   │         │  │
│   │  └───────────┘ └───────────┘ └───────────┘         │  │
│   └─────────────────────────────────────────────────────┘  │
│                                                              │
└─────────────────────────────────────────────────────────────┘

创建插件 #

javascript
// plugins/my-plugin.js
module.exports = function myPlugin(options = {}) {
  return {
    name: 'my-plugin',
    
    setup(build) {
      build.onResolve({ filter: /^my-lib:/ }, async (args) => {
        const path = args.path.replace('my-lib:', '');
        return { path: `./lib/${path}.js` };
      });
      
      build.onLoad({ filter: /\.custom$/ }, async (args) => {
        const content = await fs.readFile(args.path, 'utf8');
        return {
          contents: transformCustom(content),
          loader: 'js',
        };
      });
    },
  };
};

使用插件 #

javascript
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      plugins: [
        require('./plugins/my-plugin')({
          option1: 'value1',
        }),
      ],
    },
  },
};

插件钩子 #

javascript
module.exports = function myPlugin() {
  return {
    name: 'my-plugin',
    
    setup(build) {
      build.onStart(() => {
        console.log('Build started');
      });
      
      build.onEnd((result) => {
        console.log('Build finished');
        console.log('Warnings:', result.warnings);
        console.log('Errors:', result.errors);
      });
      
      build.onResolve({ filter: /.*/ }, async (args) => {
        if (args.path.startsWith('@')) {
          return { path: args.path, external: true };
        }
        return null;
      });
      
      build.onLoad({ filter: /\.txt$/ }, async (args) => {
        const content = await fs.readFile(args.path, 'utf8');
        return {
          contents: `export default ${JSON.stringify(content)}`,
          loader: 'js',
        };
      });
    },
  };
};

性能分析 #

构建分析 #

bash
# 分析构建
turbo build --profile

# 生成分析报告
turbo build --analyze

性能报告 #

javascript
// performance-report.js
const { performance } = require('perf_hooks');

const startTime = performance.now();

module.exports = {
  name: 'performance-plugin',
  
  setup(build) {
    build.onStart(() => {
      console.log(`Build started at ${new Date().toISOString()}`);
    });
    
    build.onEnd(() => {
      const duration = performance.now() - startTime;
      console.log(`Build completed in ${duration.toFixed(2)}ms`);
    });
  },
};

内存分析 #

bash
# 启用内存分析
NODE_OPTIONS="--inspect" turbo dev

# 使用 Chrome DevTools 分析
# chrome://inspect

缓存分析 #

bash
# 查看缓存统计
turbo build --summarize-cache

# 输出示例
# Cache hits: 150
# Cache misses: 10
# Total time saved: 45s

调试技巧 #

详细日志 #

bash
# 启用详细日志
turbo build --log-level verbose

# 调试模式
turbo build --debug

# 输出任务图
turbo build --graph

干运行模式 #

bash
# 查看将执行的任务
turbo build --dry-run

# 输出示例
# • build @my-org/web
# • build @my-org/ui
# • build @my-org/utils

缓存调试 #

bash
# 强制重新构建
turbo build --force

# 查看缓存内容
turbo build --summarize-cache

# 清除缓存
rm -rf .turbo

模块解析调试 #

javascript
// debug-resolve.js
module.exports = {
  name: 'debug-resolve',
  
  setup(build) {
    build.onResolve({ filter: /.*/ }, (args) => {
      console.log(`Resolving: ${args.path}`);
      console.log(`  Importer: ${args.importer}`);
      console.log(`  Namespace: ${args.namespace}`);
      return null;
    });
  },
};

高级配置 #

条件配置 #

javascript
// next.config.js
const isProduction = process.env.NODE_ENV === 'production';

module.exports = {
  experimental: {
    turbo: {
      rules: {
        '*.svg': {
          loaders: isProduction 
            ? ['@svgr/webpack', 'image-webpack-loader']
            : ['@svgr/webpack'],
          as: '*.js',
        },
      },
    },
  },
};

多环境配置 #

javascript
// next.config.js
module.exports = (phase, { defaultConfig }) => {
  const config = {
    experimental: {
      turbo: {},
    },
  };
  
  if (phase === 'phase-development-server') {
    config.experimental.turbo.resolveAlias = {
      '@': './src',
    };
  }
  
  if (phase === 'phase-production-build') {
    config.experimental.turbo.minify = true;
  }
  
  return config;
};

自定义输出 #

javascript
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      output: {
        path: './build',
        publicPath: '/assets/',
        filename: '[name].[contenthash].js',
        chunkFilename: '[name].[contenthash].chunk.js',
      },
    },
  },
};

代码分割策略 #

动态导入 #

tsx
// 动态导入组件
import dynamic from 'next/dynamic';

const HeavyComponent = dynamic(
  () => import('./HeavyComponent'),
  { 
    loading: () => <p>Loading...</p>,
    ssr: false,
  }
);

export function Page() {
  return (
    <div>
      <h1>My Page</h1>
      <HeavyComponent />
    </div>
  );
}

预加载 #

tsx
import { preload } from 'react-dom';

function Link({ href, children }) {
  const handleMouseEnter = () => {
    preload(href, { as: 'script' });
  };
  
  return (
    <a href={href} onMouseEnter={handleMouseEnter}>
      {children}
    </a>
  );
}

分块策略 #

javascript
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      chunkSplitting: {
        strategy: 'default',
        overrides: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            priority: 10,
          },
          common: {
            minChunks: 2,
            name: 'common',
            priority: 5,
          },
        },
      },
    },
  },
};

服务端渲染优化 #

SSR 配置 #

javascript
// next.config.js
module.exports = {
  experimental: {
    turbo: {
      ssr: {
        external: ['react', 'react-dom'],
        noExternal: ['@my-org/ui'],
      },
    },
  },
};

流式渲染 #

tsx
// app/page.tsx
import { Suspense } from 'react';

async function SlowComponent() {
  await new Promise(resolve => setTimeout(resolve, 2000));
  return <div>Slow content loaded</div>;
}

export default function Page() {
  return (
    <div>
      <h1>Fast content</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <SlowComponent />
      </Suspense>
    </div>
  );
}

边缘运行时 #

tsx
// app/api/route.ts
export const runtime = 'edge';

export async function GET() {
  return new Response(JSON.stringify({ message: 'Hello from edge' }), {
    headers: { 'Content-Type': 'application/json' },
  });
}

安全配置 #

CSP 配置 #

javascript
// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Content-Security-Policy',
            value: "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline';",
          },
        ],
      },
    ];
  },
};

环境变量安全 #

javascript
// next.config.js
module.exports = {
  env: {
    NEXT_PUBLIC_API_URL: process.env.API_URL,
  },
  experimental: {
    turbo: {
      env: {
        // 只在构建时可用的环境变量
        BUILD_TIME: new Date().toISOString(),
      },
    },
  },
};

监控与日志 #

构建监控 #

javascript
// plugins/monitor-plugin.js
module.exports = function monitorPlugin() {
  return {
    name: 'monitor-plugin',
    
    setup(build) {
      const metrics = {
        startTime: 0,
        moduleCount: 0,
        errors: [],
      };
      
      build.onStart(() => {
        metrics.startTime = Date.now();
        metrics.moduleCount = 0;
        metrics.errors = [];
      });
      
      build.onLoad({ filter: /.*/ }, () => {
        metrics.moduleCount++;
        return null;
      });
      
      build.onEnd((result) => {
        const duration = Date.now() - metrics.startTime;
        
        console.log({
          duration: `${duration}ms`,
          modules: metrics.moduleCount,
          errors: result.errors.length,
          warnings: result.warnings.length,
        });
      });
    },
  };
};

错误追踪 #

javascript
// plugins/error-tracking.js
const Sentry = require('@sentry/node');

module.exports = function errorTrackingPlugin() {
  return {
    name: 'error-tracking',
    
    setup(build) {
      build.onEnd((result) => {
        result.errors.forEach(error => {
          Sentry.captureException(new Error(error.text));
        });
      });
    },
  };
};

下一步 #

现在你已经掌握了 Turbopack 的高级用法,接下来学习 最佳实践 了解如何在生产环境中高效使用 Turbopack!

最后更新:2026-03-28