+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 234 of 355

๐Ÿš€ Vite: Fast Development Server

Master vite: fast development server in TypeScript with practical examples, best practices, and real-world applications ๐Ÿš€

๐Ÿ’ŽAdvanced
25 min read

Prerequisites

  • Basic understanding of JavaScript ๐Ÿ“
  • TypeScript installation โšก
  • VS Code or preferred IDE ๐Ÿ’ป

What you'll learn

  • Understand the concept fundamentals ๐ŸŽฏ
  • Apply the concept in real projects ๐Ÿ—๏ธ
  • Debug common issues ๐Ÿ›
  • Write type-safe code โœจ

๐ŸŽฏ Introduction

Welcome to the world of lightning-fast development with Vite! ๐ŸŽ‰ In this guide, weโ€™ll explore how Vite revolutionizes TypeScript development with its blazing-fast hot module replacement and modern build system.

Youโ€™ll discover how Vite can transform your TypeScript development experience from sluggish rebuilds to instant updates. Whether youโ€™re building React apps ๐ŸŒ, Vue projects ๐Ÿ–ฅ๏ธ, or vanilla TypeScript libraries ๐Ÿ“š, understanding Vite is essential for modern development workflows.

By the end of this tutorial, youโ€™ll feel confident setting up and optimizing Vite for your TypeScript projects! Letโ€™s dive in! ๐ŸŠโ€โ™‚๏ธ

๐Ÿ“š Understanding Vite

๐Ÿค” What is Vite?

Vite is like a lightning-fast sports car ๐ŸŽ๏ธ compared to traditional bundlers that feel like old trucks. Think of it as a development server that starts instantly and updates your code changes in milliseconds, not seconds.

In TypeScript terms, Vite leverages ES modules and esbuild for blazing-fast builds โšก. This means you can:

  • โœจ Start development server in under 100ms
  • ๐Ÿš€ See changes instantly with Hot Module Replacement (HMR)
  • ๐Ÿ›ก๏ธ Get TypeScript type checking without blocking dev server
  • ๐ŸŽฏ Bundle efficiently for production

๐Ÿ’ก Why Use Vite?

Hereโ€™s why developers love Vite:

  1. Instant Server Start โšก: No more waiting for bundling
  2. Lightning Fast HMR ๐Ÿ”ฅ: Changes appear instantly
  3. Native ES Modules ๐Ÿ“ฆ: Modern JavaScript approach
  4. Rich Plugin Ecosystem ๐Ÿงฉ: Extend functionality easily
  5. Optimized Production Builds ๐Ÿ—๏ธ: Rollup-powered bundling

Real-world example: Imagine building a TypeScript dashboard ๐Ÿ“Š. With Vite, you can see component updates instantly instead of waiting 5-10 seconds for webpack rebuilds!

๐Ÿ”ง Basic Syntax and Usage

๐Ÿ“ Simple Setup

Letโ€™s start with a basic Vite + TypeScript project:

# ๐Ÿš€ Create a new Vite project
npm create vite@latest my-ts-app -- --template vanilla-ts
cd my-ts-app
npm install
// ๐Ÿ‘‹ vite.config.ts - Your Vite configuration
import { defineConfig } from 'vite';

export default defineConfig({
  // ๐ŸŽฏ Basic configuration
  server: {
    port: 3000,        // ๐ŸŒ Development server port
    open: true,        // ๐Ÿš€ Auto-open browser
    hmr: {
      overlay: false   // ๐ŸŽจ Customize HMR overlay
    }
  },
  // ๐Ÿ—๏ธ Build configuration
  build: {
    target: 'es2020',  // โšก Modern JavaScript output
    outDir: 'dist',    // ๐Ÿ“ฆ Output directory
    sourcemap: true    // ๐Ÿ” Enable source maps
  }
});

๐Ÿ’ก Explanation: The defineConfig function provides TypeScript autocomplete for your Vite configuration!

๐ŸŽฏ TypeScript Integration

Hereโ€™s how Vite works seamlessly with TypeScript:

// ๐Ÿ“ src/main.ts - Entry point
import './style.css';

