Ders 10: Deployment ve Produksiyon
🎯 Bu Derste Neleri Öğreneceksiniz?
Section titled “🎯 Bu Derste Neleri Öğreneceksiniz?”- Uygulamayı build alma ve optimizasyon
- Deploy seçenekleri (Vercel, Netlify, Docker)
- Environment variables yönetimi
- Hata ayıklama ve monitoring
- Performans optimizasyonu
- Analytics entegrasyonu
- Güvenlik best practice’leri
📚 Build Süreci
Section titled “📚 Build Süreci”TanStack Start, Vite kullanarak optimize edilmiş production build’leri oluşturur.
Build Komutları
Section titled “Build Komutları”# Development buildnpm run dev
# Production buildnpm run build
# Production build previewnpm run preview
# Type checkingnpm run type-checkBuild Yapılandırması
Section titled “Build Yapılandırması”import { defineConfig } from 'vite'import { tanstackStartConfig } from '@tanstack/start/config'
export default defineConfig({ ...tanstackStartConfig(), // Build ayarları build: { // Chunk boyutu sınırı (kb) chunkSizeWarningLimit: 1000,
// Source map sourcemap: process.env.NODE_ENV === 'development',
// Minify minify: 'terser',
// CSS code split cssCodeSplit: true,
// Target browser target: 'es2015', },
// Server ayarları ssr: { // SSR için external modüller noExternal: ['@tanstack/start'], },})☁️ Deployment Seçenekleri
Section titled “☁️ Deployment Seçenekleri”1. Vercel (Önerilen)
Section titled “1. Vercel (Önerilen)”Vercel, TanStack Start için en iyi deploy deneyimini sunar.
Vercel Kurulumu
Section titled “Vercel Kurulumu”# Vercel CLI yüklenpm install -g vercel
# Proje dizinine gitcd my-tanstack-app
# DeployvercelVercel Yapılandırması
Section titled “Vercel Yapılandırması”{ "buildCommand": "npm run build", "outputDirectory": ".tanstack/output", "devCommand": "npm run dev", "installCommand": "npm install", "framework": "vite", "regions": ["iad1"], "functions": { "app/**/*.{ts,tsx}": { "memory": 1024, "maxDuration": 10 } }, "headers": [ { "source": "/(.*)", "headers": [ { "key": "X-Content-Type-Options", "value": "nosniff" }, { "key": "X-Frame-Options", "value": "DENY" }, { "key": "X-XSS-Protection", "value": "1; mode=block" } ] } ]}Environment Variables
Section titled “Environment Variables”# Vercel dashboard veya CLI ilevercel env add SESSION_SECRET productionvercel env add DATABASE_URL productionvercel env add API_KEY production2. Netlify
Section titled “2. Netlify”Netlify, ücretsiz deploy için harika bir seçenektir.
Netlify Yapılandırması
Section titled “Netlify Yapılandırması”[build] command = "npm run build" publish = ".tanstack/output"
[build.environment] NODE_VERSION = "20"
[[plugins]] package = "@netlify/plugin-lighthouse"
[[redirects]] from = "/*" to = "/index.html" status = 200
[[headers]] for = "/*" [headers.values] X-Frame-Options = "DENY" X-Content-Type-Options = "nosniff" X-XSS-Protection = "1; mode=block" Referrer-Policy = "strict-origin-when-cross-origin"3. Docker
Section titled “3. Docker”Docker ile containerized deploy yapabilirsiniz.
Dockerfile
Section titled “Dockerfile”# DockerfileFROM node:20-alpine AS base
# DependenciesFROM base AS depsWORKDIR /appCOPY package.json package-lock.json ./RUN npm ci
# BuilderFROM base AS builderWORKDIR /appCOPY --from=deps /app/node_modules ./node_modulesCOPY . .
# BuildRUN npm run build
# RunnerFROM base AS runnerWORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejsRUN adduser --system --uid 1001 tanstack
COPY --from=builder /app/.tanstack/output ./COPY --from=builder /app/package.json ./
RUN chown -R tanstack:nodejs /app
USER tanstack
EXPOSE 3000
CMD ["npm", "run", "start"]Docker Compose
Section titled “Docker Compose”version: '3.8'
services: app: build: . ports: - "3000:3000" environment: - NODE_ENV=production - DATABASE_URL=${DATABASE_URL} - SESSION_SECRET=${SESSION_SECRET} restart: unless-stopped
nginx: image: nginx:alpine ports: - "80:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf depends_on: - app4. VPS/Dedicated Server
Section titled “4. VPS/Dedicated Server”Kendi sunucunuzda deploy yapmak için:
PM2 ile Process Manager
Section titled “PM2 ile Process Manager”# PM2 yüklenpm install -g pm2
# Uygulamayı başlatpm2 start npm --name "tanstack-app" -- start
# Kaydetpm2 save
# Startup script oluşturpm2 startupNginx Reverse Proxy
Section titled “Nginx Reverse Proxy”server { listen 80; server_name example.com www.example.com;
location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; }}🌧️ Environment Variables
Section titled “🌧️ Environment Variables”.env Yapısı
Section titled “.env Yapısı”# .env.example (versiyon kontrolüne ekleyin)NODE_ENV=developmentPORT=3000
# DatabaseDATABASE_URL=postgresql://user:password@localhost:5432/dbname
# SessionSESSION_SECRET=your-session-secret-min-32-chars
# API KeysAPI_KEY=your-api-keySMTP_HOST=smtp.example.comSMTP_PASS=password
# External ServicesREDIS_URL=redis://localhost:6379S3_BUCKET=your-bucketS3_REGION=us-east-1
# Feature FlagsENABLE_ANALYTICS=trueENABLE_ERROR_REPORTING=trueServer’da Environment Okuma
Section titled “Server’da Environment Okuma”export const config = { nodeEnv: process.env.NODE_ENV || 'development', port: parseInt(process.env.PORT || '3000', 10), databaseUrl: process.env.DATABASE_URL!, sessionSecret: process.env.SESSION_SECRET!, apiKey: process.env.API_KEY,
// Validation isProduction: process.env.NODE_ENV === 'production', isDevelopment: process.env.NODE_ENV === 'development',}
// Development'ta eksik değişkenleri uyarif (config.isDevelopment) { const required = ['DATABASE_URL', 'SESSION_SECRET'] const missing = required.filter((key) => !process.env[key])
if (missing.length > 0) { console.warn('⚠️ Missing env vars:', missing.join(', ')) }}Runtime Environment Validation
Section titled “Runtime Environment Validation”import { createStart } from '@tanstack/react-start'import { z } from 'zod'
// Environment şemasıconst envSchema = z.object({ DATABASE_URL: z.string().url(), SESSION_SECRET: z.string().min(32), API_KEY: z.string().optional(),})
// Validate at startupconst env = envSchema.parse(process.env)
export const startInstance = createStart(() => ({ // Config'i geç config: env,}))🔍 Hata Ayıklama ve Monitoring
Section titled “🔍 Hata Ayıklama ve Monitoring”Error Tracking
Section titled “Error Tracking”Sentry Entegrasyonu
Section titled “Sentry Entegrasyonu”npm install @sentry/react @sentry/tracingimport * as Sentry from '@sentry/react'import { BrowserTracing } from '@sentry/tracing'
if (process.env.NODE_ENV === 'production') { Sentry.init({ dsn: process.env.SENTRY_DSN, integrations: [ new BrowserTracing(), ], tracesSampleRate: 0.1, // %10 trace environment: process.env.NODE_ENV, beforeSend(event) { // Hassas verileri temizle if (event.request?.headers) { delete event.request.headers['cookie'] delete event.request.headers['authorization'] } return event }, })}Performance Monitoring
Section titled “Performance Monitoring”// Web Vitalsimport { onCLS, onFID, onFCP, onLCP, onTTFB } from 'web-vitals'
export function reportWebVitals() { onCLS(console.log) onFID(console.log) onFCP(console.log) onLCP(console.log) onTTFB(console.log)}
// Kullanım (app entry point)reportWebVitals()Custom Monitoring Dashboard
Section titled “Custom Monitoring Dashboard”export function MonitoringDashboard() { const { data } = useQuery({ queryKey: ['health'], queryFn: async () => { const res = await fetch('/api/health') return res.json() }, refetchInterval: 30000, // 30 saniyede bir })
return ( <div> <h2>System Status</h2> <div>Uptime: {data?.uptime}</div> <div>Memory: {data?.memory}</div> <div>DB Connection: {data?.db ? '✅' : '❌'}</div> </div> )}⚡ Performans Optimizasyonu
Section titled “⚡ Performans Optimizasyonu”1. Code Splitting
Section titled “1. Code Splitting”// Lazy loadingimport { lazy } from 'react'
const HeavyComponent = lazy(() => import('./HeavyComponent'))
function App() { return ( <Suspense fallback={<div>Loading...</div>}> <HeavyComponent /> </Suspense> )}2. Image Optimization
Section titled “2. Image Optimization”export function OptimizedImage({ src, alt, ...props }: any) { return ( <img src={src} alt={alt} loading="lazy" decoding="async" {...props} style={{ contentVisibility: 'auto', ...props.style, }} /> )}3. Cache Strategy
Section titled “3. Cache Strategy”// Cache header'larıexport const cacheHeaders = { // Statik assets - 1 yıl '/*.js': { maxAge: 31536000, immutable: true }, '/*.css': { maxAge: 31536000, immutable: true }, '/*.png': { maxAge: 31536000, immutable: true },
// HTML - cache yok '/': { noCache: true }, '/**/*.html': { noCache: true },}4. Bundle Analysis
Section titled “4. Bundle Analysis”# Bundle analyzer yüklenpm install -D rollup-plugin-visualizer
# Build ve analyzenpm run build -- --mode analyzeimport { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({ plugins: [ visualizer({ open: true, gzipSize: true, brotliSize: true, }), ],})📊 Analytics Entegrasyonu
Section titled “📊 Analytics Entegrasyonu”Google Analytics 4
Section titled “Google Analytics 4”export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID
export function pageView(path: string) { if (typeof window !== 'undefined' && (window as any).gtag) { ;(window as any).gtag('config', GA_TRACKING_ID, { page_path: path, }) }}
export function event(action: string, category: string, label?: string, value?: number) { if (typeof window !== 'undefined' && (window as any).gtag) { ;(window as any).gtag('event', action, { event_category: category, event_label: label, value: value, }) }}// Route değişikliklerini takip etimport { useRouter } from '@tanstack/react-router'import { useEffect } from 'react'import { pageView } from '../lib/analytics'
export function useAnalytics() { const router = useRouter()
useEffect(() => { const unsubscribe = router.subscribe((event) => { if (event.type === 'onLoaded') { pageView(router.state.location.pathname) } })
return unsubscribe }, [router])}Custom Events
Section titled “Custom Events”// Buton tıklamafunction BuyButton() { const handleClick = () => { event('purchase', 'ecommerce', 'product_123', 99.99) }
return <button onClick={handleClick}>Satın Al</button>}🔒 Güvenlik Best Practice’leri
Section titled “🔒 Güvenlik Best Practice’leri”1. Güvenlik Header’ları
Section titled “1. Güvenlik Header’ları”export const securityHeaders = createMiddleware() .server(async ({ next }) => { const response = await next()
// Güvenlik header'ları ekle response.headers.set('X-Content-Type-Options', 'nosniff') response.headers.set('X-Frame-Options', 'DENY') response.headers.set('X-XSS-Protection', '1; mode=block') response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin') response.headers.set('Permissions-Policy', 'geolocation=(), microphone=()')
// CSP response.headers.set( 'Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" )
return response })2. Rate Limiting
Section titled “2. Rate Limiting”import { createMiddleware } from '@tanstack/react-start'
const rateLimiter = new Map<string, { count: number; reset: number }>()
export const rateLimitMiddleware = createMiddleware() .server(async ({ next }) => { const ip = headers.get('x-forwarded-for') || 'unknown' const now = Date.now() const windowMs = 60 * 1000 // 1 dakika const maxRequests = 100
const record = rateLimiter.get(ip)
if (!record || now > record.reset) { rateLimiter.set(ip, { count: 1, reset: now + windowMs }) return next() }
if (record.count >= maxRequests) { throw new Error('Rate limit exceeded') }
record.count++ return next() })3. Input Sanitization
Section titled “3. Input Sanitization”// XSS korumasıimport DOMPurify from 'dompurify'
export function sanitizeHTML(html: string): string { if (typeof window === 'undefined') { return html // Server'da işlem yapma } return DOMPurify.sanitize(html)}
// Kullanımconst clean = sanitizeHTML(userInput)🎨 Pratik Örnek: Production-Ready Uygulama
Section titled “🎨 Pratik Örnek: Production-Ready Uygulama”Hadi öğrendiklerimizle production-ready bir yapı oluşturalım!
Proje Yapısı
Section titled “Proje Yapısı”my-app/├── src/│ ├── start.ts # Entry point│ ├── routes/ # Routes│ ├── lib/│ │ ├── config.ts # Environment config│ │ ├── db.ts # Database│ │ └── auth.ts # Auth│ ├── middleware/│ │ ├── security.ts # Security headers│ │ └── auth.ts # Auth check│ └── components/├── public/ # Static assets├── .env.example├── Dockerfile├── docker-compose.yml├── vercel.json└── package.jsonProduction Entry Point
Section titled “Production Entry Point”import { createStart } from '@tanstack/react-start'import { securityHeaders } from './middleware/security'
export const startInstance = createStart(() => ({ requestMiddleware: [securityHeaders],
// Global error handling onError: (error) => { console.error('[ERROR]', error)
// Production'da monitoring servisine gönder if (process.env.NODE_ENV === 'production') { // sendToSentry(error) } },}))Health Check Endpoint
Section titled “Health Check Endpoint”import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/api/health')({ loader: async () => { const health = { status: 'ok', timestamp: new Date().toISOString(), uptime: process.uptime(), memory: process.memoryUsage(), environment: process.env.NODE_ENV, }
return new Response(JSON.stringify(health), { status: 200, headers: { 'Content-Type': 'application/json' }, }) },})✅ Ders 10 Özeti - Tüm Müfredatın Özeti
Section titled “✅ Ders 10 Özeti - Tüm Müfredatın Özeti”Bu derste öğrendiklerimiz:
| Konu | Açıklama |
|---|---|
| Build | Production build oluşturma |
| Vercel | Önerilen deploy platformu |
| Docker | Containerized deploy |
| Environment vars | Konfigürasyon yönetimi |
| Monitoring | Hata takibi ve performans |
| Security | Güvenlik best practice’leri |
Tüm Müfredat Özeti
Section titled “Tüm Müfredat Özeti”| Ders | Konu | Ana Öğrenmeler |
|---|---|---|
| 01 | Giriş ve Kurulum | Proje kurulumu, temel yapı |
| 02 | Routing - Temel | File-based routing, Link, Outlet |
| 03 | Routing - Orta | Search params, loaders, redirects |
| 04 | Server Functions - Giriş | createServerFn, GET/POST |
| 05 | Server Functions - Orta | Middleware, context, session |
| 06 | State Management | TanStack Query, mutations |
| 07 | SSR ve Rendering | SSR, SPA, static prerendering |
| 08 | Authentication | Session, JWT, OAuth |
| 09 | Form Yönetimi | Validasyon, multi-step forms |
| 10 | Deployment | Build, deploy, monitoring |
📝 Final Projeti
Section titled “📝 Final Projeti”E-Ticaret Uygulaması
Section titled “E-Ticaret Uygulaması”Öğrendiklerinizin tamamını kullanarak tam bir e-ticaret uygulaması yapın:
Gereksinimler:
-
Routing
- Ana sayfa (SSR)
- Ürün listesi (SSR)
- Ürün detay (SSR)
- Sepet (SPA)
- Checkout (SPA + auth)
- Admin panel (SPA + auth)
-
Server Functions
- Ürün CRUD
- Sipariş oluştur
- Ödeme işlemleri
- Admin istatistikleri
-
Authentication
- Kullanıcı girişi
- Admin yetkisi
- Session yönetimi
-
Forms
- Ürün ekleme formu (admin)
- Checkout formu
- İletişim formu
-
Deployment
- Production build
- Environment config
- Deploy (Vercel/Docker)
🎉 Tebrikler!
Section titled “🎉 Tebrikler!”TanStack Start müfredatını tamamladınız! Artık:
✅ Modern, full-stack React uygulamaları geliştirebilirsiniz ✅ Type-safe routing ve server functions kullanabilirsiniz ✅ Authentication ve authorization sistemleri kurabilirsiniz ✅ Production-ready uygulamaları deploy edebilirsiniz
Öğrenmeye Devam Edin
Section titled “Öğrenmeye Devam Edin”- Resmi Dokümantasyon: https://tanstack.com/start/latest
- GitHub: https://github.com/TanStack/start
- Discord: TanStack community
- Twitter: @TanStackQuery
Sonraki Adımlar
Section titled “Sonraki Adımlar”- Kendi projenizi oluşturun
- TanStack Router’ı derinlemesine inceleyin
- TanStack Query ile complex state yönetimi öğrenin
- Testing stratejileri araştırın
💬 Sorularınız?
Section titled “💬 Sorularınız?”Herhangi bir sorunuz varsa belirtmekten çekinmeyin!
İyi kodlamalar! 🚀👋