Building a Real‑Time Video Chat Application with Vue, WebRTC, Socket.io, Node.js and Redis
This tutorial walks through creating a full‑stack video‑chat app that supports multiple chat rooms, private messaging, user status, and peer‑to‑peer video calls by combining Vue.js for the frontend, Vuex for state management, Socket.io for real‑time communication, a Node/Express backend, Redis for scaling, and Docker for deployment.
The article demonstrates how to build a simple yet functional video‑chat application from scratch, covering both frontend and backend components.
Application features include multiple chat rooms, user status (online/away/offline), private one‑to‑one chats, video calls via WebRTC, and a basic login interface.
Technology stack used:
Frontend: Vue.js, Vuex, vue‑material, vue‑resource, vue‑socket.io
Backend: Node.js, Express, Socket.io
Real‑time engine: Socket.io with a Redis adapter for scaling
Video: WebRTC (peer‑to‑peer signaling)
Containerisation: Docker & Docker‑Compose
1. Create the Vue project
npm install -g @vue/cli
vue create video-chatSelect Babel, Router, Vuex, CSS pre‑processor and Linter manually. Install the UI framework:
npm install vue-material --saveInstall socket and HTTP helpers:
npm install vue-resource vue-socket.io --saveConfigure the plugins in main.js :
import VueSocketIO from 'vue-socket.io'
import VueResource from 'vue-resource'
import store from './store'
import { url } from './utils/config'
Vue.use(new VueSocketIO({
debug: true,
connection: `${url}/video-chat`,
vuex: { store, actionPrefix: 'SOCKET_', mutationPrefix: 'SOCKET_' }
}))
Vue.use(VueResource)
new Vue({ router, store, render: h => h(App) }).$mount('#app')Set up the Vuex store ( store.js ) with state for the current room, username, status and the list of rooms, and define placeholder mutations and actions for joining rooms, sending messages, etc.
2. Backend server
Install server dependencies:
npm install express http body-parser path cors socket.io --saveCreate /server/index.js and /server/app.js to initialise the HTTP server, attach Socket.io and configure CORS, body parsing and static file serving.
const http = require('http')
const app = require('./app')
const config = require('./config')
const server = http.createServer(app)
app.io.attach(server)
app.io.origins([config.ORIGINS])
server.listen(config.PORT, () => {
console.log(`Server Listening on port ${config.PORT}`)
})Define REST endpoints for authentication and room management, then expose the static Vue build.
3. Socket.io events
In /server/chat_namespace/index.js register listeners for events such as joinRoom , publicMessage , leaveRoom , joinPrivateRoom , privateMessage , changeStatus , and the new WebRTC signalling event privateMessagePCSignaling :
socket.on('joinRoom', events.joinRoom(socket, namespace))
socket.on('publicMessage', events.publicMessage(namespace))
// … other events …
socket.on('privateMessagePCSignaling', events.privateMessagePCSignaling(namespace))Implement the callbacks in events.js , for example broadcasting a public message:
const publicMessage = (namespace) => ({ room, message, username }) => {
namespace.sockets.in(room).emit('newMessage', { message, username })
}4. WebRTC signalling
Use a private chat room as the signalling channel. The caller creates an RTCPeerConnection , generates an offer, sets the local description and sends it via the privateMessagePCSignaling socket event. The callee receives the offer, sets it as remote description, creates an answer and sends it back the same way. ICE candidates are exchanged similarly.
Key client‑side methods (simplified):
async createOffer() {
const offer = await this.pc.createOffer(this.offerOptions)
await this.pc.setLocalDescription(offer)
this.$socket.emit('privateMessagePCSignaling', { desc: offer, to: this.to, from: this.$store.state.username, room: this.room })
}
async setRemoteDescription(remoteDesc) {
await this.pc.setRemoteDescription(remoteDesc)
}The VideoArea.vue component handles media acquisition, attaching streams to video elements, and managing the peer connection lifecycle.
5. Scaling with Redis
Install the Redis adapter:
npm install socket.io-redis redis --saveAttach it to the Socket.io instance using configuration values from config.js :
app.io.adapter(redis({ host: config.REDIS_HOST, port: config.REDIS_PORT }))A small wrapper ( /redis/index.js ) provides addUser , getUser , etc., using Redis hashes.
6. Dockerisation
Define a docker‑compose.yml with three services: a Redis container and two copies of the chat application (different ports). The Dockerfile builds the Vue app with the appropriate socket host/port arguments and runs the Node server.
FROM node:8.6
WORKDIR /videochat
COPY package.json /videochat/
RUN npm install
COPY ./ /videochat
ARG VUE_APP_SOCKET_HOST=NOT_SET
ARG VUE_APP_SOCKET_PORT=NOT_SET
RUN export VUE_APP_SOCKET_HOST=${VUE_APP_SOCKET_HOST} VUE_APP_SOCKET_PORT=${VUE_APP_SOCKET_PORT} && npm run build
CMD ["npm", "run", "run:server"]Build and start the stack with docker‑compose build && docker‑compose up , then open two browser windows pointing to the two frontend instances to test video calls.
Conclusion
The guide shows that with relatively little code you can assemble a functional video‑chat system, and it outlines further improvements such as authentication, reconnection handling, advanced WebRTC features, multi‑party calls, and production‑grade security.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.