@ -21,3 +21,174 @@ First let’s create a `package.json` manifest file that describes our project.
"dependencies": {}
}
```
**CAUTION
The "name" property must be unique, you cannot use a value like "socket.io" or "express", because npm will complain when installing the dependency.**
Now, in order to easily populate the dependencies property with the things we need, we’ll use `npm install`:
```
npm install express@4
```
Once it's installed we can create an `index.js` file that will set up our application.
```java
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
```
This means that:
- Express initializes app to be a function handler that you can supply to an HTTP server (as seen in line 4).
- We define a route handler / that gets called when we hit our website home.
- We make the http server listen on port 3000.
If you run `node index.js` you should see the following:
![]()
# Serving HTML
So far in `index.js` we’re calling res.send and passing it a string of HTML. Our code would look very confusing if we just placed our entire application’s HTML there, so instead we're going to create a `index.html` file and serve that instead.
Let’s refactor our route handler to use `sendFile` instead.
```
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
```
# Integrating Socket.IO
Socket.IO is composed of two parts:
1. A server that integrates with (or mounts on) the Node.JS HTTP Server socket.io
2. A client library that loads on the browser side socket.io-client
During development, `socket.io` serves the client automatically for us, as we’ll see, so for now we only have to install one module:
```
npm install socket.io
```
That will install the module and add the dependency to package.json. Now let’s edit index.js to add it:
```
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
```
Notice that I initialize a new instance of socket.io by passing the server (the HTTP server) object. Then I listen on the connection event for incoming sockets and log it to the console.
Now in index.html add the following snippet before the </body> (end body tag):
```
<scriptsrc="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
```
That’s all it takes to load the socket.io-client, which exposes an io global (and the endpoint GET /socket.io/socket.io.js), and then connect.
If you would like to use the local version of the client-side JS file, you can find it at `node_modules/socket.io/client-dist/socket.io.js.`
**TIP
You can also use a CDN instead of the local files (e.g. <scriptsrc="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>).
Notice that I’m not specifying any URL when I call io(), since it defaults to trying to connect to the host that serves the page.**
**NOTE:
If you're behind a reverse proxy such as apache or nginx please take a look at the documentation for it.
If you're hosting your app in a folder that is not the root of your website (e.g., https://example.com/chatapp) then you also need to specify the path in both the server and the client.**
If you now restart the process (by hitting Control+C and running node index.js again) and then refresh the webpage you should see the console print “a user connected”.
Try opening several tabs, and you’ll see several messages.
Each socket also fires a special disconnect event:
```
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
```
Then if you refresh a tab several times you can see it in action.
# Emitting events
The main idea behind Socket.IO is that you can send and receive any events you want, with any data you want. Any objects that can be encoded as JSON will do, and binary data is supported too.
Let’s make it so that when the user types in a message, the server gets it as a chat message event. The script section in index.html should now look as follows:
```
<scriptsrc="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var form = document.getElementById('form');
var input = document.getElementById('input');
form.addEventListener('submit', function(e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
</script>
```
And in `index.js` we print out the chat message event:
```
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
});
});
```
The result should be like the following
# Homework
Here are some ideas to improve the application:
- Broadcast a message to connected users when someone connects or disconnects.
- Add support for nicknames.
- Don’t send the same message to the user that sent it. Instead, append the message directly as soon as they press enter.