SiamCafe.net Blog
Technology

HTMX Alpine.js Service Mesh Setup — สร้าง Web App แบบ HTML-over-the-wire

htmx alpinejs service mesh setup
Htmx Alpine.js Service Mesh Setup | SiamCafe Blog
2025-08-28· อ. บอม — SiamCafe.net· 1,729 คำ

HTMX และ Alpine.js คืออะไร

HTMX เป็น JavaScript library ขนาดเล็ก (14KB gzipped) ที่ให้ HTML elements สามารถทำ AJAX requests, CSS transitions, WebSocket connections และ Server-Sent Events ได้โดยไม่ต้องเขียน JavaScript เลย ใช้ HTML attributes แทน เช่น hx-get, hx-post, hx-swap ทำให้สร้าง dynamic web apps ได้ด้วย HTML เป็นหลัก

Alpine.js เป็น lightweight JavaScript framework ขนาดเล็ก (15KB gzipped) สำหรับเพิ่ม reactivity ให้ HTML ใช้ directives คล้าย Vue.js เช่น x-data, x-show, x-bind, x-on เหมาะสำหรับ interactive components ที่ไม่ต้องการ full SPA framework

เมื่อรวม HTMX กับ Alpine.js จะได้ stack ที่ทรงพลังสำหรับสร้าง modern web apps โดยไม่ต้องใช้ React/Vue/Angular HTMX จัดการ server communication Alpine.js จัดการ client-side interactivity ทั้งคู่ทำงานร่วมกับ Service Mesh architecture ได้ดี เพราะ backend เป็น microservices ที่ return HTML fragments

ติดตั้งและเริ่มใช้งาน HTMX กับ Alpine.js

Setup HTMX และ Alpine.js project

# === HTMX + Alpine.js Setup ===

# 1. CDN Installation (Simplest)
cat > index.html << 'EOF'



    
    
    HTMX Alpine.js Service Mesh Setup — สร้าง Web | SiamCafe
    
    
    



    
    

Loading dashboard...

Menu is open!

EOF # 2. Python Backend (FastAPI) cat > server.py << 'PYEOF' from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse app = FastAPI() @app.get("/api/dashboard", response_class=HTMLResponse) async def dashboard(): return """

$45,678

Orders

567

