This is not your typical "paste this here" and "paste that there"-type tutorial (you can find plenty of those here on cometchat.com/tutorials). While those tutorials certainly have merit, I am going to share my thought process from beginning to end.
The application I built is simple enough. When someone loads the app, they are prompted to enter their username and begin chatting:
The application ultimately runs on Node with help from NW.js (previously known as node-webkit). NW.js is advantageous because it enables us to code cross-platform desktop applications using our favorite web technologies. For this application, I chose to use React and Redux.
The back-end logic - from sending and receiving messages in real-time to populating what I call the "participant list" - is powered by CometChat. You will learn more about CometChat as you read on.
This post is not intended to be a walkthrough. Although I will be explaining the technical components of this application, my main ambition is to help you think through a solution from beginning to end. Hopefully, when you finish this post you'll be a slightly better developer and consider CometChat for your growing tool belt.
Just want the example code?
Because the desktop app is built using web technologies, it is entirely possible to run it in your browser. Towards the end of this post, I will show you how to deploy the app on Netlify.
To follow this tutorial or run the example source code you'll need to create a V1 application.
v2 will be out of beta soon at which point we will update this tutorial.
In this section we have to decide what components will we need to build. What functionality will they have? In other words, what are the questions we need to answer, to plan the building process?
Let’s step back for a while and think. Try asking yourself the questions who will take us to the structure we need for our app.
Below I am going to lay out my questions and the answers. This is the process of the actual building the structure of the app, but in your head first. Keep in mind that it happens very often such that when answering a question new questions appear. This was the case with me as well.
What am I doing? 😆
What kind of app am I going to be building?
What are the most common components, such an app needs to have?
How do the app’s components interact with each other?
What level of completion am I aiming for — (demo apps are not supposed to be fully featured)?
Answers (following the order of the questions):
This is the most neglected question that many people forget to think about. When one can step aside first and give a clear answer to this question, his path for future developments becomes settled. In my specific case the answer I got sounds something like this — “I am thinking about building a chat app. This app should serve as a tutorial demo app. It will have to provide basic functionality for ‘having a chat’ by using CometChat API. It should run on a desktop”. The styling and specific details about what goes where will come later in the process.
A chat app that will run on desktop and serve as a demo for this tutorial.
To give a proper answer to this question, a non-familiar person would have to do some research first. Take a look at real-world chat applications. Make notes of what features they have. How are they put them in place, how do they interact between them and with the users of the app. In my case, I had some previous experience and got, more or less, the idea of what I need.
The interaction between the components would be pretty straight forward. The user should be able to use the main component that is a text input and a button to send messages. And a sidebar component to see the other chat participants.
The demo app should provide basic chat functionality — send and receive real-time messages. And be able to run on a desktop (without a browser).
I have decided to implement the following features to the demo app:
Send with Enter key
A sidebar with names and last active time
Welcome screen with input and validation with error messages
Chat area with auto-scroll to bottom
Chat message and time of sending.
Front End — React
We are going to use React to build our user interface. Below, I am going to list the components I have created and a short explanation about each of them:
ChatPane — this is the main container-like component that contains the Participants and Conversation components and passes the data they need to visualize.
Conversation — this is the component responsible for typing and sending chat messages.
Footer — displays a simple footer message, containing the app name and version, as defined in package.json file.
Header — header component holding the application menu bar.
MenuAppBar — application menu bar component, simulating how a real menu bar would look like. The hamburger menu on the left and the profile dropdown menu on the right are fake — clickable, but not functional.
Messages — a container component, holding a message itself — it has the name of the sender, the message content and the time of sending.
Participants — this component shows the name of a chat member and the time when he joined.
Welcome — this component is responsible for displaying the login page — the starting point of our app, where we have logic related to checking for certain allowed usernames and storing them to the local storage for later use. I also implemented basic error handling logic, which shows an error when the selected username is not correct, as per CometChat API (in this specific case for our demo) registered usernames — superhero1, superhero2 and so on till 5.
Here a visual representation of the app components:
State Management — Redux
Every modern application these days has a state. Place in the memory where the application is storing certain data for later use. For our application state management, we use Redux. Of course, for a simple app like this, we could go without using Redux at all. But, from the learning point of view (after all we all do this for learning new stuff, right?), I think it would be nice to see the whole cycle of sending a request to an API, going through a middleware (redux-thunks) and getting the response recorded to the state. And we will manage this state by using Redux.
How it works
The main building blocks in a Redux app are called reducers — small functions used for managing the state. Simply said, what they do is accepting the old state object as input and, depending on certain actions (which are also passed in the same input), returning new state object. The new state could be changed in full or just partially.
In our app, we have three simple reducers, which are responsible for those parts of the state, responsible for the users’ list, the login process and sending/receiving messages. All of them can be seen in /src/reducers folder, along with a file containing the initial state of our app.
Redux, as state management library, can be used with any other UI framework, practically every app that needs to have a state can benefit from using Redux. If you want to go deeper, start from their website and follow along.
Side Effects Handling — Redux Thunks
One of the best known approaches for managing side effects in a redux app is called redux-think. This is what we use in our application as well. If you want to learn more details about redux thunks and how to use them, I recommend their website as a starting point and then build a small application, like this one for example :).
Make it desktop — NW.js
Since we mentioned the other big player in the field of building cross-platform desktop apps, let me give you a brief comparison between the two.
Nw.js vs Electron
Entry of Application
In NW.js the main entry point of an application is a web page or a JS script. You specify an HTML or js file in the package.json and it is opened in a browser window as the application's main window (in case of an HTML entrypoint) or the script is executed.
Nw.js uses Chromium
Electron uses libchromiumcontent to access Chromium's Content API. libchromiumcontent is a single shared library that includes the Chromium Content module and all of its dependencies.
In NW.js, the Node integration in web pages requires patching Chromium to work.
In Electron uses a different way to integrate the libuv loop with each platform's message loop to avoid hacking Chromium.
Because of how NW.js was implemented concepts of Node context and web context were invented.
Chat — CometChat
The usage of CometChat API is pretty straight-forward. It’s a RESTFull API, on which is built another layer of abstraction - CometChat SDK. It allows us to call directly exposed methods for different actions we might want to perform, such as send. Here an example of such a method:
You may see all the Chat API logic in /src/chat-api folder. There you will also see the mocks I created, which allow us to test our app without real connection to the API.
Every project deserves some thoughts after finishing the first phase. One part of this thought process would be dedicated to how it went, what was good and bad, and what might be done better. And one part would be dedicated to thinking about possible improvements.
Here are a few ideas for our case. If someone goes to this direction and implement any of these for real, please do not forget to let me know :)
Waiting animation for when loading the chat history and the user list
Option for skipping the login screen, if already logged
Option for sending invitations to new users
Option for seeing the status of a message — sent, received, read
Inline links/images/video support, such that the user can see them interpreted — playing video, rendered image or web page to which a link is pointing.
I have added these as issues in my GitHub, in case anyone wants to take a look.
Deploy on Netlify
To deploy your application to Netlify platform you need to create an account first. Go to their website and sign up for new account. After that go ahead and login. While still under Sites section, you should see a button for deploying new site from Git.
Click it and follow the steps to create a new site for deployment from your GitHub repositories. Your process should be similar to what is shown in the image below.
Now, the last step before having your app deployed is to make sure you have the correct build commands and environment variables in place. To do that, after you create your site for deployment, go to Build & deploy settings screen and enter the following (don’t forget to use your repo URL):
Under Environment section is where you need to enter the environment variables as defined in your .env file. Here is how it looks mine:
Note: I have erased the values as this is supposed to be private info and you should not share yours as well.
That should be enough for you to have your app deployed on Netlify. Keep in mind the Deploys default settings are set to ‘auto publishing’, which means that it will trigger a deploy on each commit you do to the master branch in your repo. This is the place where you can trigger a deploy manually as well. This is how my Deploys screen looks like:
In this tutorial, we saw how can we leverage our web development skills to create applications that can run on a desktop. What we built is a demo application, that lacks a lot of a fully-featured-production-ready app features, but when one wants to learn and share, this would do the job. If you would like to deepen your knowledge in this direction, I would recommend you to try to improve it, by implementing features that are more likely to be seen in a real desktop application.
There are plenty of opportunities to explore out there, I hope this tutorial entertained you enough to keep your flame of curiosity burning even more.
🔥 Thanks for reading! 🔥
In order to use Nw.js DevTools you need to install the SDK build — https://nwjs.io/downloads/ - version 0.38.2 or higher.
_Q: What is a ‘thunk’? A: The sound your head makes when you first hear about redux-thunk. Ok sorry, that was awful. But…_daveceddia.com
[book] Cross-Platform Desktop Applications: Using Node, Electron, and NW.js
[book] Cross-platform Desktop Application Development: Electron, Node, NW.js, and React
_Thunk middleware for Redux._github.com