// ๐ŸŽจ Define types for our app
interface User {
  id: number;
  name: string;
  email: string;
  isOnline: boolean;
}

// ๐Ÿš€ Vite provides fast TypeScript compilation
const users: User[] = [
  { id: 1, name: "Alice", email: "[email protected]", isOnline: true },
  { id: 2, name: "Bob", email: "[email protected]", isOnline: false }
];

// ๐ŸŽฏ Type-safe DOM manipulation
const app = document.querySelector<HTMLDivElement>('#app')!;

function renderUsers(users: User[]): void {
  app.innerHTML = `
    <h1>๐Ÿ‘ฅ User Dashboard</h1>
    <div class="users">
      ${users.map(user => `
        <div class="user ${user.isOnline ? 'online' : 'offline'}">
          <h3>${user.name} ${user.isOnline ? '๐ŸŸข' : '๐Ÿ”ด'}</h3>
          <p>๐Ÿ“ง ${user.email}</p>
        </div>
      `).join('')}
    </div>
  `;
}

// โšก Instant updates with HMR
renderUsers(users);

// ๐Ÿ”ฅ Vite HMR API for advanced usage
if (import.meta.hot) {
  import.meta.hot.accept(); // ๐Ÿš€ Enable HMR for this module
}

๐Ÿ’ก Practical Examples

๐Ÿ›’ Example 1: E-commerce Product Configurator

Letโ€™s build a type-safe product configurator with instant updates:

// ๐Ÿ›๏ธ types/products.ts
export interface Product {
  id: string;
  name: string;
  basePrice: number;
  category: 'electronics' | 'clothing' | 'books';
  emoji: string;
  variants: ProductVariant[];
}

export interface ProductVariant {
  name: string;
  priceModifier: number;
  available: boolean;
}

export interface CartItem {
  product: Product;
  variant: ProductVariant;
  quantity: number;
}
// ๐ŸŽฎ src/product-configurator.ts
import type { Product, ProductVariant, CartItem } from './types/products';

class ProductConfigurator {
  private products: Product[] = [
    {
      id: '1',
      name: 'TypeScript Laptop',
      basePrice: 999.99,
      category: 'electronics',
      emoji: '๐Ÿ’ป',
      variants: [
        { name: '16GB RAM', priceModifier: 200, available: true },
        { name: '32GB RAM', priceModifier: 500, available: true },
        { name: '64GB RAM', priceModifier: 1000, available: false }
      ]
    },
    {
      id: '2',
      name: 'Developer Hoodie',
      basePrice: 49.99,
      category: 'clothing',
      emoji: '๐Ÿ‘”',
      variants: [
        { name: 'Small', priceModifier: 0, available: true },
        { name: 'Medium', priceModifier: 0, available: true },
        { name: 'Large', priceModifier: 5, available: true }
      ]
    }
  ];

  private cart: CartItem[] = [];

  // ๐ŸŽฏ Render product configurator
  renderConfigurator(containerId: string): void {
    const container = document.getElementById(containerId);
    if (!container) return;

    container.innerHTML = `
      <div class="configurator">
        <h2>๐Ÿ›’ Product Configurator</h2>
        ${this.products.map(product => this.renderProduct(product)).join('')}
        <div class="cart-summary">
          <h3>๐Ÿ›๏ธ Cart (${this.cart.length} items)</h3>
          <p>๐Ÿ’ฐ Total: $${this.getCartTotal().toFixed(2)}</p>
        </div>
      </div>
    `;

    // ๐ŸŽฎ Add event listeners
    this.attachEventListeners();
  }

  // ๐ŸŽจ Render individual product
  private renderProduct(product: Product): string {
    return `
      <div class="product" data-product-id="${product.id}">
        <h3>${product.emoji} ${product.name}</h3>
        <p class="base-price">Base: $${product.basePrice}</p>
        <div class="variants">
          ${product.variants.map(variant => `
            <button 
              class="variant-btn ${variant.available ? 'available' : 'unavailable'}"
              data-variant="${variant.name}"
              ${!variant.available ? 'disabled' : ''}
            >
              ${variant.name} ${variant.priceModifier > 0 ? `+$${variant.priceModifier}` : ''}
              ${variant.available ? 'โœ…' : 'โŒ'}
            </button>
          `).join('')}
        </div>
      </div>
    `;
  }

