In this article I will show how to create a simple chat application using Svelte and Socket.io.
In the current iteration I've only implemented support for a single group conversation. Someone might be interested in extending this to support direct messaging between users as well.
The application consists of two main parts:
- Socket.io server
- Svelte chat component
Server
The server is configured to listen for “add-message” events. These events are triggered whenever a user sends a new message. The message is then broadcasted to all connected users.
let app = require('express')();
let http = require('http').Server(app);
let io = require('socket.io')(http);
io.on('connection', (socket) => {
console.log('user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('add-message', (message) => {
io.emit('message', {type:'new-message', text: message});
});
});
http.listen(5000, () => {
console.log('started on port 5000');
});
Svelte Component
The Chat component makes up the client side of the application.
Here is a screenshot of the application:
In addition to rendering UI for the chat, it also configures the socket based communication between client and server.
Here is the code for the component:
<h3>Svelte Chat</h3>
{{#if !loggedIn}}
<div class="form-group">
<input ref:user class="form-control" placeholder="Name" id="userName">
</div>
<button type="button" on:click="login()" class="btn btn-primary pull-right">Join</button>
{{else}}
<ul class="list-group">
{{#each messages as msg}}
<li class="list-group-item">
<div><strong>{{msg.from}}</strong><span class="time">{{msg.time}}</span></div>
<div>{{msg.content}}</div>
</li>
{{/each}}
</ul>
<div class="form-group">
<input ref:msg class="form-control" placeholder="Message" id="msg">
</div>
<button type="button" on:click="sendMessage()" class="btn btn-primary pull-right">Send Message</button>
{{/if}}
<script>
let socket = io('http://localhost:5000');
let user = '';
export default {
onrender () {
socket.on('message', (data) => {
let messages = this.get('messages');
let newMessages = [...messages, data.text];
console.log(newMessages);
this.set({messages: newMessages});
});
},
onteardown () {
socket.disconnect();
},
data () {
return {
messages: [],
loggedIn: false
};
},
methods: {
sendMessage ( ) {
let newMessage = this.refs['msg'].value;
if(newMessage) {
socket.emit('add-message', {content: newMessage, from: user, time: new Date().toLocaleTimeString()});
this.refs['msg'].value = '';
}
},
login() {
user = this.refs['user'].value;
if(user) {
this.set({loggedIn: true});
}
}
}
};
</script>
New messages from users are sent to the server using the Socket.io api. I am relying on Svelte data binding to display new messages in the UI.
I debated using two way data binding to capture user input, but opted for refs instead. There really is no need for two way data bindings here since I never have to bind values back to the inputs.
I have added the source to Github if you are interested in checking it out.
You can test out the chat by opening the app in multiple browsers and see that chat messages appear in all browser sessions.