Aller au contenu

Feuille de chaleur Turbopack

Turbopack - Le groupe différentiel

Turbopack est un groupeur incrémental optimisé pour JavaScript et TypeScript, écrit dans Rust. Créé par Vercel, il est conçu pour être le successeur de Webpack avec des mises à jour 10x plus rapides que Vite et 700x plus rapides que Webpack.

Copier toutes les commandes Générer PDF

Sommaire

  • [Introduction] (#introduction)
  • [Installation] (#installation)
  • [Pour commencer] (#getting-started)
  • [Suivant.js Intégration] (#nextjs-integration)
  • [Configuration] (#configuration)
  • [Serveur de développement] (#development-server)
  • [Processus de construction] (#build-process)
  • [Manipulation de l'ensemble] (#asset-handling)
  • [Soutien du CSS] (#css-support)
  • [Type de support de script] (#typescript-support)
  • [variables environnementales] (#environment-variables)
  • [Plugins] (#plugins)
  • [Performance] (#performance)
  • [Migration] (#migration)
  • [Dépannage] (#troubleshooting)
  • [Meilleures pratiques] (#best-practices)

Présentation

Qu'est-ce que Turbopack?

Turbopack est un groupeur incrémental optimisé pour JavaScript et TypeScript, écrit dans Rust par les créateurs de Webpack et Next.js. Il s'agit d'un changement fondamental dans le fonctionnement des faisceaux, en se concentrant sur le calcul progressif pour atteindre une vitesse sans précédent.

Caractéristiques principales

  • Computation indirecte: Seuls les processus qui ont changé
  • Rust Performance: Construit en Rust pour une vitesse maximale
  • Remplacement du module hôte: mises à jour instantanées pendant le développement
  • Cadre Agnostic: Fonctionne avec n'importe quel cadre JavaScript
  • Suivant.js Intégration: Support de première classe pour les applications Next.js
  • TypeScript Native: prise en charge de TypeScript intégrée sans configuration

Critères de performance

# Turbopack vs other bundlers (startup time)
Turbopack: ~1.8s
Vite: ~11.4s
Webpack: ~16.5s

# Hot updates
Turbopack: ~6ms
Vite: ~30ms
Webpack: ~612ms

Installation

Next.js Intégration (Recommandé)

# Create new Next.js app with Turbopack
npx create-next-app@latest my-app

# Navigate to project
cd my-app

# Start with Turbopack
npm run dev -- --turbo
```_

### Projet actuel Next.js
```bash
# Update Next.js to latest version
npm install next@latest

# Start development with Turbopack
npm run dev -- --turbo

# Or update package.json scripts
{
  "scripts": {
    "dev": "next dev --turbo",
    "build": "next build",
    "start": "next start"
  }
}
```_

### Installation autonome (Alpha)
```bash
# Install Turbopack CLI (experimental)
npm install -g @turbo/pack

# Or locally
npm install --save-dev @turbo/pack

Vérifier l'installation

# Check Next.js version
npx next --version

# Verify Turbopack is working
npm run dev -- --turbo
# Look for "Turbopack" in the startup logs

Commencer

Configuration Basic Next.js avec Turbopack

# Create new project
npx create-next-app@latest my-turbo-app --typescript --tailwind --eslint --app

# Navigate to project
cd my-turbo-app

# Start with Turbopack
npm run dev -- --turbo

Structure du projet

my-turbo-app/
├── app/                 # App Router (Next.js 13+)
   ├── globals.css
   ├── layout.tsx
   ├── page.tsx
   └── components/
├── public/              # Static assets
├── next.config.js       # Next.js configuration
├── package.json
├── tailwind.config.js
└── tsconfig.json

Configuration de base

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    turbo: {
      // Turbopack configuration
      loaders: {
        '.svg': ['@svgr/webpack'],
      },
      resolveAlias: {
        '@': './src',
        '@components': './src/components',
      },
    },
  },
}

module.exports = nextConfig

Première composante

// app/components/Counter.tsx
'use client'

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div className="p-4 border rounded-lg">
      <h2 className="text-xl font-bold mb-4">Counter: {count}</h2>
      <div className="space-x-2">
        <button 
          onClick={() => setCount(count + 1)}
          className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
        >
          Increment
        </button>
        <button 
          onClick={() => setCount(count - 1)}
          className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
        >
          Decrement
        </button>
      </div>
    </div>
  )
}

Next.js Intégration

Routeur App avec Turbopack

// app/layout.tsx
import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Turbopack App',
  description: 'Built with Next.js and Turbopack',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <main className="container mx-auto px-4 py-8">
          {children}
        </main>
      </body>
    </html>
  )
}
// app/page.tsx
import Counter from './components/Counter'
import Link from 'next/link'

export default function Home() {
  return (
    <div className="space-y-8">
      <h1 className="text-4xl font-bold text-center">
        Welcome to Turbopack
      </h1>

      <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
        <div className="space-y-4">
          <h2 className="text-2xl font-semibold">Features</h2>
          <ul className="list-disc list-inside space-y-2">
            <li>⚡ Lightning fast HMR</li>
            <li>🦀 Built in Rust</li>
            <li>📦 Incremental bundling</li>
            <li>🔥 Hot module replacement</li>
          </ul>
        </div>

        <Counter />
      </div>

      <div className="text-center">
        <Link 
          href="/about" 
          className="text-blue-500 hover:text-blue-700 underline"
        >
          Learn more about Turbopack
        </Link>
      </div>
    </div>
  )
}

Pages Routeur avec Turbopack

// pages/_app.tsx
import type { AppProps } from 'next/app'
import '../styles/globals.css'

export default function App({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}
// pages/index.tsx
import { useState } from 'react'
import Head from 'next/head'

export default function Home() {
  const [message, setMessage] = useState('Hello Turbopack!')

  return (
    <>
      <Head>
        <title>Turbopack Demo</title>
        <meta name="description" content="Turbopack demonstration" />
      </Head>

      <div className="container mx-auto px-4 py-8">
        <h1 className="text-4xl font-bold mb-8">{message}</h1>

        <button
          onClick={() => setMessage('Turbopack is fast!')}
          className="px-6 py-3 bg-green-500 text-white rounded-lg hover:bg-green-600"
        >
          Update Message
        </button>
      </div>
    </>
  )
}

Routes des API

// app/api/hello/route.ts (App Router)
import { NextRequest, NextResponse } from 'next/server'

export async function GET(request: NextRequest) {
  return NextResponse.json({ 
    message: 'Hello from Turbopack API!',
    timestamp: new Date().toISOString()
  })
}

export async function POST(request: NextRequest) {
  const body = await request.json()

  return NextResponse.json({
    received: body,
    processed: true
  })
}
// pages/api/hello.ts (Pages Router)
import type { NextApiRequest, NextApiResponse } from 'next'

type Data = {
  message: string
  timestamp: string
}

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  res.status(200).json({ 
    message: 'Hello from Turbopack API!',
    timestamp: new Date().toISOString()
  })
}

Configuration

Configuration basique du Turbopack

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    turbo: {
      // Enable Turbopack
      rules: {
        // Custom rules for file processing
        '*.svg': {
          loaders: ['@svgr/webpack'],
          as: '*.js',
        },
      },

      // Resolve aliases
      resolveAlias: {
        '@': './src',
        '@components': './src/components',
        '@utils': './src/utils',
        '@styles': './src/styles',
      },

      // Resolve extensions
      resolveExtensions: [
        '.mdx',
        '.tsx',
        '.ts',
        '.jsx',
        '.js',
        '.mjs',
        '.json',
      ],

      // Module resolution
      resolveModules: [
        'node_modules',
        './src',
      ],
    },
  },
}

module.exports = nextConfig

Configuration avancée

// next.config.js
const nextConfig = {
  experimental: {
    turbo: {
      // Loader configuration
      loaders: {
        '.md': ['raw-loader'],
        '.svg': ['@svgr/webpack'],
        '.graphql': ['graphql-tag/loader'],
      },

      // Resolve configuration
      resolveAlias: {
        '@': './src',
        '@components': './src/components',
        '@hooks': './src/hooks',
        '@utils': './src/utils',
        '@types': './src/types',
        '@styles': './src/styles',
        '@public': './public',
      },

      // Memory optimization
      memoryLimit: 4096,

      // Experimental features
      useSwcLoader: true,
      optimizeCss: true,
    },

    // Other Next.js experimental features
    appDir: true,
    serverComponentsExternalPackages: ['@prisma/client'],
  },

  // Standard Next.js configuration
  images: {
    domains: ['example.com'],
  },

  env: {
    CUSTOM_KEY: process.env.CUSTOM_KEY,
  },
}

module.exports = nextConfig

Configuration du script de type

// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "es6"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"],
      "@utils/*": ["./src/utils/*"],
      "@types/*": ["./src/types/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

Serveur de développement

Démarrer le serveur de développement

# Start with Turbopack
npm run dev -- --turbo

# Custom port
npm run dev -- --turbo --port 3001

# Custom hostname
npm run dev -- --turbo --hostname 0.0.0.0

# Enable experimental features
npm run dev -- --turbo --experimental-https

Options de serveur de développement

// package.json
{
  "scripts": {
    "dev": "next dev --turbo",
    "dev:debug": "next dev --turbo --inspect",
    "dev:port": "next dev --turbo --port 3001",
    "dev:https": "next dev --turbo --experimental-https",
    "build": "next build",
    "start": "next start"
  }
}

Remplacement du module à chaud

// components/LiveComponent.tsx
'use client'

import { useState, useEffect } from 'react'

export default function LiveComponent() {
  const [timestamp, setTimestamp] = useState(new Date().toLocaleTimeString())

  useEffect(() => {
    const interval = setInterval(() => {
      setTimestamp(new Date().toLocaleTimeString())
    }, 1000)

    return () => clearInterval(interval)
  }, [])

  return (
    <div className="p-4 border-2 border-dashed border-blue-300 rounded-lg">
      <h3 className="text-lg font-semibold mb-2">Live Component</h3>
      <p className="text-sm text-gray-600">
        Current time: {timestamp}
      </p>
      <p className="text-xs text-green-600 mt-2">
        ✅ This component updates instantly with Turbopack HMR
      </p>
    </div>
  )
}

Débogage du développement

# Enable debugging
npm run dev -- --turbo --inspect

# Debug with specific port
npm run dev -- --turbo --inspect=9229

# Verbose logging
DEBUG=turbopack* npm run dev -- --turbo

Construire le processus

Construction de production

# Build for production
npm run build

# Build with analysis
npm run build -- --analyze

# Build with debug info
npm run build -- --debug

Configuration de construction

// next.config.js
const nextConfig = {
  // Production optimizations
  compiler: {
    removeConsole: process.env.NODE_ENV === 'production',
  },

  // Output configuration
  output: 'standalone', // For Docker deployments

  // Image optimization
  images: {
    unoptimized: false,
    domains: ['example.com'],
  },

  // Experimental Turbopack for build (future)
  experimental: {
    turbo: {
      // Build-specific configuration
    },
  },
}

module.exports = nextConfig

Analyse de construction

# Install bundle analyzer
npm install --save-dev @next/bundle-analyzer

# Configure analyzer
# next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})

module.exports = withBundleAnalyzer(nextConfig)

# Run analysis
ANALYZE=true npm run build

Scripts de construction personnalisés

// package.json
{
  "scripts": {
    "build": "next build",
    "build:analyze": "ANALYZE=true next build",
    "build:standalone": "next build && next export",
    "build:debug": "DEBUG=1 next build",
    "postbuild": "next-sitemap"
  }
}

Gestion des actifs

Actifs statiques

// components/ImageComponent.tsx
import Image from 'next/image'
import logo from '../public/logo.png'

export default function ImageComponent() {
  return (
    <div className="space-y-4">
      {/* Static import */}
      <Image
        src={logo}
        alt="Logo"
        width={200}
        height={100}
        priority
      />

      {/* Dynamic import */}
      <Image
        src="/images/hero.jpg"
        alt="Hero"
        width={800}
        height={400}
        className="rounded-lg"
      />
    </div>
  )
}

SVG Traitement

// next.config.js
const nextConfig = {
  experimental: {
    turbo: {
      rules: {
        '*.svg': {
          loaders: ['@svgr/webpack'],
          as: '*.js',
        },
      },
    },
  },
}
// components/IconComponent.tsx
import { ReactComponent as Icon } from '../assets/icon.svg'

export default function IconComponent() {
  return (
    <div className="flex items-center space-x-2">
      <Icon className="w-6 h-6 text-blue-500" />
      <span>SVG Icon</span>
    </div>
  )
}

Chargement de la police

// app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
})

const robotoMono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-roboto-mono',
})

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={`${inter.className} ${robotoMono.variable}`}>
      <body>{children}</body>
    </html>
  )
}

Importations dynamiques

// components/DynamicComponent.tsx
import dynamic from 'next/dynamic'
import { Suspense } from 'react'

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

const ChartComponent = dynamic(() => import('./Chart'), {
  suspense: true,
})

export default function DynamicComponent() {
  return (
    <div className="space-y-8">
      <HeavyComponent />

      <Suspense fallback={<div>Loading chart...</div>}>
        <ChartComponent />
      </Suspense>
    </div>
  )
}

CSS Appui

Tailfind CSS

# Install Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}',
    './app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      colors: {
        primary: '#3b82f6',
        secondary: '#64748b',
      },
    },
  },
  plugins: [],
}
/* app/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .btn-primary {
    @apply px-4 py-2 bg-primary text-white rounded-lg hover:bg-blue-600 transition-colors;
  }
}

CSS Modules

/* components/Button.module.css */
.button {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 0.375rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
}