  // ๐Ÿš€ Attach event listeners with type safety
  private attachEventListeners(): void {
    document.querySelectorAll('.variant-btn').forEach(button => {
      button.addEventListener('click', (e) => {
        const target = e.target as HTMLButtonElement;
        const productId = target.closest('.product')?.getAttribute('data-product-id');
        const variantName = target.getAttribute('data-variant');
        
        if (productId && variantName) {
          this.addToCart(productId, variantName);
        }
      });
    });
  }

  // โž• Add item to cart
  private addToCart(productId: string, variantName: string): void {
    const product = this.products.find(p => p.id === productId);
    const variant = product?.variants.find(v => v.name === variantName);
    
    if (product && variant && variant.available) {
      const existingItem = this.cart.find(
        item => item.product.id === productId && item.variant.name === variantName
      );
      
      if (existingItem) {
        existingItem.quantity++;
      } else {
        this.cart.push({ product, variant, quantity: 1 });
      }
      
      console.log(`โœ… Added ${product.emoji} ${product.name} (${variant.name}) to cart!`);
      this.renderConfigurator('app'); // ๐Ÿ”„ Re-render for instant updates
    }
  }

  // ๐Ÿ’ฐ Calculate cart total
  private getCartTotal(): number {
    return this.cart.reduce((total, item) => {
      const itemPrice = item.product.basePrice + item.variant.priceModifier;
      return total + (itemPrice * item.quantity);
    }, 0);
  }
}

// ๐ŸŽฎ Initialize the configurator
const configurator = new ProductConfigurator();
configurator.renderConfigurator('app');

// ๐Ÿ”ฅ Enable HMR for instant updates during development
if (import.meta.hot) {
  import.meta.hot.accept(() => {
    configurator.renderConfigurator('app');
  });
}

๐ŸŽฏ Try it yourself: Add a search feature and inventory management!

๐ŸŽฎ Example 2: Real-time Game Dashboard

Letโ€™s create a game dashboard with Viteโ€™s HMR:

// ๐Ÿ† src/game-dashboard.ts
interface GameSession {
  id: string;
  player: string;
  score: number;
  level: number;
  status: 'playing' | 'paused' | 'completed';
  startTime: Date;
  achievements: Achievement[];
}

interface Achievement {
  id: string;
  name: string;
  description: string;
  emoji: string;
  unlockedAt: Date;
}

class GameDashboard {
  private sessions: Map<string, GameSession> = new Map();
  private achievements: Achievement[] = [
    { id: '1', name: 'First Steps', description: 'Start your first game', emoji: '๐Ÿ‘ถ', unlockedAt: new Date() },
    { id: '2', name: 'Speed Demon', description: 'Complete a level in under 30 seconds', emoji: 'โšก', unlockedAt: new Date() },
    { id: '3', name: 'High Scorer', description: 'Reach 10,000 points', emoji: '๐Ÿ†', unlockedAt: new Date() }
  ];

  // ๐ŸŽฎ Create new game session
  startNewGame(playerName: string): string {
    const sessionId = `game-${Date.now()}`;
    const session: GameSession = {
      id: sessionId,
      player: playerName,
      score: 0,
      level: 1,
      status: 'playing',
      startTime: new Date(),
      achievements: [this.achievements[0]] // ๐Ÿ‘ถ First Steps achievement
    };
    
    this.sessions.set(sessionId, session);
    console.log(`๐ŸŽฎ ${playerName} started a new game!`);
    return sessionId;
  }

  // ๐ŸŽฏ Update game score
  updateScore(sessionId: string, points: number): void {
    const session = this.sessions.get(sessionId);
    if (!session || session.status !== 'playing') return;

    session.score += points;
    
    // ๐Ÿ† Check for achievements
    if (session.score >= 10000 && !session.achievements.find(a => a.id === '3')) {
      session.achievements.push(this.achievements[2]);
      console.log(`๐Ÿ† ${session.player} unlocked: ${this.achievements[2].emoji} ${this.achievements[2].name}!`);
    }

    // ๐Ÿ“ˆ Level up every 1000 points
    const newLevel = Math.floor(session.score / 1000) + 1;
    if (newLevel > session.level) {
      session.level = newLevel;
      console.log(`๐Ÿ“ˆ ${session.player} reached level ${session.level}!`);
    }

    this.renderDashboard();
  }

