</>tl;dr quick start code
Try the Vue Chat Demo App. The tutorial is more detailed than the quick start code, but it's better to start simple. The following code will get you started. We will exclude the fancy CSS3 animations for now.
Chat is everywhere and has ascended to one of the most important communication mediums across our daily lives. The number of chat app use cases is vast and continues to grow. And with today’s technological advancements, we expect our messages to send and receive in realtime, instantaneously. It’s not a nice-to-have, it’s a requirement.
There are thousands of ways to build a chat app, and there are many things to consider: infrastructure, scalability, reliability, and security to name a few. With a vast amount of services, frameworks, and technologies to choose from, making that decision can be overwhelming!
In this tutorial, we’re going to build a realtime group chat app in Vue.js. We’ll power our app using PubNub, which takes care of the heavy work for us; all we have to worry about is developing the app, not the underlying infrastructure.
Our application will send messages to all connected users in the group chat using publish, and receive messages using subscribe. Our messages will be stored using history, so users can see past or missed messages. To do all this, we will use the PubNub Vue.js SDK. This tutorial is broken into two sections: Publish/Subscribe (Pub/Sub) and History.
Before we start working on the app, we need to sign up for a free PubNub account to create your Pub/Sub API keys. Sign up and log in using the form below:
Next, we need to install two dependencies: vuex and pubnub-vue. We can use NPM to do so.
$pnGetMessage with a reactive property so messages display as soon as they are received. To subscribe to a channel we use $pnSubscribe and to publish to a channel we use
In the main.js file, create a unique UUID for each user and replace the pub/sub keys with your keys. We include two plugins: PubNubVue and Vuex.
Next, we generate a random 4 character UUID for the user by making a call to the function
It ’s recommended to use a standard 128-bit UUID in production apps, but the UUID can be a plain string as well, as is the case for this app. The constant ‘me’ holds the UUID. To commit the constant to the Vuex store, we add the function created.
This function will execute when the Vue instance is created.
For the store.js file, we set up the centralized store that holds and manages the application state. The file will contain a global state object along with a collection of mutation and getter functions. Since outside components cannot access the state directly, we need to commit a mutation every time we update the state.
The getMyUuid getter is referenced in three of the components and is a global getter for the UUID.
The ChatContainer component is the highest parent node of the UI. The markup includes
custom HTML tags for the children components of ChatContainer, as well as Vue specific markup to reactively render data.
Before we discuss the variable uuid, let’s discuss the imports and the two properties above
Since we are using the chat-log and message-input tags in the markup, we need to import the ChatLog and MessageInput components so the tags are rendered properly. We also import mapGetters to get the UUID from the store.
The name property is ‘chat-container ’ and it coincides with the kebab-case HTML tag name in the markup. We include the components property to tell Vue which components are being referenced in the markup.
Getting back to the variable uuid in the h1 curly brace, we need to set up the computed
property which uses mapGetters to map the getter ‘getMyUUID’ to uuid.
Since we are mapping the getter to a different name (uuid), we use an object. Finally, we include the function mounted to subscribe to the channel ‘vueChat ’.
We subscribe, using $pnSubscribe, to the channel once the Vue instance is mounted to the
We break this component into 4 parts:
Here is the template for the component.
When the user types in the message body and presses enter, the function submitMessage is called to check that the message body is not empty. This function is called inside of
methods . (Note: The rest of the code for MessageInput Component will be inside of
We access the getter, getMyUUID, and assign it to the variable userUUID.
If the user presses enter and the message body is not empty, we publish to ‘vueChat‘ the text and the user’s UUID.
We reset the text input once the user presses enter.
The chat log will display the messages sent and received in a message bubble. We ’ll get to the chat log component in a bit, but for now, let’s focus on the message bubble component. When you send a message, the message bubble is shown on the right side of the chat log without displaying your UUID. The messages received from other users are shown on the left side of the chat log with the users UUID shown above the bubble. This follows the design logic of many group chat apps.
The class ‘me ’ is bound to a class, such as ‘message-bubble ’ or ‘from ’, only if you send the message. When ‘me ’ is bound to a class, the positioning and styling of the message bubble will change, as mentioned above. A computed property is used to check if the user is yourself or someone else.
Besides the computed property, another important part in the script are the prop attributes that are registered to the MessageBubble component. The two values in the prop, ‘uuid ’ and ‘text ’, will be passed to MessgeBubble’s parent component, ChatLog.
The chat log displays the messages once it’s received in the channel. Before we work on the template, let’s do the script section first.
Since we ’ll be using the message-bubble tag in the markup, we import the MessageBubble component in the script so the tags are rendered properly. The scrollBottom function auto scrolls the chat log to the bottom whenever a message is received. This function is called in the watch property.
We use .$nextTick to make sure the scrollBottom function is called only after the DOM has been updated. Next, let’s add the name property, components and the data function.
The data function returns vueChatMsg, which contains the new message payload from the channel. As mentioned before, since we are using $pnGetMessage, the messages will display as soon as they are received. We include the channel name as a parameter.
The vueChatMsg property holds an array of objects where every object of the array is the Subscribe Message Response . For every message published, a new message response is added to the array. The objects in the message response includes information such as the channel name, the publisher, the message payload, the subscriber, and so on. We only want the message payload which includes the ‘uuid ’ and ‘text ’. We will implement this logic in the template.
We use v-for to iterate vueChatMsg with ‘msg.id ’ as the unique key. We use v-bind to bind the two prop values, ‘uuid ’ and ‘text ’. Remember that we declared the prop in the child component MessageBubble. So for every iteration of the for loop, we only iterate the message payload and bind ‘msg.message.uuid ’ and ‘msg.message.text ’ to its corresponding prop attribute.
Let’s quickly summarize the above. Every time a message response is received, it is added as a new element to the array of objects, vueChatMsg , which is returned by the data function. When this happens, inside the message-bubble tag we iterate, using v-for, the new element in the array. Since we only want the message payload, v-for only checks for ‘message ’ which contains the payload. The payload values ‘uuid ’ and ‘text ’ are bind to its appropriate props. Both values are then sent back to the child component, MessageBubble.
That’s all for the Pub/Sub section of this tutorial. Make sure that the code is correct and that you have installed the appropriate plugins. Get the CSS section of the four components from the repo . Run your program by typing ‘npm install ’ and ‘npm run dev ’ in the terminal and your program should start on a localhost port. Type a message in the message input and you should see a blueish bubble on the right side of the chat log. Open another tab, or preferably window, and copy and paste the URL. Now type a new message in the message input and again, you should see the blueish bubble on the right side of the chat log. But now, you should also see the new message on the other chat log. This new message should be a greyish bubble on the left side of the chat log. Play around with both chat windows and see the messages appear in realtime on both screens.
While everything is set up and ready to use, there is one problem. If you reload the page, you will notice that all the messages disappear. This occurs because the Storage &Playback feature is not turned on. To turn it on, go to the PubNub Admin Dashboard and click on your application. Click on Keyset and scroll down to Application add-ons . Keep scrolling down until you get to Storage &Playback and toggle the switch to on . Keep the default values the same.
Now that it’s on, messages will persist in storage and can be retrieved later on. Messages can also be deleted from history to meet GDPR compliance.
If you cloned the repo, then reload the page for the chat app and the messages should appear in oldest to newest order. If you didn’t clone the repo, the messages won’t appear since the history function, which fetches historical messages of a channel, has not been added to the code. Either way, in the next section, we will implement the history function so messages can be stored and retrieved.
Fetching the historical messages of our channel is not difficult to do. We need to make small modifications to three files: store.js, ChatContainer.vue, and ChatLog.vue. Let’s start with store.js.
In the state, we need to add a new property, history, with an empty array as the value.
In mutations, we add a new mutation, addHistory, with state as the first argument and history as the second argument.
We iterate the array history that contains the historical messages retrieved from the channel. Each element in the array contains two keys, timetoken and entry. We only want entry since it contains the text the user entered and their UUID. This is why in each iteration we push
element.entry to the history array we added in state.
We will only add one line to getters.
Since we need to use the history function, import PubNubVue.
Below the imports, we add a new function, fetchHistory, that will fetch 6 messages from the channel. You can change the number of messages to fetch with 100 being the max number.
To commit the history payload, save response.messages to the constant variable ‘msgs ’. The constant contains an array of objects where each object contains two keys (timetoken and entry) . We don’t want to commit the whole array to the Vuex Store, rather, we want to iterate the array and commit each element. This will make it easier to fetch the necessary keys in the addHistory function.
The last modification to include is in mounted which makes the call to fetchHistory.
We pass this.$store as a parameter so we can commit the changes to the store.
This is the last file we need to update. We need to make changes to the template and the script. Let’s start with the script. We need to import mapGetters since we will be using it in the computed property.
In the computed property, we map the getter ‘getHistoryMsgs ’ to history.
In the template, we add another message-bubble tag.
This looks very similar to what we did earlier. We use v-for to iterate history. At every iteration, we retrieve the ‘uuid ’ and ‘text ’ from the array and bind it to its appropriate prop attributes. The messages will show in the chat log as message bubbles.
That is all we need to do for history. Run the program again and you should see the last six messages from history in the chat log.
There are two things to take note of. The first thing is that the messages will persist in storage for 1 day only. After 1 day, the messages are removed from storage. You can change the time period a message is stored by changing the retention time, which is located in the Storage &Playback add-on. For the purpose of this tutorial, we leave the default value of 1 day.
The second thing to note is that the history messages will show on the left side of the chat log, even if the messages are from you. This is because we generate a random 4 character UUID every time the app instantiates. So when you reload the page, a new UUID is assigned to you and the previous messages you sent before the reload will now be seen as messages sent from another user. This is fine for this tutorial, but for real production, each user should have a unique UUID that is persistent. For a persistent UUID, the history messages that are sent by you will show on the right side of the chat log.
Thanks for reading!
Now that you’ve got your basic messaging functionality implemented, it’s time to add more features! Head over to our Chat Resource Center to explore new tutorials, best practices, and design patterns for taking your chat app to the next level.
Protecting your users and the data in your chat app is paramount. Taking a couple considerations into mind when building a chat app can save you a ton of headaches down the road. PubNub is built for security first, with all the SDKs having end-to-end encryption and access management (via PubNub Access Manager), for fine-grain control over user permissions.
You need to deliver a seamless chat experience for your users, no matter where they are on Earth. PubNub delivers reliability and scale for chat applications, from development, to deployment, to your app becoming the next big thing.
PubNub is globally scaled with 15 points of presence spread across the globe, so you get low-latency chat anywhere on Earth. And with a ton of features focusing on reliability like message catchup/caching and fast, efficient realtime protocols, your chat app scales as your users grow, without all the headaches of maintaining and orchestrating a messaging backend.