.primary {
  background-color: #3b82f6;
  color: white;
}

.primary:hover {
  background-color: #2563eb;
}

.secondary {
  background-color: #64748b;
  color: white;
}
// components/Button.tsx
import styles from './Button.module.css'
import { ReactNode } from 'react'

interface ButtonProps {
  children: ReactNode
  variant?: 'primary' | 'secondary'
  onClick?: () => void
}

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

Composants stylés

# Install styled-components
npm install styled-components
npm install -D @types/styled-components
// components/StyledButton.tsx
'use client'

import styled from 'styled-components'

const StyledButton = styled.button<{ variant: 'primary' | 'secondary' }>`
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 0.375rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;

  background-color: ${props => 
    props.variant === 'primary' ? '#3b82f6' : '#64748b'
  };
  color: white;

  &:hover {
    background-color: ${props => 
      props.variant === 'primary' ? '#2563eb' : '#475569'
    };
  }
`

export default function Button({ 
  children, 
  variant = 'primary',
  ...props 
}: {
  children: React.ReactNode
  variant?: 'primary' | 'secondary'
  onClick?: () => void
}) {
  return (
    <StyledButton variant={variant} {...props}>
      {children}
    </StyledButton>
  )
}

Sass/SCSS Appui

# Install Sass
npm install -D sass
// styles/components.scss
$primary-color: #3b82f6;
$secondary-color: #64748b;
$border-radius: 0.375rem;