  // ๐ŸŽจ Render the dashboard
  renderDashboard(): void {
    const app = document.getElementById('app');
    if (!app) return;

    const activeSessions = Array.from(this.sessions.values())
      .filter(s => s.status === 'playing');

    app.innerHTML = `
      <div class="game-dashboard">
        <h1>๐ŸŽฎ Game Dashboard</h1>
        
        <div class="stats">
          <div class="stat">
            <h3>๐ŸŽฏ Active Games</h3>
            <p class="stat-value">${activeSessions.length}</p>
          </div>
          <div class="stat">
            <h3>๐Ÿ‘ฅ Total Players</h3>
            <p class="stat-value">${this.sessions.size}</p>
          </div>
          <div class="stat">
            <h3>๐Ÿ† Total Achievements</h3>
            <p class="stat-value">${this.getTotalAchievements()}</p>
          </div>
        </div>

        <div class="sessions">
          <h2>๐ŸŽฎ Active Sessions</h2>
          ${activeSessions.map(session => `
            <div class="session-card">
              <h3>๐Ÿ‘ค ${session.player}</h3>
              <div class="session-stats">
                <span class="score">๐ŸŽฏ ${session.score.toLocaleString()}</span>
                <span class="level">๐Ÿ“ˆ Level ${session.level}</span>
                <span class="time">โฑ๏ธ ${this.getPlayTime(session)}</span>
              </div>
              <div class="achievements">
                ${session.achievements.map(a => `
                  <span class="achievement" title="${a.description}">
                    ${a.emoji} ${a.name}
                  </span>
                `).join('')}
              </div>
              <button onclick="gameManager.updateScore('${session.id}', 100)">
                โž• Add 100 points
              </button>
            </div>
          `).join('')}
        </div>

        <div class="new-game">
          <h2>๐Ÿ†• Start New Game</h2>
          <input type="text" id="playerName" placeholder="Enter player name" />
          <button onclick="gameManager.startNewGameFromInput()">๐ŸŽฎ Start Game</button>
        </div>
      </div>
    `;
  }

  // โฑ๏ธ Calculate play time
  private getPlayTime(session: GameSession): string {
    const now = new Date();
    const diff = now.getTime() - session.startTime.getTime();
    const minutes = Math.floor(diff / 60000);
    const seconds = Math.floor((diff % 60000) / 1000);
    return `${minutes}:${seconds.toString().padStart(2, '0')}`;
  }

  // ๐Ÿ† Get total achievements count
  private getTotalAchievements(): number {
    return Array.from(this.sessions.values())
      .reduce((total, session) => total + session.achievements.length, 0);
  }

  // ๐ŸŽฎ Start game from input
  startNewGameFromInput(): void {
    const input = document.getElementById('playerName') as HTMLInputElement;
    const playerName = input.value.trim();
    
    if (playerName) {
      this.startNewGame(playerName);
      input.value = '';
      this.renderDashboard();
    }
  }
}

// ๐ŸŽฎ Create global game manager
const gameManager = new GameDashboard();
(window as any).gameManager = gameManager; // Make it globally accessible

// ๐Ÿš€ Initial render
gameManager.renderDashboard();

// ๐Ÿ”ฅ HMR support for instant updates
if (import.meta.hot) {
  import.meta.hot.accept(() => {
    gameManager.renderDashboard();
  });
}

๐Ÿš€ Advanced Concepts

๐Ÿง™โ€โ™‚๏ธ Advanced Topic 1: Custom Vite Plugins

When youโ€™re ready to level up, create custom plugins:

// ๐ŸŽฏ vite-plugin-typescript-paths.ts
import type { Plugin } from 'vite';
import { readFileSync } from 'fs';
import { resolve } from 'path';