""" @app.get("/api/search", response_class=HTMLResponse) async def search(q: str = ""): if not q: return "

Type to search...

" items = [f"Result {i} for '{q}'" for i in range(1, 6)] html = "".join(f"
  • {item}
  • " for item in items) return f"
      {html}
    " PYEOF # Run: uvicorn server:app --reload --port 8000 echo "HTMX + Alpine.js project created"

    สร้าง Dynamic Web App

    สร้าง interactive components

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    Service Mesh Architecture

    ออกแบบ Service Mesh สำหรับ HTMX backend

    #!/usr/bin/env python3
    # service_mesh.py — Service Mesh Architecture for HTMX
    import json
    import logging
    from typing import Dict, List
    
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger("mesh")
    
    class ServiceMeshArchitecture:
        def __init__(self):
            self.services = {}
        
        def design_architecture(self):
            """HTMX-friendly microservices architecture"""
            return {
                "frontend_gateway": {
                    "role": "API Gateway / BFF (Backend for Frontend)",
                    "technology": "FastAPI / Go Fiber",
                    "responsibilities": [
                        "Route HTMX requests to appropriate microservices",
                        "Compose HTML fragments from multiple services",
                        "Handle authentication / session management",
                        "Serve static assets (HTML, CSS, JS)",
                    ],
                    "endpoints": {
                        "GET /": "Main page (full HTML)",
                        "GET /api/dashboard": "Dashboard HTML fragment",
                        "GET /api/search": "Search results HTML fragment",
                        "POST /api/orders": "Create order, return updated HTML",
                        "GET /api/notifications": "SSE stream for real-time updates",
                    },
                },
                "microservices": {
                    "user-service": {"port": 8001, "returns": "JSON", "db": "PostgreSQL"},
                    "product-service": {"port": 8002, "returns": "JSON", "db": "PostgreSQL"},
                    "order-service": {"port": 8003, "returns": "JSON", "db": "PostgreSQL"},
                    "search-service": {"port": 8004, "returns": "JSON", "db": "Elasticsearch"},
                    "notification-service": {"port": 8005, "returns": "SSE/WebSocket", "db": "Redis"},
                },
                "service_mesh": {
                    "control_plane": "Istio / Linkerd",
                    "features": [
                        "mTLS between services",
                        "Traffic management (canary, blue-green)",
                        "Circuit breaking",
                        "Retry policies",
                        "Rate limiting",
                        "Observability (traces, metrics, logs)",
                    ],
                },
                "pattern": {
                    "name": "HTML-over-the-wire",
                    "flow": [
                        "1. Browser sends HTMX request (GET /api/dashboard)",
                        "2. Gateway receives request",
                        "3. Gateway calls microservices via mesh (JSON)",
                        "4. Gateway renders HTML fragment from JSON data",
                        "5. Gateway returns HTML fragment to browser",
                        "6. HTMX swaps HTML into DOM",
                    ],
                },
            }
        
        def mesh_config(self):
            """Service mesh configuration"""
            return {
                "retry_policy": {
                    "attempts": 3,
                    "per_try_timeout": "2s",
                    "retry_on": "5xx, reset, connect-failure",
                },
                "circuit_breaker": {
                    "consecutive_errors": 5,
                    "interval": "30s",
                    "base_ejection_time": "30s",
                    "max_ejection_percent": 50,
                },
                "rate_limit": {
                    "requests_per_second": 100,
                    "burst": 200,
                },
                "timeout": {
                    "connect_timeout": "5s",
                    "request_timeout": "15s",
                },
            }
    
    arch = ServiceMeshArchitecture()
    design = arch.design_architecture()
    print("Services:", json.dumps(list(design["microservices"].keys()), indent=2))
    print("\nPattern:", json.dumps(design["pattern"]["flow"], indent=2))
    
    config = arch.mesh_config()
    print("\nMesh Config:", json.dumps(config, indent=2))

    Deploy กับ Istio Service Mesh

    Deploy HTMX app บน Kubernetes กับ Istio

    # === Istio Service Mesh Deployment ===
    
    # 1. Install Istio
    curl -L https://istio.io/downloadIstio | sh -
    cd istio-1.22.0
    export PATH=$PWD/bin:$PATH
    
    istioctl install --set profile=default -y
    kubectl label namespace default istio-injection=enabled
    
    # 2. Deploy Frontend Gateway
    cat > k8s/gateway-deployment.yaml << 'EOF'
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: htmx-gateway
      labels:
        app: htmx-gateway
        version: v1
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: htmx-gateway
      template:
        metadata:
          labels:
            app: htmx-gateway
            version: v1
        spec:
          containers:
            - name: gateway
              image: registry/htmx-gateway:v1
              ports:
                - containerPort: 8000
              env:
                - name: USER_SERVICE_URL
                  value: "http://user-service:8001"
                - name: PRODUCT_SERVICE_URL
                  value: "http://product-service:8002"
                - name: ORDER_SERVICE_URL
                  value: "http://order-service:8003"
              resources:
                requests:
                  cpu: 100m
                  memory: 128Mi
                limits:
                  cpu: 500m
                  memory: 256Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: htmx-gateway
    spec:
      selector:
        app: htmx-gateway
      ports:
        - port: 80
          targetPort: 8000
    EOF
    
    # 3. Istio Virtual Service (Traffic Management)
    cat > k8s/virtual-service.yaml << 'EOF'
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: htmx-gateway-vs
    spec:
      hosts:
        - htmx-gateway
      http:
        - timeout: 10s
          retries:
            attempts: 3
            perTryTimeout: 3s
            retryOn: 5xx,reset,connect-failure
          route:
            - destination:
                host: htmx-gateway
                subset: v1
              weight: 90
            - destination:
                host: htmx-gateway
                subset: v2
              weight: 10
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: htmx-gateway-dr
    spec:
      host: htmx-gateway
      trafficPolicy:
        connectionPool:
          http:
            maxRequestsPerConnection: 100
        outlierDetection:
          consecutive5xxErrors: 5
          interval: 30s
          baseEjectionTime: 30s
      subsets:
        - name: v1
          labels:
            version: v1
        - name: v2
          labels:
            version: v2
    EOF
    
    kubectl apply -f k8s/
    
    # 4. Istio Gateway (External Access)
    cat > k8s/istio-gateway.yaml << 'EOF'
    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
      name: htmx-gateway-ingress
    spec:
      selector:
        istio: ingressgateway
      servers:
        - port:
            number: 443
            name: https
            protocol: HTTPS
          tls:
            mode: SIMPLE
            credentialName: htmx-tls-cert
          hosts:
            - app.example.com
    EOF
    
    echo "Service mesh deployment complete"

    Monitoring และ Observability

    Monitor HTMX app บน service mesh

    #!/usr/bin/env python3
    # mesh_monitor.py — Service Mesh Monitoring
    import json
    import logging
    from datetime import datetime
    
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger("monitor")
    
    class MeshMonitor:
        def __init__(self):
            self.metrics = {}
        
        def collect_metrics(self):
            return {
                "timestamp": datetime.utcnow().isoformat(),
                "services": {
                    "htmx-gateway": {
                        "rps": 250,
                        "latency_p50_ms": 15,
                        "latency_p99_ms": 85,
                        "error_rate_pct": 0.2,
                        "instances": 2,
                    },
                    "user-service": {
                        "rps": 120,
                        "latency_p50_ms": 8,
                        "latency_p99_ms": 45,
                        "error_rate_pct": 0.1,
                        "instances": 2,
                    },
                    "product-service": {
                        "rps": 180,
                        "latency_p50_ms": 12,
                        "latency_p99_ms": 65,
                        "error_rate_pct": 0.0,
                        "instances": 3,
                    },
                },
                "mesh": {
                    "mtls_enabled": True,
                    "circuit_breakers_open": 0,
                    "retry_count_1h": 45,
                    "timeout_count_1h": 3,
                },
            }
        
        def htmx_specific_metrics(self):
            """Metrics specific to HTMX applications"""
            return {
                "html_fragment_sizes": {
                    "dashboard": {"avg_bytes": 2048, "p99_bytes": 4096},
                    "search_results": {"avg_bytes": 1024, "p99_bytes": 3072},
                    "notifications": {"avg_bytes": 512, "p99_bytes": 1024},
                },
                "swap_performance": {
                    "avg_swap_time_ms": 5,
                    "dom_updates_per_second": 15,
                },
                "request_patterns": {
                    "hx_get_pct": 70,
                    "hx_post_pct": 20,
                    "hx_delete_pct": 5,
                    "sse_connections": 50,
                    "ws_connections": 10,
                },
            }
    
    monitor = MeshMonitor()
    metrics = monitor.collect_metrics()
    print("Services:", json.dumps(metrics["services"]["htmx-gateway"], indent=2))
    print("Mesh:", json.dumps(metrics["mesh"], indent=2))
    
    htmx_metrics = monitor.htmx_specific_metrics()
    print("\nHTMX Metrics:", json.dumps(htmx_metrics["request_patterns"], indent=2))

    FAQ คำถามที่พบบ่อย

    Q: HTMX กับ React เลือกใช้อย่างไร?

    A: HTMX เหมาะสำหรับ content-driven apps ที่ server render HTML (blogs, e-commerce, dashboards, admin panels) ใช้ง่าย ไม่ต้องเรียน framework ใหม่ bundle size เล็กมาก SEO ดี (server-rendered HTML) React เหมาะสำหรับ highly interactive apps (real-time collaboration, complex forms, data visualization, games) ต้องการ rich client-side state management ecosystem ใหญ่กว่า HTMX กฎง่ายๆ ถ้า app เหมือน document/form ใช้ HTMX ถ้า app เหมือน desktop application ใช้ React

    Q: Service Mesh จำเป็นไหมสำหรับ HTMX app?

    A: ไม่จำเป็นสำหรับ small apps (monolith backend เพียงพอ) จำเป็นเมื่อมี microservices หลายตัว ต้องการ mTLS, traffic management, observability ข้ามservices สำหรับ HTMX app ที่มี 2-3 backend services ใช้ simple load balancer เพียงพอ ที่มี 5+ services พิจารณา service mesh (Linkerd ง่ายกว่า Istio) ที่มี 10+ services service mesh แนะนำอย่างยิ่ง

    Q: HTMX กับ Alpine.js ใช้ร่วมกันอย่างไร?

    A: แบ่งหน้าที่ชัดเจน HTMX จัดการ server communication (fetch HTML fragments, form submissions, real-time updates) Alpine.js จัดการ client-side interactivity (toggles, dropdowns, tabs, form validation, animations) ใช้ร่วมกัน เช่น Alpine.js validate form ก่อน แล้ว HTMX submit, HTMX load content แล้ว Alpine.js เพิ่ม interactivity หลีกเลี่ยงให้ทั้งสองทำ task เดียวกัน เช่น ไม่ต้องใช้ Alpine.js fetch data ถ้า HTMX ทำได้

    Q: Istio กับ Linkerd เลือกอันไหน?

    A: Linkerd ง่ายกว่ามาก ติดตั้งเร็ว resource ใช้น้อย เหมาะสำหรับทีมเล็กที่ต้องการ mTLS, observability, reliability features ไม่มี VirtualService/DestinationRule ที่ซับซ้อน Istio ทรงพลังกว่า มี features ครบ traffic management, security policies, extensibility ด้วย WASM แต่ซับซ้อนกว่า ใช้ resources มากกว่า learning curve สูงกว่า สำหรับ HTMX app ที่ต้องการ canary deployments, A/B testing HTML fragments แนะนำ Istio สำหรับ basic mTLS และ observability แนะนำ Linkerd

    📖 บทความที่เกี่ยวข้อง

    Htmx Alpine.js Load Testing Strategyอ่านบทความ → Htmx Alpine.js FinOps Cloud Costอ่านบทความ → Htmx Alpine.js DNS Managementอ่านบทความ → Htmx Alpine.js Home Lab Setupอ่านบทความ →

    📚 ดูบทความทั้งหมด →