@mixin button-base {
  padding: 0.5rem 1rem;
  border: none;
  border-radius: $border-radius;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.2s;
}

.btn {
  @include button-base;

  &--primary {
    background-color: $primary-color;
    color: white;

    &:hover {
      background-color: darken($primary-color, 10%);
    }
  }

  &--secondary {
    background-color: $secondary-color;
    color: white;

    &:hover {
      background-color: darken($secondary-color, 10%);
    }
  }
}

Support de script de type

Configuration du script de type

// tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "es6"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"],
      "@utils/*": ["./src/utils/*"],
      "@types/*": ["./src/types/*"],
      "@hooks/*": ["./src/hooks/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

Définitions de type

// src/types/index.ts
export interface User {
  id: string
  name: string
  email: string
  avatar?: string
  createdAt: Date
  updatedAt: Date
}

export interface Post {
  id: string
  title: string
  content: string
  author: User
  published: boolean
  tags: string[]
  createdAt: Date
  updatedAt: Date
}

export interface ApiResponse<T> {
  data: T
  message: string
  status: 'success' | 'error'
}

export type Theme = 'light' | 'dark' | 'system'

export interface AppConfig {
  apiUrl: string
  theme: Theme
  features: {
    auth: boolean
    analytics: boolean
    notifications: boolean
  }
}

Composants dactylographiés

// components/UserCard.tsx
import { User } from '@/types'
import Image from 'next/image'

interface UserCardProps {
  user: User
  showEmail?: boolean
  onEdit?: (user: User) => void
  className?: string
}

export default function UserCard({ 
  user, 
  showEmail = false, 
  onEdit,
  className = ''
}: UserCardProps) {
  return (
    <div className={`p-4 border rounded-lg ${className}`}>
      <div className="flex items-center space-x-3">
        {user.avatar && (
          <Image
            src={user.avatar}
            alt={user.name}
            width={40}
            height={40}
            className="rounded-full"
          />
        )}

        <div>
          <h3 className="font-semibold">{user.name}</h3>
          {showEmail && (
            <p className="text-sm text-gray-600">{user.email}</p>
          )}
        </div>
      </div>

      {onEdit && (
        <button
          onClick={() => onEdit(user)}
          className="mt-3 text-blue-500 hover:text-blue-700"
        >
          Edit User
        </button>
      )}
    </div>
  )
}

Crochets personnalisés avec TypeScript

// hooks/useApi.ts
import { useState, useEffect } from 'react'
import { ApiResponse } from '@/types'

interface UseApiOptions {
  immediate?: boolean
}

export function useApi<T>(
  url: string, 
  options: UseApiOptions = {}
) {
  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const fetchData = async () => {
    setLoading(true)
    setError(null)

    try {
      const response = await fetch(url)
      const result: ApiResponse<T> = await response.json()

      if (result.status === 'success') {
        setData(result.data)
      } else {
        setError(result.message)
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : 'An error occurred')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    if (options.immediate !== false) {
      fetchData()
    }
  }, [url])

  return { data, loading, error, refetch: fetchData }
}

Variables d'environnement

Configuration de l'environnement

# .env.local
NEXT_PUBLIC_API_URL=http://localhost:3001/api
NEXT_PUBLIC_APP_NAME=Turbopack App
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
SECRET_KEY=your-secret-key
# .env.production
NEXT_PUBLIC_API_URL=https://api.production.com
NEXT_PUBLIC_APP_NAME=Production App
DATABASE_URL=postgresql://user:password@prod-db:5432/mydb
SECRET_KEY=production-secret-key

Utilisation des variables d'environnement

// lib/config.ts
export const config = {
  apiUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api',
  appName: process.env.NEXT_PUBLIC_APP_NAME || 'My App',
  isDevelopment: process.env.NODE_ENV === 'development',
  isProduction: process.env.NODE_ENV === 'production',
}

// Server-side only
export const serverConfig = {
  databaseUrl: process.env.DATABASE_URL!,
  secretKey: process.env.SECRET_KEY!,
}
// components/ApiExample.tsx
'use client'

import { config } from '@/lib/config'
import { useEffect, useState } from 'react'

export default function ApiExample() {
  const [data, setData] = useState(null)

  useEffect(() => {
    fetch(`${config.apiUrl}/hello`)
      .then(res => res.json())
      .then(setData)
  }, [])

  return (
    <div className="p-4 border rounded-lg">
      <h3 className="font-semibold mb-2">API Response</h3>
      <p className="text-sm text-gray-600 mb-2">
        API URL: {config.apiUrl}
      </p>
      <pre className="text-xs bg-gray-100 p-2 rounded">
        {JSON.stringify(data, null, 2)}
      </pre>
    </div>
  )
}

Configuration d'exécution

// next.config.js
const nextConfig = {
  env: {
    CUSTOM_KEY: process.env.CUSTOM_KEY,
    BUILD_TIME: new Date().toISOString(),
  },

  publicRuntimeConfig: {
    // Available on both server and client
    apiUrl: process.env.API_URL,
  },

  serverRuntimeConfig: {
    // Only available on server
    secretKey: process.env.SECRET_KEY,
  },
}

module.exports = nextConfig

Greffons

Prise en charge actuelle du plugin

// next.config.js
const nextConfig = {
  experimental: {
    turbo: {
      // Loader configuration (limited plugin support)
      loaders: {
        '.svg': ['@svgr/webpack'],
        '.md': ['raw-loader'],
        '.graphql': ['graphql-tag/loader'],
      },

      // Rules for file processing
      rules: {
        '*.svg': {
          loaders: ['@svgr/webpack'],
          as: '*.js',
        },
      },
    },
  },
}

Plugins Webpack (Fallback)

// next.config.js
const nextConfig = {
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    // Custom webpack configuration for features not yet supported in Turbopack
    config.plugins.push(
      new webpack.DefinePlugin({
        __BUILD_ID__: JSON.stringify(buildId),
      })
    )

    return config
  },

  experimental: {
    turbo: {
      // Turbopack configuration
    },
  },
}