export function typescriptPaths(): Plugin {
  return {
    name: 'typescript-paths',
    configResolved(config) {
      // ๐Ÿ” Read tsconfig.json
      const tsconfig = JSON.parse(
        readFileSync(resolve(config.root, 'tsconfig.json'), 'utf-8')
      );
      
      // ๐ŸŽจ Apply path mapping
      if (tsconfig.compilerOptions?.paths) {
        const paths = tsconfig.compilerOptions.paths;
        const alias: Record<string, string> = {};
        
        for (const [key, value] of Object.entries(paths)) {
          const aliasKey = key.replace('/*', '');
          const aliasValue = resolve(config.root, (value as string[])[0].replace('/*', ''));
          alias[aliasKey] = aliasValue;
        }
        
        config.resolve.alias = { ...config.resolve.alias, ...alias };
      }
    }
  };
}

// ๐Ÿช„ Using the custom plugin
// vite.config.ts
import { defineConfig } from 'vite';
import { typescriptPaths } from './plugins/vite-plugin-typescript-paths';

export default defineConfig({
  plugins: [
    typescriptPaths(), // โœจ Custom plugin for TypeScript paths
  ],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
      '@components': resolve(__dirname, 'src/components'),
      '@utils': resolve(__dirname, 'src/utils')
    }
  }
});

๐Ÿ—๏ธ Advanced Topic 2: Environment-Specific Configurations

For complex projects with multiple environments:

// ๐Ÿš€ Advanced Vite configuration
import { defineConfig, loadEnv } from 'vite';
import type { UserConfig } from 'vite';

export default defineConfig(({ command, mode }) => {
  // ๐ŸŒ Load environment variables
  const env = loadEnv(mode, process.cwd(), '');
  
  const config: UserConfig = {
    define: {
      // ๐ŸŽฏ Global constants
      __APP_VERSION__: JSON.stringify(env.npm_package_version),
      __API_URL__: JSON.stringify(env.VITE_API_URL),
      __DEV__: command === 'serve'
    },
    
    server: {
      port: parseInt(env.VITE_PORT) || 3000,
      proxy: {
        // ๐Ÿ”„ API proxy for development
        '/api': {
          target: env.VITE_API_URL || 'http://localhost:8080',
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, '')
        }
      }
    },
    
    build: {
      // ๐Ÿ—๏ธ Production optimizations
      rollupOptions: {
        output: {
          manualChunks: {
            vendor: ['react', 'react-dom'],
            utils: ['lodash', 'date-fns']
          }
        }
      },
      // ๐Ÿ“Š Bundle analysis
      reportCompressedSize: true,
      chunkSizeWarningLimit: 1000
    },
    
    // ๐Ÿงช Testing configuration
    test: {
      environment: 'jsdom',
      setupFiles: ['./src/test/setup.ts']
    }
  };
  
  // ๐ŸŽฏ Mode-specific configurations
  if (mode === 'development') {
    config.server!.hmr = {
      overlay: true,
      clientPort: 3001
    };
  }
  
  if (mode === 'production') {
    config.build!.minify = 'terser';
    config.build!.terserOptions = {
      compress: {
        drop_console: true // ๐Ÿšซ Remove console.logs in production
      }
    };
  }
  
  return config;
});

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Slow TypeScript Checking

// โŒ Wrong way - blocking TypeScript checking
// vite.config.ts
export default defineConfig({
  // This will slow down your dev server! ๐Ÿ˜ฐ
  plugins: [
    typescript({
      check: true,        // ๐ŸŒ Blocks dev server
      declaration: true   // ๐ŸŒ Generates .d.ts files
    })
  ]
});

// โœ… Correct way - non-blocking type checking
export default defineConfig({
  plugins: [
    typescript({
      check: false,       // โšก Don't block dev server
      declaration: false  // โšก Skip .d.ts generation in dev
    })
  ]
});

// ๐Ÿ› ๏ธ Run type checking separately
// package.json
{
  "scripts": {
    "dev": "vite",
    "type-check": "tsc --noEmit",
    "type-check:watch": "tsc --noEmit --watch"
  }
}

