We worked on this as a group project after constructing our own chat apps.
Contributers:
If you'd like to create the next SnapChat, proceed.
If you'd like to be the creator of a new and improved SnapChat, read on.
You still there? Awesome. Thanks for checking out our tutorial!
Today you'll learn how to create your first functional, peer to peer, chat app. For many beginner JavaScript developers, building one of these has become somewhat of a rite of passage so congratulations, welcome to the club. Chat app projects are a good place to test your budding Javascript skills because it's framework comprise of complex yet accessible parts.
Here, we'll show you the basic framework. And from the framework, we'll go on to teach you how to style, test, and host your site! Sounds like a lot right? Don't panic, youre in good hand. By the end of our tutorial, you'll be able to build features that go above and beyond the SnapChat-standard.
We'll teach you what a server and client does and of course give you instruction on the code to make the server and client connect with each other.
By the end you will have learned: how to create a server and client, how to get them communicating with each other, how to style the app, how to test it, how to host it, and finally, how to impress the internet by pushing your code to Github.
###WebSockets
A WebSocket is a technology, based on the WS protocol, that makes it possible to establish a continuous full-duplex connection stream between a client and a server. A typical WebSocket client would be a user's browser, but the protocol is platform independent. The WebSocket API is available to JavaScript code whose scope is either a DOM Window object or any object implementing WorkerUtil.
The WebSockets API was originally part of the HTML5 standard, but it has been split off into a separate W3C standard. The WebSockets protocol is an IETF standard described in RFC 6455. The WebSockets API has full browser support in Chrome 14, Firefox 6, IE 10 (desktop and mobile), Opera 12.1 (desktop and moblie), Safari 6.0 (desktop and mobile), Android 4.4, Chrome Mobile, and Firefox Mobile. Some older browsers have partial support or can be supported using a Flash based fallback.
This simple example creates a new WebSocket, connecting to the server at:
var WebSocket = require("ws");
var ws = new WebSocket("ws://localhost:3000");
ws.on("open", function () {
console.log("Connected to server.");
});
#Git & Github
The git init command creates a new Git repository. It can be used to convert an existing, unversioned project to a Git repository or initialize a new empty repository. Most of the other Git commands are not available outside of an initialized repository, so this is usually the first command you’ll run in a new project.
The git clone command copies an existing Git repository. This is sort of like svn checkout, except the “working copy” is a full-fledged Git repository—it has its own history, manages its own files, and is a completely isolated environment from the original repository.
The git config command lets you configure your Git installation (or an individual repository) from the command line. This command can define everything from user info to preferences to the behavior of a repository. Several common configuration options are listed below.
Linktos or Asides or Syntax Bubble:
Executing git init creates a .git subdirectory in the project root, which contains all of the necessary metadata for the repo, and makes it possible to start recording revisions of the project..
$ git clone <repository link>
Clone the repository located at onto the local machine. The original repository can be located on the local filesystem or on a remote machine accessible via HTTP or SSH.
To update your local repository to the newest commit, execute git pull in your working directory to fetch and merge remote changes.
Assuming you've already created a folder inside your text editor. Now its time to create a github repo and push to github.
- Navigate to the working directory
$ cd tutorialChatApp
- Check status & proceed
$ git status
- Add any changes - note
add .
will add all but you can also specify files
$ git add .
- Commit your changes - whatever you write here will help in tracking changes
$ git commit -m "First commit"
Your changes are now in your local working copy.
- Push up to git via https (not SSH)- granted you have no troubles with your log in. Make sure
$ git push origin master
#Back end
##Ws
A websocket server can receive and send data among multiple clients, and is necessary to host your chat app. The purpose of this server is to relay messages, This code will require several crucial lines of code, but additional features can be added to make your chat app more robust.
-
First, the ws module must be required.
var WebSocket = require("ws").Server; var chatServer = new WebSocket({port:3000});
Note that the Server method is necessary when requiring ws for the purpose of creating a server. A port number of your choice should be declared, but it must consistent across future code in order for the server and clients to interact.
2. An empty array should be created to track clients connecting to the server. This will allow the server to send information to multiple clients at once.
```
var users = [];
-
Event listeners are added to the server in order to define how it handles connections and messages.
chatServer.on("connection" , function(ws){ console.log("connection"); users.push(ws); }
The above code adds every connecting client to the users array, and console logs a simple message that will help you monitor /test functionality. Nested within the above function, you must also add event listeners to the clients, which are defined above by the ws parameter.
```
ws.on("message" , function(msg){
console.log(msg);
users.forEach(function(usr){usr.send(msg)});
})
-
Every time there is a message event, the above code will log that message on the server console, and send the message to every user in the users array, including the original sender.
-
This next step is virtually essential. In the event a client disconnects, any attempt the server makes to send a message will cause it to crash. We must add another event listener to the client that will remove it from the users array on a close event.
ws.on("close" , function(){ var clientIndex = users.indexOf(ws); users.splice(clientIndex,1); console.log("a client has disconnected"); })
Every time a client disconnects, the above code finds the index of that client with the users array, and then deletes their information from the array. This code in its current state is completely usable for the purpose of serving a simple chat app.
```
var WebSocket = require("ws").Server;
var chatServ = new WebSocket({port:3000});
var users = [];
chatServ.on("connection" , function(ws){
console.log("connection");
users.push(ws);
ws.on("message" , function(msg){
console.log(msg);
users.forEach(function(usr){
usr.send(msg)});
})
ws.on("close" , function(){
var client = users.indexOf(ws);
users.splice(client,1);
console.log("a client has disconnected");
})
})
```
Other possible features you might want to consider adding to your app are a persistent message history, private messages between users, and word filtering functions. Incorporating JSON into your code will allow you to package more information in every message beyond simple strings.
<br>
---
#Front end
---
<h2 id = "4">Client files</h2>
---
####HTML file
Let's make a barebones HTML file that'll allow us to use the client for the chat app.
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- link to style sheet - we'll get to his later! -->
<link rel="stylesheet" type="text/css" href="tutorialStyle.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chat</title>
</head>
<body>
<!-- In the beginning there was a div for the header -->
<div class="header">
<h2>A Tutorial Chat App</h2>
</div>
<!-- But! Here's a div that binds them all! -->
<div class="container">
<!-- and in the darkness... presents the message... -->
<div id="inset">
<!-- but first this div collects your name! -->
<div id = "fixed">
<p id="enter"> Please enter your screen name:</p></br>
<input type="text" id="inputName" placeholder="Name"></input>
</div>
<ul id="msgHolder"></ul>
</div>
</div>
<!-- This div holds the input box -->
<div class="bottom">
<!-- <div class="bottom"> -->
<input placeholder="Type here" id="inputMsg"></input>
<!-- </div> -->
</div>
<script type="text/javascript" src="tutorialclient.js"></script>
</body>
</html>
---
###Client JS file
---
In order for the client to connect to the server we'll want to set up some variables.
1. Establish a new Websocket client. Remember to be explicit in naming your variables!
```
var client = new WebSocket( "ws://localhost:3000" );
-
Let's say that our client is going to log in and have a name. But prior to connecting the name will be a string that is empty.
var userName = ''; var connected = true;
3. Let's setup event listeners for the client to determine what's happening.
```
client.addEventListener( 'open', function ( evt ) {
} );
client.addEventListener( 'message', function ( message ) {
} )
client.addEventListener( 'close', function ( evt ) {
} );
```
4. Now to get more detailed...
Upon connecting ('open') we want the client to set their name. In order to do this, let's have them send a message that changes their `userName` value. We'll utilize DOM manipulation and a keyboard event listener to do that.
```
// upon open
client.addEventListener( 'open', function () {
// grab inputTwo
var inputTwo = document.getElementById( 'inputTwo' )
// event listener on inputTwo
inputTwo.addEventListener( 'keyup', function ( e ) {
// if enter is pressed and the box is NOT empty
if ( e.keyCode === 13 && inputOne.value.trim() != '' ) {
// set the userName value...
var fixedDiv = document.querySelector( '#fixed' )
userName = inputOne.value;
// and grab the fixedDiv and set it's style to make it disappear!
fixedDiv.style.display = 'none';
}
} );
} );
```
5. Now that we've set our client's name upon connect, let's tackle what happens when we recieve a message.
```
// upon recieving a message
client.addEventListener( 'message', function ( message ) {
//create an li element
var li = document.createElement( "li" );
// change it's innerText value to the recieved message
li.innerText = input.value;
// set it's id to 'msg'
li.setAttribute( 'id', 'msg' )
// grab the ul element
var msgHolder = document.querySelector( "ul#msgHolder" );
// and append it to include the new li
msgHolder.appendChild( li );
// then have it display BEFORE the newest element
var before = ul.firstChild;
ul.insertBefore( li, before )
} );
```
6. While we're not doing anything complex yet, you can certainly have events occur upon close. Let's make a couple edits to display this.
We'll add a boolean to the file...
```
var userName = '';
var connected = false; //set to false by default
```
..and have it return true upon connect...
```
client.addEventListener( 'open', function () {
connected = true;
```
..and have it return back to false upon close!
```
client.addEventListener( 'close', function () {
connected = false;
```
While not necessary in our tutorial app, just note that it's possible to have events occur on the client side but you can't send anything to the server upon close.
7. BUT WAIT! How on earth do we send messages?!!
Well.. there's an app for that...
But seriously...
We've already done it upon connection so let's make another event listener.
```
// grab the inputMsg element
var inputMsg = document.getElementById( 'inputMsg' )
inputMsg.addEventListener( 'keyup', function ( e ) {
// upon pressing enter
if ( e.keyCode === 13 ) {
// grab the text in the input box and call it newMessage
var newMessage = input.value;
// with the .send method let's format and send our name & message
client.send( userName + ': ' + newMessage );
// finally, let's clear the input box
input.value = ''; //clear the input area
}
} );
```
And now you have your javascript file for your client!
<br>
---
<h1 id = 5>Local Testing</h1>
---
It's important to local test your site as much as possible but mainly after you get it set up and have finished each feature. make sure to put console.log() at different places in your code so that you can debug and know where your code is getting to and where it might be breaking.
1. Navigate in terminal to folder
Open up a terminal window and navigate into the folder that holds your Chat App
```
$ cd tutorialChatApp
-
Open your index.html file
To see your Chat App on the client side you will need to open your html file locally to show you what if would look like and if your chat features work.
While your in your folder, type in the command to open the index.html file.
$ open index.html
-
OOPs! An error occurred!
Before we can actually use our Chat App, we will need to run our Node.js file as well as understand what to look for with errors.
If on mac: press CMD + ALT + I on your keyboard. This should bring up the developer tools at the bottom.
Navigate to the console by clicking on the console tap in the top nav bar.
This console area will show if you what errors occur and on what line they occur in what file (client or server side). Also you can see how many errors have occurred total from any window in the developers tools by looking in the top right hand corner of the window.
-
Run tutorialServer.js file
The first thing we need to do and should of done to test locally was run our Node.js file and start up our server side javascript.
Start by navigating into the folder with the Node.js file and then type in the command:
$ node tutorialServer.js
Then press enter. you should see the cursor go the far left hand side on the next line. It is now listening for a client connection. If you ever see an error in the developer tools: “web socket console is closing or is already closed”, probably need to come check this terminal to see if there was an error thrown.
If there was an error thrown the server will shutdown and it will tell you what line and the error to look for. debug this and then try again.
-
Refresh HTML file
Now that the server is running, go refresh your index.html page in the browser
-
Check for console errors and debug!
Now open the developer tools and check for console errors.
If there are errors find where they are fix them and save the file.
Then try again.
We'll reference some of our HTML tags here so please feel free to review or refer to the client section. //add links
####Divs Divs Divs - All about dem divs
In order for us to have a responsive (and what other way is there to be?!) design let's start with some givens.
-
Flexbox ex: vertical centering made easy! This alone will make your CSS life easier
-
Use percentages and vh instead of fixed pixels when able to in order to have a relative design. [provide links on the side to responsive design] With the following snippet in your header you're establishing that the width of the content will be the device width, and with percentages you should be able to have easy responsive design.
-
Framework your design, whether by hand, inDesign, photoshop or just with divs alone before you start so you have a path.
-
A good tip to remember while working with divs is to give them all different colored borders so you can tell where they are exactly and help you position them as well. This is espescially convenient when planning to make your site responsive. For example here are 2 divs that we'll be working on:
div.container { border: thin solid black; height: 80%; width: 80%; margin: auto; } .bottom { border: thin solid orange; height: 40px; width: 80%; margin: auto; }
---
####Creating the CSS file
___
1. Please note that while we refer to the divs as `div.whatever` it's only to point it out to you. Let's set up all our divs now so we can view the frame:
```
div.container {
border: thin solid black;
height: 80%; /* set to 80% of the body */
width: 80%; /* set to 80% of the window */
display: flex;
margin: auto;
}
div#fixed {
border: thin solid black;
min-height: 10vh; /* vh is viewport height - this says 10% of vh*/
margin: auto;
text-align: center;
padding: 2%;
overflow: auto;
}
div#inset {
border: thin solid red;
height: 100%;
width: 100%;
min-width: 30vh;
overflow: auto;
align-self: center;
display: flex;
flex-direction: column-reverse;
}
div.bottom {
display: flex;
border: thin solid orange;
height: 40px;
width: 80%;
display: flex;
margin: auto;
font-size: 1.25em;
}
-
Working from top down, we'll style the header:
.header { font-size: 100%; /*set the font-size to 100% (note the %)*/ text-align: center; /*set the text-align value to center*/ width: 50%; /*we'll establish the width at 50%*/ margin-left: 25%; /*as we've set the width to 50% we can set the margin-left at 25% thereby centering the element*/ }
-
We are setting the container div to have
display: flex;
in order to easily vertical center the fixed div that'll appear upon login.div.container { height: 80%; width: 80%; display: flex; /* Hey Alex... FLEXBOX! */ margin: auto; } div#fixed { min-height: 10vh; margin: auto; /*setting the display of the parent to flex lets you vertical center with just this line!*/ text-align: center; padding: 2%; overflow: auto; } p#enter { font-size: 80%; line-height: 10%; vertical-align: top; }
Note that we've removed the borders now and have styled the components of the div that will disappear upon recieving client name as well.
4. Continuing with our responsive design let's edit the `div#inset` and the `div.bottom`.
```
#inset {
background-color: #1a1a1a;
color: #2cbda9;
height: 100%;
width: 100%;
min-width: 30vh;
overflow: auto;
align-self: center;
display: flex;
flex-direction: column-reverse;
}
.bottom {
display: flex;
background-color: #333;
height: 40px;
width: 80%;
display: flex;
margin: auto;
font-size: 1.25em;
}
-
And finish off with the input elements and text...
input { border-style: none; background-color: #333; } #inputName { color: #ff323b; font-size: 1em; text-align: center; } #inputMsg { flex: 2; /*FLEXBOX! This flex setting allows us to span the input to the entire div*/ font-size: 1em; padding-left: 1%; /*When adjusting the blank space, remember to stay responsive!*/ background-color: #333; color: #ff323b; } li#msg { margin-right: 5%; list-style-type: none; }
###Voila!
![image](chatApp.png)
---
<h1 id = "7"> Hosting your chat app online</h1>
---
### Push files to Github
---
Before we can set up a the hosting side of things we need to make sure out github is up to date!
As you remember in steps one and two we set up the git repo and connected it to our github repo.
Lets push our files up to that repo:
1. first initiate push by typing in the terminal:
$ git add .
2. Then asign a commit log by typing in the terminal:
$ git commit -m “first commit”
3. then push it by typing in the terminal:
$ git push master origin
Your files are now ready on Github!
### Hosting through your server
---
In order to host your files on the internet publicly we'll need to set up your server. Let's SSH into the server.
1. Open up a new terminal window.in the terminal type:
$ ssh root@yourserveraddress
Have your login information handy as you'll need to enter it here
2. Clone the site's Github repo
* Now that we are in the server we need to clone our repo over so that we have all the files.
* Go to your github page and find the directory address and copy it.
* In the Server Terminal type:
$ git clone directoryAddress
3. Once it's cloned, type in `ls` in the command line and press enter. This should show you if it is in the directory. Move (`cd`) into the folder.
4. Run your tutorialServer.js file
* Now that we have our file all set up we need to start our server, run your node file just like you did in step 6. if you need help or reference, here is a link back the step.
* Now open up a new terminal and ssh into your server again using #2 in this step.
5. Http-server
* Once you have your second terminal open and your ssh’d in, its time to start up your server.
* In the terminal type in:
```
$ http-server -p80
```
This should start the server and allow you to go to the server address and see your chat app up and running. The -p80 at the end allows you to not have to have a subdomain and make a clean and tidy server address. If any errors occur you can see them on the terminal where you are running the node file and also in the client side browser in the developer tools.
6. Shutting down the server
* When you are done or need to fix a bug, press CONTROL + C at anytime to shut the server down. You will need to shut the node file down as well.