Turbopack Cheatsheet¶
¶
¶
■h1 títuloTurbopack - The Incremental Bundler "Clase de inscripción" Turbopack es un paquete incremental optimizado para JavaScript y TypeScript, escrito en Rust. Creado por Vercel, está diseñado para ser el sucesor de Webpack con 10 actualizaciones más rápidas que Vite y 700x más rápido que Webpack. ▪/p] ■/div titulada
¶
########################################################################################################################################################################################################################################################## Copiar todos los comandos¶
########################################################################################################################################################################################################################################################## Generar PDF seleccionado/button¶
■/div titulada ■/div titulada
Cuadro de contenidos¶
- Introducción
- Instalación
- Empezar
- Siguiente.js Integración
- Configuración
- Development Server
- Proceso de construcción
- Asset Handling
- CSS Support
- TypeScript Support
- Varias del medio ambiente
- Plugins
- Performance
- Migración
- Solucionando
- Las mejores prácticas
Introducción¶
¿Qué es Turbopack?¶
Turbopack es un paquete incremental optimizado para JavaScript y TypeScript, escrito en Rust por los creadores de Webpack y Next.js. Representa un cambio fundamental en cómo funcionan los usuarios, centrándose en la computación incremental para lograr una velocidad sin precedentes.
Características clave¶
- Computación Incremental: Sólo procesos lo que ha cambiado
- Rust Performance: Construido en Rust para velocidad máxima
- Reemplazamiento del módulo de arranque: Actualizaciones instantáneas durante el desarrollo
- Framework Agnostic: Funciona con cualquier marco JavaScript
- Siguiente.js Integración: Apoyo de primera clase para aplicaciones Next.js
- TypeScript Native: Soporte de tipoScript incorporado sin configuración
Parámetros de rendimiento¶
# Turbopack vs other bundlers (startup time)
Turbopack: ~1.8s
Vite: ~11.4s
Webpack: ~16.5s
# Hot updates
Turbopack: ~6ms
Vite: ~30ms
Webpack: ~612ms
Instalación¶
Next.js Integration (Recomendado)¶
# 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
Proyecto existente Next.js¶
# 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"
}
}
Instalación independiente (Alpha)¶
# Install Turbopack CLI (experimental)
npm install -g @turbo/pack
# Or locally
npm install --save-dev @turbo/pack
Verificar la instalación¶
# Check Next.js version
npx next --version
# Verify Turbopack is working
npm run dev -- --turbo
# Look for "Turbopack" in the startup logs
Comienzo¶
Basic Next.js Configuración con 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
Estructura del proyecto¶
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
Configuración básica¶
// 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
Primer componente¶
// 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 Integration¶
App Router con 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 Router con 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>
</>
)
}
API Routes¶
// 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()
})
}
Configuración¶
Configuración básica de 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
Configuración avanzada¶
// 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
Configuración TipoScript¶
// 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"]
}
Development Server¶
Start Development Server¶
# 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
Opciones de desarrollo del servidor¶
// 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"
}
}
Reemplazamiento del módulo caliente¶
// 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>
)
}
Development Debugging¶
# 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
Proceso de construcción¶
Producción¶
# Build for production
npm run build
# Build with analysis
npm run build -- --analyze
# Build with debug info
npm run build -- --debug
Configuración de construcción¶
// 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
Análisis de la construcción¶
# 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
Guiones de construcción personalizados¶
// 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"
}
}
Asset Handling¶
Activos estaticos¶
// 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 Manejo¶
// 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>
)
}
Fuente¶
// 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>
)
}
Importaciones dinámicas¶
// 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 Apoyo¶
Tailwind CSS¶
// 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 Módulos¶
/* 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>
)
}
Componentes de estilo¶
// 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 Apoyo¶
// 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%);
}
}
}
Soporte TipoScript¶
Configuración TipoScript¶
// 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"]
}
Definición¶
// 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
}
}
Componentes clasificados¶
// 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>
)
}
```_
### Ganchos personalizados con TipoScript
```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 }
}
Medio ambiente¶
Configuración del medio ambiente¶
# .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
Utilización de variables ambientales¶
// 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>
)
}
```_
### Configuración de tiempo de ejecución
```javascript
// 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
Plugins¶
Soporte de plugin actual¶
// 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
},
},
}
Future Plugin System¶
// Future Turbopack plugin API (conceptual)
const nextConfig = {
experimental: {
turbo: {
plugins: [
// Future plugin system
'@turbopack/plugin-sass',
'@turbopack/plugin-postcss',
['@turbopack/plugin-custom', { options: {} }],
],
},
},
}
Ejecución¶
Parámetros de rendimiento¶
# 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
Supervisión de la ejecución¶
// 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>
)
}
Bundle Analysis¶
# 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)
Migración¶
De Webpack a 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"
}
}
Lista de control de migración¶
- Actualizar Next.js a la versión 13.5+
- Añadir
--turbo_ flag to dev script - Prueba todas las características en el desarrollo
- Actualizar configuración de webpack personalizado
- Verificar todos los cargadores funcionan correctamente
- Prueba de sustitución del módulo caliente
- Comprobar compatibilidad del proceso de construcción
Cuestiones de migración comunes¶
// 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
},
}
Migración gradual¶
// 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
},
}
Solución de problemas¶
Cuestiones comunes¶
Turbopack no empieza¶
# Check Next.js version
npx next --version
# Ensure version 13.5+
npm install next@latest
# Clear cache
rm -rf .next
npm run dev -- --turbo
Cuestiones relativas a la resolución del módulo¶
// next.config.js
const nextConfig = {
experimental: {
turbo: {
resolveAlias: {
'@': './src',
'@components': './src/components',
},
resolveExtensions: ['.tsx', '.ts', '.jsx', '.js'],
},
},
}
Recarga caliente no funciona¶
# 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
Errores de construcción¶
# Enable verbose logging
DEBUG=turbopack* npm run dev -- --turbo
# Check for unsupported features
npm run build
Configuración de depuración¶
// next.config.js
const nextConfig = {
experimental: {
turbo: {
// Enable debug mode
logLevel: 'debug',
// Memory limit
memoryLimit: 4096,
},
},
// Enable source maps
productionBrowserSourceMaps: true,
}
Buenas prácticas¶
Estructura del proyecto¶
# 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
Prácticas óptimas de rendimiento¶
- Use Turbopack para el desarrollo para obtener beneficios de máxima velocidad
- Ejecución de código adecuado con importaciones dinámicas
- Optimizar imágenes con el componente Next.js Imagen
- Use TipoScript para una mejor experiencia de desarrollo
- ** Tamaño del paquete de monitor** con analizador de paquetes
Development Best Practices¶
- Empieza con la bandera __CODE_BLOCK_66_ para el desarrollo
- Use importaciones absolutas con alias de ruta
- **Implement proper error boundaries* *
- Use React DevTools para depurar
- El mejor hot reload funcionalidad regularmente
Producción Buenas Prácticas¶
- Test construye antes del despliegue
- Rendimiento del monitor métricas
- Utilizar variables de entorno para la configuración
- Estrategias de caché adecuadas
- ** Tamaño del paquete de monitor** y rendimiento
-...
Resumen¶
Turbopack representa el futuro de la agrupación de JavaScript con su enfoque incremental y el rendimiento de Rust. Las características principales incluyen:
-
Incremental Bundling # Sólo los procesos cambiaron archivos para la velocidad máxima¶
- Rust Performance: Construido en Rust para 10 actualizaciones más rápidas que Vite
- Siguiente.js Integración: Apoyo de primera clase para aplicaciones Next.js
- Reemplazamiento del módulo de arranque: Actualizaciones instantáneas durante el desarrollo
- TypeScript Native: Soporte de tipoScript incorporado sin configuración
- Framework Agnostic: Funciona con cualquier marco JavaScript
- Future-Proof: Diseñado para reemplazar Webpack como el paquete estándar
Mediante la adopción de Turbopack, puede mejorar significativamente su experiencia de desarrollo con construcciones más rápidas, recargas calientes instantáneas y un flujo de trabajo de desarrollo más sensible.
" copia de la funciónToClipboard() {} comandos const = document.querySelectorAll('code'); que todos losCommands = '; comandos. paraCada(cmd = confianza allCommands += cmd.textContent + '\n'); navigator.clipboard.writeText(allCommands); alerta ('Todos los comandos copiados a portapapeles!'); }
función generaPDF() { ventana.print(); } ■/script título