๐Ÿคฏ Pitfall 2: Import Path Issues

// โŒ Dangerous - might not work in production!
import { utils } from '../../../utils/helpers';
import Component from './Component.tsx'; // ๐Ÿ’ฅ Explicit .tsx not needed!

// โœ… Safe - use path mapping and proper imports!
// tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"],
      "@/components/*": ["./src/components/*"],
      "@/utils/*": ["./src/utils/*"]
    }
  }
}

// โœ… Clean imports
import { utils } from '@/utils/helpers';
import Component from './Component'; // โœ… No extension needed

๐Ÿ› ๏ธ Best Practices

  1. โšก Keep Dev Fast: Donโ€™t block the dev server with type checking
  2. ๐Ÿ“ฆ Use Path Mapping: Clean imports with TypeScript paths
  3. ๐Ÿ”ฅ Leverage HMR: Use import.meta.hot for custom HMR logic
  4. ๐ŸŒ Environment Variables: Use .env files for configuration
  5. ๐Ÿ—๏ธ Optimize Builds: Configure chunking for better performance
  6. ๐Ÿงช Separate Concerns: Type checking, linting, and dev server separately

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Build a TypeScript Code Playground

Create a Vite-powered TypeScript playground with instant compilation:

๐Ÿ“‹ Requirements:

  • โœ… Real-time TypeScript compilation with error display
  • ๐ŸŽจ Syntax highlighting for TypeScript code
  • ๐Ÿš€ Instant preview of compiled JavaScript
  • ๐Ÿ’พ Save/load code snippets with localStorage
  • ๐Ÿ”„ Hot reload for instant updates
  • ๐Ÿ“Š Bundle size analysis

๐Ÿš€ Bonus Points:

  • Add Monaco Editor integration
  • Implement sharing functionality
  • Create preset code examples
  • Add TypeScript version switching

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
// ๐ŸŽฏ TypeScript Playground Implementation
interface CodeSnippet {
  id: string;
  name: string;
  typescript: string;
  javascript: string;
  errors: string[];
  createdAt: Date;
}

class TypeScriptPlayground {
  private snippets: Map<string, CodeSnippet> = new Map();
  private currentSnippet: CodeSnippet | null = null;
  private compileTimeout: number | null = null;

  constructor() {
    this.loadSnippets();
    this.setupEventListeners();
    this.renderPlayground();
  }

  // ๐ŸŽฎ Setup the playground interface
  renderPlayground(): void {
    const app = document.getElementById('app');
    if (!app) return;

    app.innerHTML = `
      <div class="playground">
        <header class="playground-header">
          <h1>๐ŸŽฎ TypeScript Playground</h1>
          <div class="controls">
            <button id="newSnippet">๐Ÿ“ New</button>
            <button id="saveSnippet">๐Ÿ’พ Save</button>
            <select id="snippetSelect">
              <option value="">๐Ÿ“‹ Load Snippet...</option>
              ${Array.from(this.snippets.values()).map(s => 
                `<option value="${s.id}">${s.name}</option>`
              ).join('')}
            </select>
          </div>
        </header>

        <div class="editor-container">
          <div class="editor-panel">
            <h3>๐Ÿ“ TypeScript Code</h3>
            <textarea 
              id="typescriptEditor" 
              placeholder="// ๐Ÿ‘‹ Start typing TypeScript code here!
interface User {
  name: string;
  age: number;
  emoji: string;
}

const user: User = {
  name: 'Alice',
  age: 25,
  emoji: '๐Ÿ˜Š'
};

console.log(\`Hello \${user.name}! \${user.emoji}\`);"
            ></textarea>
          </div>

          <div class="output-panel">
            <h3>โšก Compiled JavaScript</h3>
            <pre id="javascriptOutput"></pre>
            
            <h3>๐Ÿšจ Type Errors</h3>
            <div id="errorOutput"></div>
          </div>
        </div>

        <div class="preview-panel">
          <h3>๐ŸŽฎ Code Preview</h3>
          <div id="codePreview"></div>
        </div>
      </div>
    `;

    this.loadDefaultSnippet();
  }