Futur système de plugin

// Future Turbopack plugin API (conceptual)
const nextConfig = {
  experimental: {
    turbo: {
      plugins: [
        // Future plugin system
        '@turbopack/plugin-sass',
        '@turbopack/plugin-postcss',
        ['@turbopack/plugin-custom', { options: {} }],
      ],
    },
  },
}

Rendement

Critères de performance

# Development server startup
Turbopack: ~1.8s (10x faster than Vite)
Vite: ~11.4s
Webpack: ~16.5s

# Hot Module Replacement
Turbopack: ~6ms (5x faster than Vite)
Vite: ~30ms
Webpack: ~612ms (100x slower)

# Large codebase (30k modules)
Turbopack: ~1.2s startup
Webpack: ~30s startup

Surveillance de la performance

// components/PerformanceMonitor.tsx
'use client'

import { useEffect, useState } from 'react'

export default function PerformanceMonitor() {
  const [metrics, setMetrics] = useState<any>(null)

  useEffect(() => {
    if (typeof window !== 'undefined' && 'performance' in window) {
      const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming

      setMetrics({
        domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
        loadComplete: navigation.loadEventEnd - navigation.loadEventStart,
        firstPaint: performance.getEntriesByName('first-paint')[0]?.startTime,
        firstContentfulPaint: performance.getEntriesByName('first-contentful-paint')[0]?.startTime,
      })
    }
  }, [])

  if (!metrics) return null

  return (
    <div className="p-4 bg-gray-100 rounded-lg">
      <h3 className="font-semibold mb-2">Performance Metrics</h3>
      <div className="grid grid-cols-2 gap-2 text-sm">
        <div>DOM Content Loaded: {metrics.domContentLoaded?.toFixed(2)}ms</div>
        <div>Load Complete: {metrics.loadComplete?.toFixed(2)}ms</div>
        <div>First Paint: {metrics.firstPaint?.toFixed(2)}ms</div>
        <div>First Contentful Paint: {metrics.firstContentfulPaint?.toFixed(2)}ms</div>
      </div>
    </div>
  )
}

