# Migrasi Arsitektur Real-time: Dari Vue.js Composition API ke WebSocket Skala Enterprise

> Diterbitkan oleh Literally Web ID pada 21 Oct 2026
> Sumber: https://literally.web.id/articles/migrasi-arsitektur-real-time-dari-vuejs-composition-api-ke-websocket-skala-enterprise

---

Dalam 15 menit ke depan, kita akan merakit sebuah sistem real-time berbeban tinggi dari nol sampai berjalan mulus, langsung dari ruang kendali infrastruktur kita. Lupakan teori kelas pengantar; mari kita bedah bagaimana menangani lonjakan jutaan frame WebSocket dengan Vue.js Composition API dan Pinia tanpa membuat browser klien mengalami *memory leak* atau *UI stutter*.

## 1. Menu Kita Hari Ini & Alat yang Perlu Disiapkan

Pagi ini di meja kerja kita sudah tersusun rapi bahan-bahan kelas enterprise: Node.js dengan native `ws` untuk backend WebSocket berkecepatan tinggi, Vue 3 Composition API bersama Pinia untuk manajemen state reaktif, serta Nginx sebagai reverse proxy yang siap mengamankan upgrade header WebSocket kita. Bayangkan arsitektur ini seperti jalur pipa air bertekanan tinggi; jika katup dan sambungannya tidak presisi, airnya akan meluap dan merusak komponen di sekitarnya.

Pastikan di mesin lokal Anda sudah terpasang Node.js versi 20 LTS, Vue CLI atau Vite, serta Redis untuk menangani sinkronisasi pub/sub lintas instance backend. Kita tidak akan membuang waktu membahas instalasi dasar, jadi mari kita langsung masuk ke blueprint perakitannya.

## 2. Peta Jalan Singkat: Apa yang Sedang Kita Rakit

Sebelum kita menyalakan terminal, mari kita petakan alur perjalanan data kita. Kita akan mulai dengan menyiapkan fondasi *Reactivity Transform* pada WebSocket stream agar setiap paket data yang masuk dari server langsung memicu perubahan state UI secara instan tanpa overhead berlebih. Dari sana, kita akan mengalirkan data tersebut melalui *Pinia Store Integration* yang bertindak sebagai dispatcher terpusat, memastikan komponen-komponen Vue kita tetap bersih dan decoupled.

> [!TIP]
> Kunci dari arsitektur real-time yang sehat adalah memisahkan lapisan *socket transport* dari lapisan *business logic* di state manager. Jangan pernah langsung memanggil instance WebSocket di dalam komponen UI.

Langkah terakhir dari perjalanan kilat kita adalah mengupas tuntas *Memory Management di Vue 3*, di mana kita akan membersihkan event listener dan memutus koneksi socket saat komponen di-unmount agar RAM browser tidak perlahan-lahan bengkak hingga *crash*.

## 3. Langkah 1: Mempersiapkan Fondasi & Environment

Mari kita mulai dengan meracik fondasi server WebSocket yang efisien di Node.js. Buat file `server.js` di direktori backend Anda dan masukkan konfigurasi dasar untuk menangani koneksi mentah berkecepatan tinggi:

```javascript
const { WebSocketServer } = require('ws');
const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Enterprise WebSocket Gateway Active\n');
});

const wss = new WebSocketServer({ server });

wss.on('connection', (ws) => {
  console.log('[INFO] Klien baru terhubung ke edge node.');
  
  ws.on('message', (message) => {
    // Broadcast dummy data real-time ke semua klien
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(`Echo: ${message}`);
      }
    });
  });

  ws.on('close', () => {
    console.log('[INFO] Klien terputus secara bersih.');
  });
});

server.listen(8080, () => {
  console.log('[SYSTEM] WebSocket Gateway berjalan di port 8080');
});
```

Jalankan dengan perintah `node server.js`. Perhatikan respons log di terminal Anda; tulisan tersebut adalah tanda pertama bahwa gerbang komunikasi real-time kita sudah siap menerima hantaman trafik.

## 4. Langkah 2: Meracik Konfigurasi Inti Tanpa Basa-basi

Sekarang kita berpindah ke sisi frontend Vue 3. Di sinilah keajaiban *Reactivity Transform pada WebSocket Stream* dan *Pinia Store Integration* berpadu. Kita buat file `src/stores/useRealtimeStore.js` untuk mengelola state koneksi dan aliran data masuk:

```javascript
import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useRealtimeStore = defineStore('realtime', () => {
  const socket = ref(null);
  const messages = ref([]);
  const isConnected = ref(false);

  function connect(url) {
    socket.value = new WebSocket(url);

    socket.value.onopen = () => {
      isConnected.value = true;
      console.log('[VUE] Terhubung ke WebSocket server.');
    };

    socket.value.onmessage = (event) => {
      // Masukkan data langsung ke reaktif array dengan batasan buffer
      if (messages.value.length > 100) messages.value.shift();
      messages.value.push(event.data);
    };

    socket.value.onclose = () => {
      isConnected.value = false;
      console.warn('[VUE] Koneksi terputus. Menjadwalkan reconnect...');
      setTimeout(() => connect(url), 3000);
    };
  }

  function sendMessage(payload) {
    if (socket.value && socket.value.readyState === WebSocket.OPEN) {
      socket.value.send(payload);
    }
  }

  return { socket, messages, isConnected, connect, sendMessage };
});
```

> [!IMPORTANT]
> Perhatikan pembatasan array `messages.value.length > 100`. Pada aplikasi enterprise, mengabaikan ukuran buffer array reaktif adalah penyebab nomor satu browser mengalami *memory exhaustion* dalam hitungan jam.

## 5. Langkah 3: Sentuhan Akhir Keamanan & Optimasi

Di dunia nyata, kita tidak pernah menyambungkan WebSocket langsung ke port backend tanpa pengaman. Kita butuh Nginx di depan untuk menangani *SSL/TLS termination* dan *Upgrade Header*. Berikut adalah blok konfigurasi Nginx yang wajib Anda pasang:

```nginx
server {
    listen 443 ssl http2;
    server_name ws.perusahaan.com;

    ssl_certificate /etc/letsencrypt/live/ws.perusahaan.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ws.perusahaan.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
        
        # Timeout penunjang koneksi persisten
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}
```

Uji konfigurasi dengan `nginx -t` dan reload service Nginx Anda. Jalur pipa data kini sudah terenkripsi dan terlindung di balik benteng proxy yang kokoh.

## 6. Tes Rasa: Memastikan Semuanya Berjalan Sempurna

Mari kita integrasikan store Pinia tadi ke dalam komponen Vue (`src/components/LiveFeed.vue`) untuk melihat hasil racikan kita:

```vue
<script setup>
import { onMounted, onUnmounted } from 'vue';
import { useRealtimeStore } from '@/stores/useRealtimeStore';

const store = useRealtimeStore();

onMounted(() => {
  store.connect('wss://ws.perusahaan.com');
});

onUnmounted(() => {
  if (store.socket) {
    store.socket.close();
  }
});
</script>

<template>
  <div class="p-6 font-sans">
    <div :class="store.isConnected ? 'bg-green-500' : 'bg-red-500'" class="w-4 h-4 rounded-full inline-block mr-2"></div>
    <span>Status: {{ store.isConnected ? 'Online' : 'Offline' }}</span>
    <ul class="mt-4 border p-4 rounded bg-gray-50 h-64 overflow-y-auto">
      <li v-for="(msg, index) in store.messages" :key="index" class="text-sm py-1">
        {{ msg }}
      </li>
    </ul>
  </div>
</template>
```

> [!TIP]
> Implementasi `onUnmounted` di atas adalah wujud nyata dari *Memory Management di Vue 3*. Hook ini memastikan socket ditutup secara eksplisit saat komponen dihancurkan, mencegah *orphan connection* yang menguras resource server.

## 7. Pertolongan Pertama: Jika Terjadi Kendala Kecil

Jika Anda mendapati koneksi WebSocket langsung terputus dengan kode `1006` sesaat setelah dibuka, biasanya Nginx memutus koneksi karena *proxy_read_timeout* terlalu pendek atau ada aturan WAF/Cloudflare yang memblokir header `Upgrade`. Pastikan Anda menonaktifkan fitur caching Cloudflare untuk subdomain WebSocket (`ws.*`) karena proxy edge mereka secara default tidak mendukung koneksi persisten HTTP/1.1 Upgrade pada paket gratis.