  // ๐ŸŽฏ Setup event listeners
  private setupEventListeners(): void {
    document.addEventListener('DOMContentLoaded', () => {
      const editor = document.getElementById('typescriptEditor') as HTMLTextAreaElement;
      const newBtn = document.getElementById('newSnippet');
      const saveBtn = document.getElementById('saveSnippet');
      const select = document.getElementById('snippetSelect') as HTMLSelectElement;

      // โšก Real-time compilation
      editor?.addEventListener('input', () => {
        if (this.compileTimeout) {
          clearTimeout(this.compileTimeout);
        }
        this.compileTimeout = window.setTimeout(() => {
          this.compileTypeScript(editor.value);
        }, 300); // ๐Ÿ• 300ms debounce
      });

      // ๐Ÿ“ New snippet
      newBtn?.addEventListener('click', () => this.createNewSnippet());
      
      // ๐Ÿ’พ Save snippet
      saveBtn?.addEventListener('click', () => this.saveCurrentSnippet());
      
      // ๐Ÿ“‹ Load snippet
      select?.addEventListener('change', (e) => {
        const snippetId = (e.target as HTMLSelectElement).value;
        if (snippetId) this.loadSnippet(snippetId);
      });
    });
  }

  // โšก Compile TypeScript code
  private async compileTypeScript(code: string): Promise<void> {
    try {
      // ๐ŸŽฏ Simple TypeScript compilation simulation
      // In a real implementation, you'd use TypeScript's compiler API
      const errors: string[] = [];
      let javascript = code;

      // ๐Ÿ” Basic error checking
      if (code.includes('any')) {
        errors.push("โš ๏ธ Avoid using 'any' type - be more specific!");
      }

      if (code.includes('console.log') && code.includes('production')) {
        errors.push("๐Ÿšซ Remove console.log statements in production code!");
      }

      // ๐ŸŽจ Simple transformation (remove type annotations)
      javascript = code
        .replace(/:\s*string/g, '')
        .replace(/:\s*number/g, '')
        .replace(/:\s*boolean/g, '')
        .replace(/interface\s+\w+\s*{[^}]*}/g, '')
        .replace(/type\s+\w+\s*=\s*[^;]+;/g, '');

      // ๐Ÿ“Š Update outputs
      this.updateOutputs(javascript, errors);
      
      // ๐ŸŽฎ Update preview
      this.updatePreview(javascript);

    } catch (error) {
      console.error('Compilation error:', error);
      this.updateOutputs('', [`๐Ÿ’ฅ Compilation failed: ${error}`]);
    }
  }

  // ๐Ÿ“Š Update output panels
  private updateOutputs(javascript: string, errors: string[]): void {
    const jsOutput = document.getElementById('javascriptOutput');
    const errorOutput = document.getElementById('errorOutput');

    if (jsOutput) {
      jsOutput.textContent = javascript || '// ๐ŸŽฏ Compiled JavaScript will appear here';
    }

    if (errorOutput) {
      if (errors.length > 0) {
        errorOutput.innerHTML = errors.map(error => 
          `<div class="error">${error}</div>`
        ).join('');
      } else {
        errorOutput.innerHTML = '<div class="success">โœ… No errors found!</div>';
      }
    }
  }

  // ๐ŸŽฎ Update live preview
  private updatePreview(javascript: string): void {
    const preview = document.getElementById('codePreview');
    if (!preview) return;

    try {
      // ๐Ÿš€ Execute the code safely
      const originalLog = console.log;
      const logs: string[] = [];
      
      console.log = (...args) => {
        logs.push(args.map(arg => 
          typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
        ).join(' '));
      };

      // ๐ŸŽฏ Execute in isolated scope
      new Function(javascript)();
      
      // ๐Ÿ“ Restore console.log
      console.log = originalLog;

      // ๐Ÿ“Š Display results
      preview.innerHTML = `
        <div class="preview-output">
          <h4>๐Ÿ“ค Console Output:</h4>
          ${logs.length > 0 ? 
            logs.map(log => `<div class="log-line">${log}</div>`).join('') :
            '<div class="no-output">๐Ÿคซ No console output</div>'
          }
        </div>
      `;

    } catch (error) {
      preview.innerHTML = `
        <div class="preview-error">
          <h4>๐Ÿ’ฅ Runtime Error:</h4>
          <div class="error">${error}</div>
        </div>
      `;
    }
  }

  // ๐Ÿ“ Create new snippet
  private createNewSnippet(): void {
    const editor = document.getElementById('typescriptEditor') as HTMLTextAreaElement;
    if (editor) {
      editor.value = `// ๐ŸŽฏ New TypeScript snippet
interface HelloWorld {
  message: string;
  emoji: string;
}

const greeting: HelloWorld = {
  message: "Hello, TypeScript!",
  emoji: "๐Ÿš€"
};

console.log(\`\${greeting.message} \${greeting.emoji}\`);`;
      
      this.compileTypeScript(editor.value);
    }
  }

  // ๐Ÿ’พ Save current snippet
  private saveCurrentSnippet(): void {
    const editor = document.getElementById('typescriptEditor') as HTMLTextAreaElement;
    const name = prompt('๐Ÿ“ Enter snippet name:');
    
    if (name && editor) {
      const snippet: CodeSnippet = {
        id: Date.now().toString(),
        name,
        typescript: editor.value,
        javascript: '', // Will be compiled
        errors: [],
        createdAt: new Date()
      };
      
      this.snippets.set(snippet.id, snippet);
      this.saveSnippets();
      this.renderPlayground();
      console.log(`๐Ÿ’พ Saved snippet: ${name}`);
    }
  }

  // ๐Ÿ“‹ Load snippet
  private loadSnippet(snippetId: string): void {
    const snippet = this.snippets.get(snippetId);
    if (snippet) {
      const editor = document.getElementById('typescriptEditor') as HTMLTextAreaElement;
      if (editor) {
        editor.value = snippet.typescript;
        this.compileTypeScript(snippet.typescript);
        this.currentSnippet = snippet;
      }
    }
  }

  // ๐ŸŽฏ Load default example
  private loadDefaultSnippet(): void {
    this.createNewSnippet();
  }

  // ๐Ÿ’พ Save snippets to localStorage
  private saveSnippets(): void {
    localStorage.setItem('ts-playground-snippets', JSON.stringify(
      Array.from(this.snippets.entries())
    ));
  }

  // ๐Ÿ“‹ Load snippets from localStorage
  private loadSnippets(): void {
    const saved = localStorage.getItem('ts-playground-snippets');
    if (saved) {
      const entries = JSON.parse(saved);
      this.snippets = new Map(entries);
    }
  }
}

