Build a Real-Time Dashboard with Vue 3 and WebSockets

Build a Real-Time Dashboard with Vue 3 and WebSockets

Build a Real-Time Dashboard with Vue 3 and WebSockets

Build a live dashboard that updates metrics in real time — simulating a server monitoring or analytics use case.

Features

  • Real-time data via WebSocket connection
  • Live updating line charts with Chart.js
  • Connection status indicator with auto-reconnect
  • Pinia store as single source of truth for metrics
  • Configurable alert thresholds

Step 1 — WebSocket Composable

// composables/useWebSocket.js
import { ref, onUnmounted } from 'vue'

export function useWebSocket(url) {
  const status   = ref('connecting')
  const messages = ref([])
  let ws, reconnectTimer

  function connect() {
    ws = new WebSocket(url)

    ws.onopen    = () => { status.value = 'connected' }
    ws.onmessage = (e) => messages.value.push(JSON.parse(e.data))
    ws.onclose   = () => {
      status.value  = 'disconnected'
      reconnectTimer = setTimeout(connect, 3000) // auto-reconnect
    }
    ws.onerror   = () => { status.value = 'error' }
  }

  function disconnect() {
    clearTimeout(reconnectTimer)
    ws?.close()
  }

  function send(data) {
    if (ws?.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify(data))
    }
  }

  connect()
  onUnmounted(disconnect)

  return { status, messages, send, disconnect }
}

Step 2 — Metrics Store

// stores/metrics.js
export const useMetricsStore = defineStore('metrics', () => {
  const cpu    = ref([])
  const memory = ref([])
  const labels = ref([])

  const MAX_POINTS = 30

  function addDataPoint(data) {
    labels.value.push(new Date().toLocaleTimeString())
    cpu.value.push(data.cpu)
    memory.value.push(data.memory)

    if (labels.value.length > MAX_POINTS) {
      labels.value.shift()
      cpu.value.shift()
      memory.value.shift()
    }
  }

  return { cpu, memory, labels, addDataPoint }
})

Step 3 — Dashboard Component

<script setup>
import { watch } from 'vue'
import { useWebSocket } from '@/composables/useWebSocket'
import { useMetricsStore } from '@/stores/metrics'

const { status, messages } = useWebSocket('ws://localhost:8080/metrics')
const metricsStore         = useMetricsStore()

watch(messages, (msgs) => {
  const latest = msgs[msgs.length - 1]
  if (latest) metricsStore.addDataPoint(latest)
}, { deep: true })
</script>

<template>
  <div class="dashboard">
    <span :class="`status-${status}`">● {{ status }}</span>
    <MetricChart title="CPU %" :data="metricsStore.cpu" color="#FF6384" />
    <MetricChart title="Memory %" :data="metricsStore.memory" color="#36A2EB" />
  </div>
</template>
All Comments