Analyse de l'ensemble

# Install bundle analyzer
npm install --save-dev @next/bundle-analyzer

# Analyze bundle
ANALYZE=true npm run build
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})

const nextConfig = {
  experimental: {
    turbo: {
      // Turbopack configuration
    },
  },
}

module.exports = withBundleAnalyzer(nextConfig)

Migrations

De Webpack à Turbopack

# Update Next.js to latest version
npm install next@latest

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

Liste de contrôle des migrations

  • Mettre à jour Next.js vers la version 13.5+
  • Ajouter --turbo drapeau au script dev
  • Tester toutes les caractéristiques du développement
  • Mettre à jour la configuration du paquet web personnalisé
  • Vérifier que tous les chargeurs fonctionnent correctement
  • Essai de remplacement du module à chaud
  • Vérifier la compatibilité du processus de construction

Questions communes en matière de migration

// Issue: Custom webpack loaders not supported
// Solution: Use Turbopack loader configuration
const nextConfig = {
  experimental: {
    turbo: {
      loaders: {
        '.custom': ['custom-loader'],
      },
    },
  },

  // Fallback to webpack for unsupported features
  webpack: (config) => {
    // Custom webpack configuration
    return config
  },
}

Migration progressive

// next.config.js
const nextConfig = {
  experimental: {
    turbo: {
      // Enable Turbopack for development only
    },
  },

  // Keep webpack configuration for production builds
  webpack: (config, { dev }) => {
    if (!dev) {
      // Production webpack configuration
    }
    return config
  },
}