// ๐Ÿš€ Initialize the playground
const playground = new TypeScriptPlayground();

// ๐Ÿ”ฅ HMR support
if (import.meta.hot) {
  import.meta.hot.accept(() => {
    playground.renderPlayground();
  });
}

๐ŸŽ“ Key Takeaways

Youโ€™ve learned so much about Vite! Hereโ€™s what you can now do:

  • โœ… Set up Vite with TypeScript with lightning-fast builds ๐Ÿ’ช
  • โœ… Configure advanced plugins and optimizations ๐Ÿ›ก๏ธ
  • โœ… Implement HMR for instant development feedback ๐ŸŽฏ
  • โœ… Debug build issues like a pro ๐Ÿ›
  • โœ… Build production-ready apps with TypeScript and Vite! ๐Ÿš€

Remember: Vite is your development superpower! It makes TypeScript development feel instant and joyful. ๐Ÿค

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve mastered Vite with TypeScript!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Build a project using Vite + TypeScript
  2. ๐Ÿงฉ Explore Vite plugins for your framework (React, Vue, Svelte)
  3. ๐Ÿ“š Learn about advanced build optimizations
  4. ๐ŸŒŸ Share your fast development experience with others!

Remember: Every TypeScript expert was once waiting for slow webpack builds. Now you have the speed of Vite! Keep coding, keep learning, and most importantly, enjoy the instant feedback! ๐Ÿš€


Happy coding! ๐ŸŽ‰๐Ÿš€โœจ