Простой чат на node.js


Источники:
https://github.com/bezzad/Simple-broadcast-chat-nodejs-socket.io
http://falbar.ru/article/razrabatyvaem-prostoj-chat-s-pomoshhyu-nodejs-i-socketio
https://medium.com/freecodecamp-russia-русскоязычный/создание-простого-приложения-для-чата-с-помощью-node-js-и-socket-io-eb7498391611

Настройка среды разработки

Создаём папку node-chat

Открываем в vsc, в терминале выполняем команду

npm init -y

Устанавливаем пакеты

- socket.io

npm install socket.io

- express

npm install express

- nodemon

npm install nodemon

- ejs

npm install ejs

В файле package.json пишем код

  "scripts": {
    "start""node app",
    "dev""nodemon app"
  }

Это позволит запускать приложение командой

npm run dev

Создаём файл app.js - стартовая точка нашего приложения

пишем в app.js тестовый код

const http = require("http");
const server = http.createServer((requestresponse=> {
  response.end("Hello NodeJS!");
});
server.listen(3000, () => {
  console.log("Сервер начал прослушивание запросов на порту 3000");
});

По адресу http://localhost:3000/ открываем приложение.

Архитектура приложения
приложение включает в себя две части:  клиент и сервер


Серверная часть:

В файле app.js пишем код

const express = require('express');
const app = express();

app.set('view engine''ejs');
app.use(express.static('public'));
app.get('/', (reqres=> {
  res.send('My first app')
})
const server = app.listen('3000', () => {
  console.log('Server is running')
})

Работает
Подключаем socket.io к серверу

const io = require('socket.io')(server);
io.on('connection', (socket=> {
  console.log('New user connected')
})

Переходим к клиентской части



Клиентская часть

Заменим в коде

app.get('/', (reqres=> {
  res.send('My first app')
})

res.send('My first app') на res.render('index')

Добавляем разметку и стили
Создаём папку views с файлом index.ejs и папку public с файлом  style.css
приложение выглядит так (потом улучшим)


Подключаем socket.io к клиенту
В файле index.ejs подключаем скрипты

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script src="chat.js"></script>

В папке public создаём файл chat.js и пишем код

function startSession() {
  const socket = io.connect("http://localhost:3000");
}
startSession()

При перезагрузке страницы приложения в терминале появляется надпись "New user connected"

Отправка и получение данных

Имя пользователя

В файле app.js пишем код:

io.on('connection', (socket=> {
  socket.username = 'User';
  socket.on('change_username', (data=> {
    socket.username = data.username
  }) 
})

Каждый socket это новый пользователь. Мы указали имя пользователя по умолчанию - User, а затем добавили событие с именем 'change_username', и когда это событие произойдёт, имя пользователя изменится на то, которое указано в аргументе

Соответственно, клиент должен это событие сгенерировать
В файле chat.js пишем код

  const username = document.querySelector("#username");
  const send_username = document.querySelector("#send_username");

  send_username.addEventListener('click', () => {
    socket.emit("change_username", { username: username.value });
  })

Сообщения обрабатываем аналогично
В файле app.js пишем код:

  socket.on('new_message', (data=> {
    io.sockets.emit('add_message', {
      message : data.message, 
      username : socket.username
    });
  })

Обращение к io.sockets необходимо для того, чтобы сообщение отправилось всем подключённым пользователям, в том числе и к автору сообщения тоже

В файле chat.js пишем код

  send_message.addEventListener('click', () => {
    socket.emit('new_message', { message: message.value });
  })

  socket.on('add_message', (data=> {
    const message = document.createElement('div');
    message.classList.add('message');
    message.innerHTML = `<p><b>${data.username}:</b> ${data.message}</p>`;
    chatroom.append(message)
  })

При клике по кнопке send_message генерируется событие new_message со значением равным тому тексту, который ввели в поле сообщения

При наступлении события add_message у всех подключенных пользователей в чате отображается отправленное сообщение. Немного стилей помогут раскрасить парные и непарные сообщения в разные цвета



Улучшение чата

Добавим надпись "Пользователь печатает сообщение", когда сообщение набирается
для этого в файле chat.js пишем код

  message.addEventListener('keypress', () => {
    console.log('typing');
    socket.emit('typing');
  })

  socket.on('typing', (data=> {
    feedback.innerHTML = `<p><i>${data.username} is typing a message...</i></p>`;
    chatroom.append(message)
  })

При нажатии клавиш клавиатуры в окне для ввода сообщения генерируется событие typing.

Код в файле app.js отлавливает это событие, генерирует на его основе новое событие add_typing в котором передаёт имя пользователя

socket.on('typing', (data=> {
    io.sockets.emit('add_typing', {
      username : socket.username
    });
  })


При наступлении события add_typing в элементе feedback появляется текст "data.username is typing a message..."
За это отвечает код в файле chat.js

  socket.on('add_typing', (data=> {
    feedback.innerHTML = `<p><i>${data.username} is typing a message...</i></p>`;
  })

При отправке сообщения очищаем элемент feedback

  send_message.addEventListener('click', () => {
    feedback.innerHTML = '';
  })

Собственно, всё. приложение создано и работает используя серверную и клиентскую часть

Код приложения на гитхабе https://github.com/irinainina/node-chat