Dépannage

Questions communes

Turbopack ne démarre pas

# Check Next.js version
npx next --version

# Ensure version 13.5+
npm install next@latest

# Clear cache
rm -rf .next
npm run dev -- --turbo

Résolution des problèmes

// next.config.js
const nextConfig = {
  experimental: {
    turbo: {
      resolveAlias: {
        '@': './src',
        '@components': './src/components',
      },
      resolveExtensions: ['.tsx', '.ts', '.jsx', '.js'],
    },
  },
}

La recharge à chaud ne fonctionne pas

# Check file watching limits (Linux)
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Restart development server
npm run dev -- --turbo

Créer des erreurs

# Enable verbose logging
DEBUG=turbopack* npm run dev -- --turbo

# Check for unsupported features
npm run build

Configuration de débogage

// next.config.js
const nextConfig = {
  experimental: {
    turbo: {
      // Enable debug mode
      logLevel: 'debug',

      // Memory limit
      memoryLimit: 4096,
    },
  },

  // Enable source maps
  productionBrowserSourceMaps: true,
}

Meilleures pratiques

Structure du projet

# Recommended structure for Turbopack projects
src/
├── app/                 # App Router pages
   ├── globals.css
   ├── layout.tsx
   ├── page.tsx
   └── (routes)/
