🎯 Рекомендуемые коллекции
Балансированные коллекции примеров кода из различных категорий, которые вы можете исследовать
Примеры Turbopack
Примеры пакета Turbopack, включая конфигурацию, оптимизацию производительности и интеграцию с современными веб-фреймворками
💻 Базовая настройка Turbopack typescript
🟢 simple
⭐
Фундаментальная конфигурация Turbopack и базовые паттерны использования для веб-приложений
⏱️ 15 min
🏷️ turbopack, nextjs, setup, development
Prerequisites:
Node.js, npm/yarn, Basic React knowledge
// Turbopack Basic Setup Examples
// Turbopack is an incremental bundler written in Rust for the web
// 1. Next.js with Turbopack
// package.json
{
"name": "my-turbopack-app",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev --turbo",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "^14.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"eslint": "^8.0.0",
"eslint-config-next": "^14.0.0",
"typescript": "^5.0.0"
}
}
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
turbo: {
// Turbopack configuration
loaders: {
'.svg': ['@svgr/webpack'],
},
},
},
// Enable Turbopack for development
turbo: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
}
module.exports = nextConfig
// 2. Basic TypeScript Configuration
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["dom", "dom.iterable", "ES2020"],
"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"
}
],
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/lib/*": ["./src/lib/*"],
"@/styles/*": ["./src/styles/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
// 3. Basic App Structure
// src/app/layout.tsx
import './globals.css'
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
export const metadata = {
title: 'Turbopack App',
description: 'A Next.js app powered by Turbopack',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>
<main className="min-h-screen bg-gray-50">
<nav className="bg-white shadow-sm border-b">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex items-center">
<h1 className="text-xl font-bold">Turbopack App</h1>
</div>
<div className="flex items-center space-x-4">
<a href="/" className="text-gray-600 hover:text-gray-900">
Home
</a>
<a href="/about" className="text-gray-600 hover:text-gray-900">
About
</a>
</div>
</div>
</div>
</nav>
{children}
</main>
</body>
</html>
)
}
// src/app/page.tsx
export default function HomePage() {
return (
<div className="py-12">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center">
<h1 className="text-4xl font-bold text-gray-900 sm:text-5xl">
Welcome to Turbopack
</h1>
<p className="mt-6 text-xl text-gray-600 max-w-3xl mx-auto">
Experience lightning-fast builds with Turbopack, the incremental bundler
built for modern web development.
</p>
<div className="mt-10 flex justify-center space-x-4">
<button className="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700">
Get Started
</button>
<button className="border border-gray-300 text-gray-700 px-6 py-3 rounded-lg hover:bg-gray-50">
Learn More
</button>
</div>
</div>
<div className="mt-16 grid grid-cols-1 md:grid-cols-3 gap-8">
<div className="text-center">
<div className="text-3xl font-bold text-blue-600">10x</div>
<div className="mt-2 text-lg text-gray-600">Faster Builds</div>
</div>
<div className="text-center">
<div className="text-3xl font-bold text-green-600">99%</div>
<div className="mt-2 text-lg text-gray-600">Reliability</div>
</div>
<div className="text-center">
<div className="text-3xl font-bold text-purple-600">5x</div>
<div className="mt-2 text-lg text-gray-600">Better DX</div>
</div>
</div>
</div>
</div>
)
}
// src/app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Custom CSS for Turbopack app */
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.turbopack-animations {
animation: fadeInUp 0.6s ease-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
// 4. Component Examples
// src/components/TurbopackFeatures.tsx
import { useState } from 'react'
interface Feature {
title: string
description: string
icon: string
benefits: string[]
}
const features: Feature[] = [
{
title: 'Incremental Builds',
description: 'Only rebuild what changed with Turbopack's intelligent dependency tracking',
icon: '⚡',
benefits: ['10-100x faster builds', 'Minimal rebuilds', 'Smart caching']
},
{
title: 'Rust Performance',
description: 'Built with Rust for maximum performance and memory efficiency',
icon: '🦀',
benefits: ['Blazing fast', 'Memory efficient', 'Reliable']
},
{
title: 'Modern ESM Support',
description: 'First-class support for ES modules and modern JavaScript features',
icon: '📦',
benefits: ['Tree shaking', 'Code splitting', 'Modern syntax']
},
{
title: 'TypeScript Integration',
description: 'Deep TypeScript integration with zero-config setup',
icon: '📘',
benefits: ['Type checking', 'IntelliSense', 'Error reporting']
},
{
title: 'CSS Modules',
description: 'Built-in support for CSS modules and CSS-in-JS',
icon: '🎨',
benefits: ['Scoped styles', 'CSS-in-JS', 'PostCSS support']
},
{
title: 'Hot Module Replacement',
description: 'Lightning-fast HMR for instant development feedback',
icon: '🔄',
benefits: ['State preservation', 'Instant updates', 'Dev tooling']
}
]
export default function TurbopackFeatures() {
const [selectedFeature, setSelectedFeature] = useState<number | null>(null)
return (
<div className="py-16 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-center text-gray-900 mb-12">
Turbopack Features
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{features.map((feature, index) => (
<div
key={index}
className={`bg-white rounded-lg shadow-lg p-6 cursor-pointer transition-all duration-300 hover:shadow-xl ${
selectedFeature === index ? 'ring-2 ring-blue-500' : ''
}`}
onClick={() => setSelectedFeature(selectedFeature === index ? null : index)}
>
<div className="text-4xl mb-4">{feature.icon}</div>
<h3 className="text-xl font-semibold text-gray-900 mb-2">
{feature.title}
</h3>
<p className="text-gray-600 mb-4">{feature.description}</p>
{selectedFeature === index && (
<div className="mt-4 pt-4 border-t">
<h4 className="font-semibold text-gray-900 mb-2">Benefits:</h4>
<ul className="space-y-1">
{feature.benefits.map((benefit, idx) => (
<li key={idx} className="flex items-center text-sm text-gray-600">
<span className="w-1.5 h-1.5 bg-green-500 rounded-full mr-2"></span>
{benefit}
</li>
))}
</ul>
</div>
)}
</div>
))}
</div>
</div>
</div>
)
}
// src/components/PerformanceComparison.tsx
export default function PerformanceComparison() {
const benchmarks = [
{ metric: 'Cold Start', webpack: '2.3s', turbopack: '0.4s', improvement: '5.8x' },
{ metric: 'Hot Reload', webpack: '1.8s', turbopack: '0.1s', improvement: '18x' },
{ metric: 'Build Size', webpack: '245KB', turbopack: '210KB', improvement: '14%' },
{ metric: 'Memory Usage', webpack: '512MB', turbopack: '180MB', improvement: '65%' },
]
return (
<div className="py-16 bg-white">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 className="text-3xl font-bold text-center text-gray-900 mb-12">
Performance Comparison
</h2>
<div className="bg-gray-50 rounded-lg p-8">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{benchmarks.map((benchmark, index) => (
<div key={index} className="text-center">
<div className="text-2xl font-bold text-gray-900 mb-2">
{benchmark.metric}
</div>
<div className="space-y-2 mb-4">
<div className="flex justify-between text-sm">
<span className="text-gray-600">Webpack:</span>
<span className="font-medium">{benchmark.webpack}</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-600">Turbopack:</span>
<span className="font-medium text-green-600">{benchmark.turbopack}</span>
</div>
</div>
<div className="bg-green-100 text-green-800 rounded-lg px-3 py-2">
<div className="text-lg font-bold">{benchmark.improvement}</div>
<div className="text-xs">faster</div>
</div>
</div>
))}
</div>
<div className="mt-8 text-center">
<p className="text-gray-600">
Benchmarks based on typical Next.js applications. Results may vary based on
project complexity and configuration.
</p>
</div>
</div>
</div>
</div>
)
}
// 5. API Routes with Turbopack
// src/app/api/hello/route.ts
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
const searchParams = request.nextUrl.searchParams
const name = searchParams.get('name') || 'World'
return NextResponse.json({
message: `Hello, ${name}!`,
timestamp: new Date().toISOString(),
bundler: 'Turbopack'
})
}
export async function POST(request: Request) {
try {
const body = await request.json()
const { name } = body
return NextResponse.json({
message: `Hello, ${name}!`,
received: body,
timestamp: new Date().toISOString()
})
} catch (error) {
return NextResponse.json(
{ error: 'Invalid JSON data' },
{ status: 400 }
)
}
}
// src/app/api/users/route.ts
import { NextResponse } from 'next/server'
// Mock user data
const users = [
{ id: 1, name: 'John Doe', email: '[email protected]' },
{ id: 2, name: 'Jane Smith', email: '[email protected]' },
{ id: 3, name: 'Bob Johnson', email: '[email protected]' },
]
export async function GET() {
return NextResponse.json({
users,
count: users.length,
bundler: 'Turbopack'
})
}
export async function POST(request: Request) {
try {
const body = await request.json()
const newUser = {
id: users.length + 1,
...body
}
users.push(newUser)
return NextResponse.json({
message: 'User created successfully',
user: newUser
}, { status: 201 })
} catch (error) {
return NextResponse.json(
{ error: 'Failed to create user' },
{ status: 500 }
)
}
}
// 6. Development Scripts
// scripts/dev.js
const { execSync } = require('child_process')
const fs = require('fs')
const path = require('path')
// Check if Turbopack is available
function checkTurbopack() {
try {
execSync('npx next --version', { stdio: 'pipe' })
return true
} catch {
console.log('❌ Next.js not found. Installing...')
execSync('npm install next@latest react@latest react-dom@latest', { stdio: 'inherit' })
return true
}
}
// Start development server with Turbopack
function startDevServer() {
console.log('🚀 Starting development server with Turbopack...')
console.log('📦 This will use Turbopack for lightning-fast builds!')
console.log('🌐 Visit http://localhost:3000 to see your app')
try {
execSync('npm run dev', { stdio: 'inherit' })
} catch (error) {
console.error('❌ Failed to start development server:', error.message)
process.exit(1)
}
}
// Main execution
if (require.main === module) {
if (checkTurbopack()) {
startDevServer()
}
}
// 7. Environment Configuration
// .env.local
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:3000/api
TURBOPACK=1
NODE_ENV=development
// .env.production.local
NEXT_PUBLIC_APP_URL=https://your-app-domain.com
NEXT_PUBLIC_API_URL=https://your-api-domain.com/api
NODE_ENV=production
export default TurbopackFeatures
💻 Продвинутая конфигурация Turbopack typescript
🟡 intermediate
⭐⭐⭐⭐
Расширенная конфигурация Turbopack, включая кастомные загрузчики, плагины, оптимизацию производительности и настройку сборки
⏱️ 45 min
🏷️ turbopack, advanced, configuration, optimization
Prerequisites:
Turbopack basics, Next.js, TypeScript, Build tools
// Turbopack Advanced Configuration
// Advanced patterns and customization for Turbopack
// 1. Advanced Next.js Configuration with Turbopack
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
turbo: {
// Enable Turbopack
turbo: {
// Custom loaders configuration
loaders: {
'.svg': [
{
loader: '@svgr/webpack',
options: {
icon: true,
svgo: true,
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
},
},
},
],
},
},
},
],
'.glsl': ['raw-loader'],
'.wgsl': ['raw-loader'],
'.mdx': ['@next/mdx'],
},
// Resolve aliases
resolveAlias: {
'@': './src',
'@/components': './src/components',
'@/lib': './src/lib',
'@/styles': './src/styles',
'@/assets': './src/assets',
'@/types': './src/types',
},
// External packages to skip transpilation
externals: ['sharp', 'canvas'],
// Custom transformations
transform: {
'^.+\\.(js|jsx|ts|tsx)$': ['swc-loader'],
},
// Source map configuration
sourceMap: {
production: true,
development: true,
},
// Minification
minify: process.env.NODE_ENV === 'production',
// Tree shaking
treeshake: true,
// Code splitting
splitChunks: {
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
framework: {
name: 'framework',
chunks: 'all',
test: /(?<!node_modules.*)[\\/]node_modules[\\/](react|react-dom|scheduler|prop-types|use-subscription)[\\/]/,
priority: 40,
enforce: true,
},
lib: {
test: /[\\/]node_modules[\\/]/,
name(module) {
const packageName = module.context
? module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)?.[1]
: null
return `npm.${packageName}`
},
priority: 30,
minChunks: 1,
reuseExistingChunk: true,
},
},
},
},
},
// Experimental features
appDir: true,
serverComponentsExternalPackages: ['@prisma/client'],
// Output configuration
output: 'standalone',
// Compression
compress: true,
// Powered-by header removal
poweredByHeader: false,
// React strict mode
reactStrictMode: true,
// SWC minification
swcMinify: true,
// Image optimization
images: {
domains: ['example.com', 'cdn.example.com'],
formats: ['image/webp', 'image/avif'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
// Rewrites for API routes
async rewrites() {
return [
{
source: '/api/external/:path*',
destination: 'https://external-api.com/:path*',
},
]
},
// Redirects
async redirects() {
return [
{
source: '/home',
destination: '/',
permanent: true,
},
]
},
// Headers
async headers() {
return [
{
source: '/api/:path*',
headers: [
{ key: 'Access-Control-Allow-Credentials', value: 'true' },
{ key: 'Access-Control-Allow-Origin', value: '*' },
{ key: 'Access-Control-Allow-Methods', value: 'GET,OPTIONS,PATCH,DELETE,POST,PUT' },
],
},
]
},
},
// Webpack configuration fallback (for when Turbopack is not used)
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Custom webpack rules
config.module.rules.push({
test: /\\.glsl$/,
use: 'raw-loader',
})
// Performance optimizations
if (!dev && !isServer) {
config.optimization.splitChunks = {
chunks: 'all',
cacheGroups: {
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: -10,
chunks: 'all',
},
},
}
}
return config
},
}
module.exports = nextConfig
// 2. Custom Turbopack Loader
// loaders/custom-loader.ts
import type { LoaderContext } from '@next/swc'
export default function customLoader(
this: LoaderContext,
source: string
): string {
const { resourcePath, options } = this
// Custom transformation logic
if (resourcePath.endsWith('.custom')) {
// Process custom file format
const processed = source
.replace(/\/\* CUSTOM_START \*\//g, '')
.replace(/\/\* CUSTOM_END \*\//g, '')
.trim()
return `export default ${JSON.stringify(processed)};`
}
// TypeScript file processing
if (resourcePath.endsWith('.ts') || resourcePath.endsWith('.tsx')) {
// Add custom TypeScript transformations
return source
.replace(/console\.log/g, '// console.log') // Remove console.logs
.replace(/debugger;/g, '// debugger;') // Remove debuggers
}
return source
}
// 3. Turbopack Plugin System
// plugins/turbopack-plugin.ts
import type { Plugin } from '@next/swc'
interface PluginOptions {
enabled?: boolean
analyze?: boolean
}
export function turbopackPlugin(options: PluginOptions = {}): Plugin {
const { enabled = true, analyze = false } = options
return {
name: 'custom-turbopack-plugin',
apply(compiler) {
if (!enabled) return
compiler.hooks.beforeCompile.tap('CustomPlugin', (params) => {
console.log('🔧 Turbopack compilation starting...')
})
compiler.hooks.afterCompile.tap('CustomPlugin', (stats) => {
console.log('✅ Turbopack compilation completed!')
if (analyze) {
console.log('📊 Build stats:', {
time: stats.endTime - stats.startTime,
assets: stats.assets?.length || 0,
chunks: stats.chunks?.length || 0
})
}
})
// Custom optimization hooks
compiler.hooks.optimize.tap('CustomPlugin', (compilation) => {
// Add custom optimizations
compilation.modules.forEach(module => {
// Module-specific optimizations
})
})
},
}
}
// 4. Environment-specific Configuration
// config/turbo.config.development.ts
import type { TurboConfig } from 'turbo'
const devConfig: TurboConfig = {
pipeline: {
build: {
dependsOn: ['^build'],
cache: false,
},
dev: {
cache: false,
persistent: true,
},
lint: {
outputs: [],
},
test: {
dependsOn: ['build'],
cache: false,
},
},
env: {
NEXT_PUBLIC_DEV_MODE: 'true',
TURBOPACK_DEV: 'true',
},
}
export default devConfig
// config/turbo.config.production.ts
import type { TurboConfig } from 'turbo'
const prodConfig: TurboConfig = {
pipeline: {
build: {
dependsOn: ['^build', 'lint', 'test'],
cache: true,
},
lint: {
outputs: [],
},
test: {
dependsOn: ['build'],
cache: true,
},
deploy: {
dependsOn: ['build'],
cache: false,
},
},
env: {
NEXT_PUBLIC_DEV_MODE: 'false',
TURBOPACK_PROD: 'true',
},
}
export default prodConfig
// 5. Performance Monitoring
// utils/performance-monitor.ts
interface BuildMetrics {
startTime: number
endTime?: number
duration?: number
fileSize?: number
chunks?: number
assets?: string[]
}
class TurbopackPerformanceMonitor {
private metrics: Map<string, BuildMetrics> = new Map()
startBuild(buildName: string) {
this.metrics.set(buildName, {
startTime: Date.now(),
})
}
endBuild(buildName: string, additionalMetrics?: Partial<BuildMetrics>) {
const metric = this.metrics.get(buildName)
if (metric) {
metric.endTime = Date.now()
metric.duration = metric.endTime - metric.startTime
if (additionalMetrics) {
Object.assign(metric, additionalMetrics)
}
console.log(`📈 Build Performance (${buildName}):`, {
duration: `${metric.duration}ms`,
fileSize: metric.fileSize ? `${(metric.fileSize / 1024 / 1024).toFixed(2)}MB` : 'N/A',
chunks: metric.chunks || 'N/A'
})
}
}
getReport(): string {
const report = ['📊 Turbopack Performance Report\n']
for (const [name, metric] of this.metrics) {
report.push(`🔹 ${name}:`)
if (metric.duration) {
report.push(` Duration: ${metric.duration}ms`)
}
if (metric.fileSize) {
report.push(` Size: ${(metric.fileSize / 1024 / 1024).toFixed(2)}MB`)
}
report.push('')
}
return report.join('\n')
}
}
export const performanceMonitor = new TurbopackPerformanceMonitor()
// 6. Build Optimization Scripts
// scripts/optimize-build.js
const { execSync } = require('child_process')
const fs = require('fs')
const path = require('path')
class BuildOptimizer {
constructor() {
this.projectRoot = process.cwd()
this.nextConfigPath = path.join(this.projectRoot, 'next.config.js')
this.packageJsonPath = path.join(this.projectRoot, 'package.json')
}
async optimizeForProduction() {
console.log('🚀 Optimizing build for production...')
// 1. Analyze bundle size
await this.analyzeBundleSize()
// 2. Optimize dependencies
await this.optimizeDependencies()
// 3. Configure Turbopack for production
await this.configureTurbopackProduction()
// 4. Run production build
await this.runProductionBuild()
}
async analyzeBundleSize() {
console.log('📦 Analyzing bundle size...')
try {
const result = execSync('npm run build -- --analyze', {
encoding: 'utf8',
stdio: 'pipe'
})
console.log('Bundle analysis completed.')
} catch (error) {
console.warn('Bundle analysis failed, continuing...')
}
}
async optimizeDependencies() {
console.log('🔧 Optimizing dependencies...')
// Remove unused dependencies
const packageJson = JSON.parse(fs.readFileSync(this.packageJsonPath, 'utf8'))
// Add production-specific optimizations
if (!packageJson.browser) {
packageJson.browser = {
"fs": false,
"path": false,
"os": false
}
}
fs.writeFileSync(this.packageJsonPath, JSON.stringify(packageJson, null, 2))
console.log('✅ Dependencies optimized')
}
async configureTurbopackProduction() {
console.log('⚙️ Configuring Turbopack for production...')
const configContent = `
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
turbo: {
loaders: {
'.svg': ['@svgr/webpack'],
},
resolveAlias: {
'@': './src',
},
minify: true,
treeshake: true,
sourceMap: false,
},
},
swcMinify: true,
compress: true,
poweredByHeader: false,
output: 'standalone',
}
module.exports = nextConfig
`
fs.writeFileSync(this.nextConfigPath, configContent)
console.log('✅ Turbopack configured for production')
}
async runProductionBuild() {
console.log('🏗️ Running production build...')
try {
execSync('npm run build', { stdio: 'inherit' })
console.log('✅ Production build completed successfully!')
} catch (error) {
console.error('❌ Production build failed:', error.message)
process.exit(1)
}
}
}
// CLI execution
if (require.main === module) {
const optimizer = new BuildOptimizer()
optimizer.optimizeForProduction().catch(console.error)
}
// 7. Custom Turbopack Presets
// presets/react-library-preset.ts
import type { TurboConfig } from 'turbo'
export function reactLibraryPreset(): TurboConfig {
return {
pipeline: {
build: {
dependsOn: ['^build'],
outputs: ['dist/**'],
},
dev: {
cache: false,
persistent: true,
},
test: {
dependsOn: ['build'],
cache: true,
},
lint: {
outputs: [],
},
typecheck: {
dependsOn: ['build'],
cache: true,
},
},
globalEnv: {
NODE_ENV: 'development',
TURBOPACK: '1',
},
env: {
NEXT_PUBLIC_APP_NAME: 'React Library',
},
}
}
// presets/monorepo-preset.ts
export function monorepoPreset(): TurboConfig {
return {
pipeline: {
build: {
dependsOn: ['^build'],
outputs: ['dist/**', '.next/**'],
},
dev: {
cache: false,
persistent: true,
},
lint: {
outputs: [],
},
test: {
dependsOn: ['build'],
cache: true,
},
clean: {
cache: false,
},
},
globalDependencies: ['**/.env.*local'],
globalEnv: {
NODE_ENV: 'development',
TURBOPACK: '1',
},
}
}
// 8. Development Utilities
// utils/turbo-dev-utils.ts
export class TurboDevUtils {
static async reloadConfig() {
// Clear require cache for config files
Object.keys(require.cache).forEach(key => {
if (key.includes('next.config') || key.includes('turbo.config')) {
delete require.cache[key]
}
})
console.log('🔄 Configuration reloaded')
}
static async invalidateCache(pattern: string) {
// Invalidate Turbopack cache for specific patterns
console.log(`🗑️ Invalidating cache for pattern: ${pattern}`)
}
static measureBuildPerformance() {
const startTime = performance.now()
return {
end: () => {
const endTime = performance.now()
const duration = endTime - startTime
return {
duration,
formatted: `${duration.toFixed(2)}ms`,
performanceLevel: duration < 1000 ? 'excellent' :
duration < 3000 ? 'good' : 'needs-improvement'
}
}
}
}
static getBuildStats() {
return {
memoryUsage: process.memoryUsage(),
platform: process.platform,
nodeVersion: process.version,
turbopackVersion: '1.0.0', // Get from package.json
}
}
}
// Usage examples
export function startOptimizedDevServer() {
const perf = TurboDevUtils.measureBuildPerformance()
console.log('🚀 Starting optimized dev server...')
console.log('📊 Current system stats:', TurboDevUtils.getBuildStats())
// Simulate dev server start
setTimeout(() => {
const stats = perf.end()
console.log(`⚡ Dev server ready! (${stats.formatted})`)
console.log(`🎯 Performance: ${stats.performanceLevel}`)
}, 100)
}
export default BuildOptimizer
💻 Руководство по миграции Turbopack typescript
🔴 complex
⭐⭐⭐⭐⭐
Полное руководство по миграции с Webpack/Vite на Turbopack, включая пошаговый процесс и лучшие практики
⏱️ 90 min
🏷️ turbopack, migration, automation, advanced
Prerequisites:
Advanced build tools knowledge, JavaScript/TypeScript, CLI usage
// Turbopack Migration Guide
// Complete guide for migrating from Webpack/Vite to Turbopack
// 1. Migration Assessment Script
// scripts/assess-migration.ts
import * as fs from 'fs'
import * as path from 'path'
import { execSync } from 'child_process'
interface ProjectAssessment {
projectName: string
packageManager: 'npm' | 'yarn' | 'pnpm'
buildTool: 'webpack' | 'vite' | 'rollup' | 'other'
framework: 'nextjs' | 'react' | 'vue' | 'angular' | 'other'
complexity: 'simple' | 'medium' | 'complex'
migrationComplexity: 'easy' | 'moderate' | 'challenging'
compatibility: Array<{
feature: string
status: 'supported' | 'partial' | 'unsupported'
notes: string
}>
recommendations: string[]
}
class MigrationAssessor {
private projectPath: string
constructor(projectPath: string = process.cwd()) {
this.projectPath = projectPath
}
assessProject(): ProjectAssessment {
const packageJson = this.readPackageJson()
const assessment: ProjectAssessment = {
projectName: packageJson.name || 'unknown',
packageManager: this.detectPackageManager(),
buildTool: this.detectBuildTool(packageJson),
framework: this.detectFramework(packageJson),
complexity: this.assessComplexity(),
migrationComplexity: 'moderate',
compatibility: [],
recommendations: []
}
this.assessCompatibility(assessment)
this.generateRecommendations(assessment)
return assessment
}
private readPackageJson(): any {
try {
const packageJsonPath = path.join(this.projectPath, 'package.json')
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
} catch {
return {}
}
}
private detectPackageManager(): 'npm' | 'yarn' | 'pnpm' {
if (fs.existsSync(path.join(this.projectPath, 'pnpm-lock.yaml'))) return 'pnpm'
if (fs.existsSync(path.join(this.projectPath, 'yarn.lock'))) return 'yarn'
return 'npm'
}
private detectBuildTool(packageJson: any): 'webpack' | 'vite' | 'rollup' | 'other' {
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }
if (deps.vite) return 'vite'
if (deps.webpack || deps['webpack-cli'] || deps['webpack-dev-server']) return 'webpack'
if (deps.rollup) return 'rollup'
return 'other'
}
private detectFramework(packageJson: any): 'nextjs' | 'react' | 'vue' | 'angular' | 'other' {
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }
if (deps.next) return 'nextjs'
if (deps.react && deps['react-dom']) return 'react'
if (deps.vue) return 'vue'
if (deps['@angular/core']) return 'angular'
return 'other'
}
private assessComplexity(): 'simple' | 'medium' | 'complex' {
let score = 0
// Check for custom configuration files
if (fs.existsSync(path.join(this.projectPath, 'webpack.config.js'))) score += 2
if (fs.existsSync(path.join(this.projectPath, 'vite.config.ts'))) score += 1
if (fs.existsSync(path.join(this.projectPath, 'postcss.config.js'))) score += 1
if (fs.existsSync(path.join(this.projectPath, 'tailwind.config.js'))) score += 1
// Check for number of dependencies
const packageJson = this.readPackageJson()
const depCount = Object.keys({
...packageJson.dependencies,
...packageJson.devDependencies
}).length
if (depCount > 50) score += 2
else if (depCount > 20) score += 1
if (score <= 2) return 'simple'
if (score <= 4) return 'medium'
return 'complex'
}
private assessCompatibility(assessment: ProjectAssessment) {
const features = [
{ feature: 'TypeScript Support', supported: true },
{ feature: 'ES Modules', supported: true },
{ feature: 'CSS Modules', supported: true },
{ feature: 'PostCSS', supported: true },
{ feature: 'Tailwind CSS', supported: true },
{ feature: 'Static Assets', supported: true },
{ feature: 'Code Splitting', supported: true },
{ feature: 'Tree Shaking', supported: true },
]
if (assessment.framework === 'nextjs') {
features.push(
{ feature: 'App Router', supported: true },
{ feature: 'Server Components', supported: true },
{ feature: 'API Routes', supported: true },
{ feature: 'Image Optimization', supported: true },
{ feature: 'Font Optimization', supported: true }
)
}
assessment.compatibility = features.map(feature => ({
...feature,
status: feature.supported ? 'supported' : 'partial',
notes: feature.supported ? 'Fully supported by Turbopack' : 'May require configuration'
}))
// Check for potentially incompatible features
const potentiallyIncompatible = [
'Custom Webpack Loaders',
'Complex Babel Configurations',
'Specific Webchain Plugins',
'Legacy Module Systems'
]
potentiallyIncompatible.forEach(feature => {
assessment.compatibility.push({
feature,
status: 'partial',
notes: 'May require custom loader or configuration'
})
})
}
private generateRecommendations(assessment: ProjectAssessment) {
const recommendations: string[] = []
if (assessment.framework === 'nextjs') {
recommendations.push('✅ Excellent choice! Turbopack is designed for Next.js')
recommendations.push('🚀 Simply add --turbo flag to your dev script')
} else {
recommendations.push('⚠️ Consider migrating to Next.js for best Turbopack experience')
}
if (assessment.complexity === 'simple') {
recommendations.push('🎯 Your project complexity is ideal for easy migration')
} else if (assessment.complexity === 'complex') {
recommendations.push('🔧 Consider simplifying configuration before migration')
recommendations.push('📋 Document current webpack/vite configuration')
}
recommendations.push('📦 Update to latest package versions')
recommendations.push('🧪 Test thoroughly after migration')
recommendations.push('👥 Consider gradual migration for large projects')
assessment.recommendations = recommendations
}
generateReport(): string {
const assessment = this.assessProject()
let report = `📊 Migration Assessment Report for ${assessment.projectName}
\n🔧 Build Tool: ${assessment.buildTool}
🎨 Framework: ${assessment.framework}
📦 Package Manager: ${assessment.packageManager}
🎯 Project Complexity: ${assessment.complexity}
🚀 Migration Complexity: ${assessment.migrationComplexity}
📋 Feature Compatibility:
\n`
assessment.compatibility.forEach(comp => {
const icon = comp.status === 'supported' ? '✅' : comp.status === 'partial' ? '⚠️' : '❌'
report += `${icon} ${comp.feature}: ${comp.notes}\n`
})
report += `
\n💡 Recommendations:
\n`
assessment.recommendations.forEach(rec => {
report += `${rec}\n`
})
return report
}
}
// CLI execution
if (require.main === module) {
const assessor = new MigrationAssessor()
console.log(assessor.generateReport())
}
export { MigrationAssessor, ProjectAssessment }
// 2. Webpack to Turbopack Migration Script
// scripts/migrate-webpack-to-turbopack.ts
import * as fs from 'fs'
import * as path from 'path'
interface WebpackConfig {
entry?: any
output?: any
module?: {
rules?: any[]
}
resolve?: {
alias?: Record<string, string>
extensions?: string[]
}
plugins?: any[]
optimization?: any
}
class WebpackToTurbopackMigrator {
private projectPath: string
private webpackConfig: WebpackConfig
constructor(projectPath: string = process.cwd()) {
this.projectPath = projectPath
this.webpackConfig = this.loadWebpackConfig()
}
private loadWebpackConfig(): WebpackConfig {
const configPath = path.join(this.projectPath, 'webpack.config.js')
if (!fs.existsSync(configPath)) {
throw new Error('webpack.config.js not found')
}
// Clear require cache to ensure fresh load
delete require.cache[require.resolve(configPath)]
try {
const config = require(configPath)
return typeof config === 'function' ? config() : config
} catch (error) {
console.warn('Failed to load webpack config:', error.message)
return {}
}
}
migrate(): void {
console.log('🔄 Starting migration from Webpack to Turbopack...')
// 1. Create Next.js project structure if it doesn't exist
this.createNextJsStructure()
// 2. Migrate entry points
this.migrateEntryPoints()
// 3. Migrate loaders
this.migrateLoaders()
// 4. Migrate resolve configuration
this.migrateResolveConfig()
// 5. Migrate plugins
this.migratePlugins()
// 6. Create Turbopack configuration
this.createTurbopackConfig()
// 7. Update package.json scripts
this.updatePackageJson()
// 8. Create migration report
this.createMigrationReport()
console.log('✅ Migration completed successfully!')
}
private createNextJsStructure() {
const appDir = path.join(this.projectPath, 'src', 'app')
if (!fs.existsSync(appDir)) {
fs.mkdirSync(appDir, { recursive: true })
// Create basic app structure
fs.writeFileSync(
path.join(appDir, 'layout.tsx'),
this.generateDefaultLayout()
)
fs.writeFileSync(
path.join(appDir, 'page.tsx'),
this.generateDefaultPage()
)
}
}
private migrateEntryPoints() {
if (this.webpackConfig.entry) {
console.log('📝 Migrating entry points...')
// Entry points are handled differently in Next.js
// Convert to pages or app router structure
}
}
private migrateLoaders() {
if (!this.webpackConfig.module?.rules) return
console.log('📦 Migrating loaders...')
const loaders: string[] = []
this.webpackConfig.module.rules.forEach(rule => {
// Handle different loader types
if (rule.test?.test(/\\.svg$/)) {
loaders.push("'.svg': ['@svgr/webpack']")
}
if (rule.test?.test(/\\.(css|scss|sass)$/)) {
// CSS is handled automatically by Turbopack
}
if (rule.test?.test(/\\.(ts|tsx|js|jsx)$/)) {
// TypeScript/JavaScript is handled automatically
}
})
this.turbopackLoaders = loaders
}
private migrateResolveConfig() {
if (!this.webpackConfig.resolve) return
console.log('🔍 Migrating resolve configuration...')
if (this.webpackConfig.resolve.alias) {
this.turbopackAliases = this.webpackConfig.resolve.alias
}
if (this.webpackConfig.resolve.extensions) {
// Extensions are handled automatically by Turbopack
}
}
private migratePlugins() {
if (!this.webpackConfig.plugins) return
console.log('🔌 Migrating plugins...')
this.webpackConfig.plugins.forEach(plugin => {
// Handle specific plugins
if (plugin.constructor.name === 'HtmlWebpackPlugin') {
// Handled automatically by Next.js
}
if (plugin.constructor.name === 'MiniCssExtractPlugin') {
// CSS extraction handled automatically
}
})
}
private turbopackLoaders: string[] = []
private turbopackAliases: Record<string, string> = {}
private createTurbopackConfig() {
const configContent = `/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
turbo: {
loaders: {
${this.turbopackLoaders.join(',\n ')}
},
resolveAlias: {
${Object.entries(this.turbopackAliases)
.map(([key, value]) => `'${key}': '${value}'`)
.join(',\n ')}
},
},
},
}
module.exports = nextConfig`
const configPath = path.join(this.projectPath, 'next.config.js')
fs.writeFileSync(configPath, configContent)
console.log('⚙️ Created next.config.js with Turbopack configuration')
}
private updatePackageJson() {
const packageJsonPath = path.join(this.projectPath, 'package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
// Update dependencies for Next.js
if (!packageJson.dependencies?.next) {
packageJson.dependencies = {
...packageJson.dependencies,
next: '^14.0.0',
react: '^18.0.0',
'react-dom': '^18.0.0'
}
}
// Update dev dependencies
packageJson.devDependencies = {
...packageJson.devDependencies,
'@types/node': '^20.0.0',
'@types/react': '^18.0.0',
'@types/react-dom': '^18.0.0',
typescript: '^5.0.0'
}
// Update scripts
packageJson.scripts = {
...packageJson.scripts,
dev: 'next dev --turbo',
build: 'next build',
start: 'next start',
lint: 'next lint'
}
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
console.log('📦 Updated package.json with Next.js scripts and dependencies')
}
private createMigrationReport() {
const report = {
migrationDate: new Date().toISOString(),
originalConfig: this.webpackConfig,
migratedFeatures: {
loaders: this.turbopackLoaders.length,
aliases: Object.keys(this.turbopackAliases).length,
},
nextSteps: [
'Install new dependencies: npm install',
'Test the development server: npm run dev',
'Check all pages and components work correctly',
'Update any custom webpack loaders not supported by Turbopack',
'Test build process: npm run build'
],
knownIssues: this.identifyKnownIssues()
}
fs.writeFileSync(
path.join(this.projectPath, 'migration-report.json'),
JSON.stringify(report, null, 2)
)
console.log('📋 Created migration-report.json')
}
private identifyKnownIssues(): string[] {
const issues: string[] = []
// Check for potentially problematic configurations
if (this.webpackConfig.plugins?.some(p => p.constructor.name === 'DefinePlugin')) {
issues.push('Webpack DefinePlugin needs to be converted to Next.js environment variables')
}
if (this.webpackConfig.optimization) {
issues.push('Custom webpack optimization may need manual migration')
}
return issues
}
private generateDefaultLayout(): string {
return `import './globals.css'
export const metadata = {
title: 'Migrated App',
description: 'Migrated from Webpack to Turbopack',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<main>{children}</main>
</body>
</html>
)
}`
}
private generateDefaultPage(): string {
return `export default function HomePage() {
return (
<div>
<h1>Welcome to Your Turbopack App!</h1>
<p>Successfully migrated from Webpack to Turbopack</p>
</div>
)
}`
}
}
// 3. Vite to Turbopack Migration
// scripts/migrate-vite-to-turbopack.ts
class ViteToTurbopackMigrator {
private projectPath: string
private viteConfig: any
constructor(projectPath: string = process.cwd()) {
this.projectPath = projectPath
this.viteConfig = this.loadViteConfig()
}
private loadViteConfig(): any {
const configPath = path.join(this.projectPath, 'vite.config.ts')
if (!fs.existsSync(configPath)) {
console.warn('vite.config.ts not found, assuming default configuration')
return {}
}
try {
// In a real implementation, you'd need to properly load the Vite config
return {}
} catch (error) {
console.warn('Failed to load Vite config:', error.message)
return {}
}
}
migrate(): void {
console.log('🔄 Starting migration from Vite to Turbopack...')
this.convertToNextJs()
this.migratePlugins()
this.updateConfiguration()
this.updatePackageJson()
console.log('✅ Vite to Turbopack migration completed!')
}
private convertToNextJs() {
console.log('🔄 Converting to Next.js structure...')
// Create app directory structure
const appDir = path.join(this.projectPath, 'src', 'app')
fs.mkdirSync(appDir, { recursive: true })
// Convert index.html to layout.tsx and page.tsx
this.convertIndexHtml()
// Convert src/main.tsx to app components
this.convertMainTs()
}
private convertIndexHtml() {
const indexPath = path.join(this.projectPath, 'index.html')
if (fs.existsSync(indexPath)) {
const indexContent = fs.readFileSync(indexPath, 'utf8')
const title = indexContent.match(/<title>(.*?)<\/title>/)?.[1] || 'App'
// Create layout.tsx
const layoutContent = `import './globals.css'
export const metadata = {
title: '${title}',
description: 'Migrated from Vite to Turbopack',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<div id="root">{children}</div>
</body>
</html>
)
}`
fs.writeFileSync(
path.join(this.projectPath, 'src', 'app', 'layout.tsx'),
layoutContent
)
console.log('📄 Converted index.html to Next.js layout')
}
}
private convertMainTs() {
const mainPath = path.join(this.projectPath, 'src', 'main.tsx')
if (fs.existsSync(mainPath)) {
const mainContent = fs.readFileSync(mainPath, 'utf8')
// Create page.tsx from main.tsx content
const pageContent = `'use client'
${mainContent.replace(/import React from 'react'/, '')}
export default function HomePage() {
return <App />
}`
fs.writeFileSync(
path.join(this.projectPath, 'src', 'app', 'page.tsx'),
pageContent
)
console.log('📄 Converted main.tsx to Next.js page')
}
}
private migratePlugins() {
// Vite plugins need to be converted to Next.js configuration
if (this.viteConfig.plugins) {
console.log('🔌 Analyzing Vite plugins for migration...')
// Handle common plugins
const pluginMap: Record<string, string> = {
'@vitejs/plugin-react': 'Built-in to Next.js',
'vite-plugin-svgr': '@svgr/webpack in Turbopack',
'tailwindcss': 'Built-in to Next.js',
'postcss': 'Built-in to Next.js'
}
this.viteConfig.plugins.forEach((plugin: any) => {
const pluginName = typeof plugin === 'string' ? plugin : plugin.name
if (pluginMap[pluginName]) {
console.log(` ✅ ${pluginName}: ${pluginMap[pluginName]}`)
} else {
console.log(` ⚠️ ${pluginName}: May require custom configuration`)
}
})
}
}
private updateConfiguration() {
console.log('⚙️ Creating Next.js configuration...')
const nextConfig = {
experimental: {
turbo: {
// Vite-specific settings would go here
}
}
}
const configContent = `/** @type {import('next').NextConfig} */
const nextConfig = ${JSON.stringify(nextConfig, null, 2)}
module.exports = nextConfig`
fs.writeFileSync(
path.join(this.projectPath, 'next.config.js'),
configContent
)
}
private updatePackageJson() {
console.log('📦 Updating package.json...')
const packageJsonPath = path.join(this.projectPath, 'package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
// Update dependencies
packageJson.dependencies = {
...packageJson.dependencies,
next: '^14.0.0',
'react': '^18.0.0',
'react-dom': '^18.0.0'
}
// Remove Vite-specific dependencies
delete packageJson.devDependencies?.vite
delete packageJson.devDependencies?.['@vitejs/plugin-react']
// Update scripts
packageJson.scripts = {
dev: 'next dev --turbo',
build: 'next build',
start: 'next start',
preview: 'next build && next start',
lint: 'next lint'
}
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
}
}
// 4. Migration Verification Script
// scripts/verify-migration.ts
class MigrationVerifier {
private projectPath: string
constructor(projectPath: string = process.cwd()) {
this.projectPath = projectPath
}
async verify(): Promise<boolean> {
console.log('🔍 Verifying migration...')
const checks = [
this.checkDependencies(),
this.checkConfiguration(),
this.checkProjectStructure(),
this.checkDevelopmentServer(),
this.checkBuildProcess()
]
const results = await Promise.allSettled(checks)
const failures = results.filter(r => r.status === 'rejected')
if (failures.length === 0) {
console.log('✅ All verification checks passed!')
return true
} else {
console.log(`❌ ${failures.length} verification checks failed:`)
failures.forEach((failure, index) => {
console.log(` ${index + 1}. ${failure.reason}`)
})
return false
}
}
private async checkDependencies(): Promise<void> {
const requiredPackages = ['next', 'react', 'react-dom']
const packageJsonPath = path.join(this.projectPath, 'package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
const missing = requiredPackages.filter(pkg => !packageJson.dependencies?.[pkg])
if (missing.length > 0) {
throw new Error(`Missing required packages: ${missing.join(', ')}`)
}
}
private async checkConfiguration(): Promise<void> {
const configPath = path.join(this.projectPath, 'next.config.js')
if (!fs.existsSync(configPath)) {
throw new Error('next.config.js not found')
}
}
private async checkProjectStructure(): Promise<void> {
const requiredPaths = [
'src/app/layout.tsx',
'src/app/page.tsx'
]
const missing = requiredPaths.filter(p => !fs.existsSync(path.join(this.projectPath, p)))
if (missing.length > 0) {
throw new Error(`Missing required files: ${missing.join(', ')}`)
}
}
private async checkDevelopmentServer(): Promise<void> {
// This would typically try to start the dev server
// For now, just check if the script exists
const packageJsonPath = path.join(this.projectPath, 'package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
if (!packageJson.scripts?.dev?.includes('--turbo')) {
throw new Error('Development script not configured for Turbopack')
}
}
private async checkBuildProcess(): Promise<void> {
const packageJsonPath = path.join(this.projectPath, 'package.json')
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
if (!packageJson.scripts?.build) {
throw new Error('Build script not found')
}
}
}
// 5. Usage Examples
// CLI execution
if (require.main === module) {
const args = process.argv.slice(2)
const command = args[0]
switch (command) {
case 'assess':
const assessor = new MigrationAssessor()
console.log(assessor.generateReport())
break
case 'webpack':
const webpackMigrator = new WebpackToTurbopackMigrator()
webpackMigrator.migrate()
break
case 'vite':
const viteMigrator = new ViteToTurbopackMigrator()
viteMigrator.migrate()
break
case 'verify':
const verifier = new MigrationVerifier()
verifier.verify().then(success => {
process.exit(success ? 0 : 1)
})
break
default:
console.log(`
Usage: npm run migrate [command]
Commands:
assess - Assess project migration readiness
webpack - Migrate from Webpack to Turbopack
vite - Migrate from Vite to Turbopack
verify - Verify migration was successful
`)
}
}
export {
MigrationAssessor,
WebpackToTurbopackMigrator,
ViteToTurbopackMigrator,
MigrationVerifier
}