├── components/          # Reusable components
   ├── ui/             # Basic UI components
   ├── forms/          # Form components
   └── layout/         # Layout components
├── hooks/              # Custom hooks
├── lib/                # Utility libraries
├── types/              # TypeScript types
├── styles/             # Global styles
└── utils/              # Utility functions

Meilleures pratiques en matière de rendement

  • Utilisez Turbopack pour le développement pour obtenir des avantages de vitesse maximum
  • Mise en œuvre du fractionnement correct du code avec les importations dynamiques
  • Optimiser les images avec le composant Next.js Image
  • Utilisez TypeScript pour une meilleure expérience de développement
  • ** Taille du faisceau de moniteur** avec analyseur de faisceau

Meilleures pratiques de développement

  • Démarrer avec --turbo flag pour le développement
  • Utilisation des importations absolues avec alias de trajectoire
  • **Mise en œuvre des limites d'erreur appropriées* *
  • Utilisez React DevTools pour le débogage
  • Testez régulièrement la fonctionnalité de recharge à chaud

Meilleures pratiques de production

  • Construits d'essai avant déploiement
  • Performance du moniteur
  • Utiliser les variables d'environnement pour la configuration
  • Mise en oeuvre de stratégies appropriées de mise en cache
  • ** Taille du faisceau de moniteurs** et performances

Résumé

Turbopack représente l'avenir du regroupement JavaScript avec son approche progressive et ses performances alimentées par Rust. Les principales caractéristiques sont les suivantes :

  • Bundling incrémental: Seuls les processus de fichiers modifiés pour la vitesse maximale
  • Rust Performance: Construit dans Rust pour des mises à jour 10x plus rapides que Vite
  • Suivant.js Intégration: Support de première classe pour les applications Next.js
  • Remplacement du module hôte: mises à jour instantanées pendant le développement
  • TypeScript Native: prise en charge de TypeScript intégrée sans configuration
  • Cadre Agnostic: Fonctionne avec n'importe quel cadre JavaScript
  • Future-Proof: Conçu pour remplacer Webpack en tant que conteneur standard

En adoptant Turbopack, vous pouvez améliorer considérablement votre expérience de développement avec des constructions plus rapides, des recharges instantanées et un flux de travail de développement plus réactif.