채팅 앱 만들기

gyomni·2022년 3월 16일
2

Week I Learned

목록 보기
11/20
post-thumbnail

📱접속 후 채팅해서 server가 메시지를 받은 뒤,메시지를 각 사용자들에게 보내는 방식의 채팅 앱 만들기~!📲

코드 구조 📂

src
├─ index.html
├─>css
├┴style.css
├─>js
├┴chat.js

app.js

web server 생성 💻

app.js

const express = require("express");
const http = require("http");
const app = express();
const path = require("path");
const server = http.createServer(app);
const socketIO = require("socket.io");

const io = socketIO(server);

app.use(express.static(path.join(__dirname,"src")));  // __dirname: 프로젝트 폴더 이름

const PORT = process.env.PORT || 5000;

io.on("connection",(socket)=>{
    console.log("연결이 이루어 졌습니다.");
});

// app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
server.listen(PORT, ()=>console.log(`server is running ${PORT}`));

src-index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>chat app</title>
</head>
<body>
    <h1>hello</h1>
  
    <!-- express사용하고 있기 때문에 절대경로 사용해서 다운 받은 라이브러리에 접근가능. -->
    <script src="/socket.io/socket.io.js"></script>
    <script src="js/chat.js"></script>
</body>
</html>

src-js-chat.js

"use strict"
const socket = io();
// 정상적으로 불러와졌는지 확인
console.log(socket);

코드 파헤치기

package.json 생성

npm init -y 
  • app의 중요한 정보를 담고 있음.
  • 설정이나 라이브러리들의 기록 같은 것을 담아 놓는 중요한 파일.

라이브러리 설치

npm install express socket.io moment
  • 시간을 알려주기 위해 moment도 같이 설치.
  • node_modules 생성
  • git 등에 공유할 때 ignore을 시켜서 node_modules은 보내지 않고 package.json 파일만 올리면 어떤 라이브러리를 설치 했는지 공유할 수 있다.

express 라이브러리 가져오기

const express = require("express");
  • 필요한 express 라이브러리를 가져오고, 그 라이브러리를 변수 express에 담음.
  • require를 쓰게 되면 자동적으로 node_modules를 보기 때문에,
    필요한 express만 적어줘도 경로 없이 가져올 수 있게 됨.

변수에 담기

const app = express();

express를 실행한 내용을 app에 담음.


path 불러오기

const path = require("path")
  • 서버 주소를 명확하게 쓰기 위해서 path라는 node.js의 기본 모듈 불러오기

서버가 보여줄 파일 지정

app.use(express.static(path.join(__dirname,"src")));
  • 서버가 실행이 되면 서버가 보여줄 파일들을 지정.
  • path사용으로 url을 쉽게 만들수 있게 됨.

PORT 생성

const PORT = process.env.PORT || 5000;
  • 서버를 실행하기 위해서는 PORT가 필요함.
  • process환경에 PORT가 지정이 되어 있다면, 그 PORT를 사용하고, 아니라면 5000번 PORT 사용.

서버 실행

app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
  • app.listen(포트,명령);

nodemon 라이브러리 설치

npm install -g nodemon
  • 기존에는 js파일에 변경이 있을 때 마다 새롭게 실행해줘야하는 불편함이 있음.
  • 번거러우므로 nodemon이라는 라이브러리 설치
  • js 파일에 변경이 있을 때 마다 자동으로 실행시켜줌.

http 불러오기

const http = require("http");
  • socket.io를 받을 수 있도록 서버 쪽에서 세팅을 해줘야함.
  • 현재 web socket이라서 http를 통해서 이루어져야만 한다.
  • http node.js의 기본 모듈인 http를 불러서 사용.

변수 server 생성

const server = http.createServer(app);
  • http 불러 온 후에 server라는 변수 생성
  • express로 구현한 app을 담아서 express가 결국 http를 통해서 실행될 수 있도록 구현.
  • server.listen(PORT, ()=>console.log(`server is running ${PORT}`));
    ( app -> server 변경 )

socket.io 불러오기

const socketIO = require("socket.io");
  • socket.io 라이브러리를 불러와서 변수에 담아줌.

server 담아주기

const io = socketIO(server);
  • 생성한 변수 socketIOserver담아주기.
  • 생성한 io를 통해서 보낸 메시지나 정보를 받아 와서 사용, 제어를 한다.

정보를 socket에 담기

io.on("connection",(socket)=>{
    console.log("연결이 이루어 졌습니다.");
});
  • connection이 이루어지면 연결이 이루어졌을 때 연결에 대한 정보를 socket에 담음.
  • socket에 담겨있는 정보에 접근해서 내용을 다루게 된다.
  • console.log("연결이 이루어 졌습니다.");로 연결 확인을 한다.

연결 확인

  • 연결이 완료된것을 확인할 수 있다!

혹시나 라이브러리 불러오는 것이 안된다면?
cdnjs_socket.io에 들어가서 코드 카피후에 html파일에 붙여넣으면 된다 😮

메시지 주고 받기 🙌

app.js

const express = require("express");
const http = require("http");
const app = express();
const path = require("path");
const server = http.createServer(app);
const socketIO = require("socket.io");

const io = socketIO(server);

app.use(express.static(path.join(__dirname,"src")));  // __dirname: 프로젝트 폴더 이름

const PORT = process.env.PORT || 5000;

// 서버에서 받아주기
io.on("connection",(socket)=>{
    socket.on("chatting",(data)=>{
        console.log(data)
        io.emit("chatting", `오오옹 안농 ${data}`)
    })
});

// app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
server.listen(PORT, ()=>console.log(`server is running ${PORT}`));

src-js-chat.js

"use strict"
const socket = io();

socket.emit("chatting", "hi gyomni"); // socket 객체를 이용해서 메시지 보내기

// 받아 줄 때는 socket.on 사용.
socket.on("chatting", (data)=>{
    console.log(data)
})

// 정상적으로 불러와졌는지 확인
console.log(socket);

코드 파헤치기

chat.js

socket 객체를 이용해서 메시지 보내기

socket.emit("chatting", "hi gyomni")
  • socket.emit("채팅 아이디", "보낼 내용")

app.js

서버에서 받아주기

io.on("connection",(socket)=>{
    socket.on("chatting",(data)=>{
        console.log(data)
    })
});
io.on("connection",(socket)=>{
    socket.on("채팅 아이디",(클라이언트에서 보낸 내용을 파라미터로 받음)=>{      
    })
}); 
  • 서버를 준비하고 프론트에서 새로고침하면 hi gyomni가 서버에 출력된 것을 확인할 수 있다.

서버에서 출력되고 서버에서 메시지 되돌려주기

app.js

io.on("connection",(socket)=>{
    socket.on("chatting",(data)=>{
        console.log(data)
        io.emit("chatting", `오오옹 안농 ${data}`)
    })
});
  • string 형태로 전체메시지 보내기
  • 프론트에서도 서버가 보낸 내용을 받을 수 있음.
  • 여기까지만 하면 프론트에서는 변화가 없으므로 아래처럼 작성하면 프론트에서 확인할 수 있다.

chat.js

socket.on("chatting", (data)=>{
    console.log(data);
})
  • 받아 줄 때는 socket.on 사용.
  • data에는 서버에서 보낸 내용이 담기게 된다. (이름 무관)
  • 첫번째 인자 : 채팅아이디
  • 두번째 인자 : 실행할 내용

-> 새로고침을 하면 emit을 통해서 보내게 되고( chat.js )
서버에서 다시 emit을 통해서 프론트엔드 쪽으로 보내고( app.js )
프론트는 메시지를 확인 ( chat.js )할 수 있게 된다.


레이아웃 잡기 🧩

기본적인 버튼 만들어서 전송하고, 서버에서 받은 내용을 핸들링 하기

app.js

const express = require("express");
const http = require("http");
const app = express();
const path = require("path");
const server = http.createServer(app);
const socketIO = require("socket.io");

const io = socketIO(server);


app.use(express.static(path.join(__dirname,"src")));  // __dirname: 프로젝트 폴더 이름

const PORT = process.env.PORT || 5000;

// 서버에서 받아주기
io.on("connection",(socket)=>{
    socket.on("chatting",(data)=>{
        console.log(data)
        io.emit("chatting", `오오옹 안농 ${data}`)
    })
});

// app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
server.listen(PORT, ()=>console.log(`server is running ${PORT}`));

src-index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>chat app</title>
</head>
<body>
    <div class="wrapper">
        <div class="user-container">
            대화명 : <input type="text" id="nickname">
        </div>
        <div class="display-container">
            <ul class="chatting-list">
                <!-- 받은 내용을 li로 넣기 -->
            </ul>
        </div>
        <div class="input-container">
            <input type="text" class="chatting-input">
            <button class="send-button">전송</button>
        </div>
    </div>
    <!-- express사용하고 있기 때문에 절대경로 사용해서 다운 받은 라이브러리에 접근가능. -->
    <script src="/socket.io/socket.io.js"></script>
    <script src="js/chat.js"></script>
</body>
</html>

src-js-chat.js

"use strict"
const socket = io();

const nickname = document.querySelector("#nickname");
const chatList =document.querySelector(".chatting-list");
const chatInput = document.querySelector(".chatting-input")
const sendButton = document.querySelector(".send-button")

sendButton.addEventListener("click",()=>{
    
        const param = {
            name: nickname.value,   // input이라서 value 접근 가능.
            msg : chatInput.value,
        };
    
    socket.emit("chatting",param);
} )

// 받아 줄 때는 socket.on 사용.
socket.on("chatting", (data)=>{
    const li = document.createElement("li");
    li.innerText = `${data.name}님의 메시지 : ${data.msg}`;
    chatList.appendChild(li);
})

// 정상적으로 불러와졌는지 확인
console.log(socket);

코드 파헤치기

이벤트 걸기

chat.js

sendButton.addEventListener("click",()=>{

        const param = {
            name: nickname.value,   // input이라서 value 접근 가능.
            msg : chatInput.value,
        };    
    socket.emit("chatting",param);
} )
  • 닉네임과 내용을 서버로 보내기.
  • 데이터를 오브젝트로 보낸다.
  • param를 보내주면 서버에서 받을 수 있다.

서버에서 받는 부분 확인

app.js

io.on("connection",(socket)=>{
    socket.on("chatting",(data)=>{
        console.log(data)
        io.emit("chatting", `오오옹 안농 ${data}`)
    })
});
  • 서버에 오브젝트 형태로 전송이 된 것을 확인할 수 있음.
io.on("connection",(socket)=>{
    socket.on("chatting",(data)=>{
        io.emit("chatting", data)
    })
});
  • 받은 오브젝트를 그대로 다시 보내주기 (나머지 부분은 클라이언트에서 처리)
  • 데이터에는 오브젝트가 담겨있기 때문에 전송해주면 나온 내용을 받을 수 있다.
    -> {name: 'gyomni', msg: 'hihi'}

socket을 받았을 때 chatListli를 만들고 넣기

chat.js

socket.on("chatting", (data)=>{
    const li = document.createElement("li");
    li.innerText = `${data.name}님의 메시지 : ${data.msg}`;
    chatList.appendChild(li);
})
  • http://localhost:5000/으로 들어가서 새로운 페이지에 닉네임과 대화를 작성하니 web socket으로 채팅이 된다.

대략적인 style을 css로 작성

  • 하드 코딩으로 내용을 대략적으로 채워넣고 스타일을 잡았다.
  • chat.js에서 li생성하는 부분을 수정해야 한다!

수정하기 🪐

app.js

const express = require("express");
const http = require("http");
const app = express();
const path = require("path");
const server = http.createServer(app);
const socketIO = require("socket.io");
const moment = require("moment");
const io = socketIO(server);


app.use(express.static(path.join(__dirname,"src")));  // __dirname: 프로젝트 폴더 이름

const PORT = process.env.PORT || 5000;

// 서버에서 받아주기
io.on("connection",(socket)=>{
    socket.on("chatting",(data)=>{
        const {name, msg} = data;
        io.emit("chatting",{
            name,
            msg,
            time: moment(new Date()).format("h:mm A")
        })
    })
});

// app.listen(PORT, ()=>console.log(`server is running ${PORT}`));
server.listen(PORT, ()=>console.log(`server is running ${PORT}`));

src-index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>chat app</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="wrapper">
        <div class="user-container">
            <label for="nickname">대화명</label>
            <input type="text" id="nickname">
        </div>
        <div class="display-container">
            <ul class="chatting-list">                
            </ul>
        </div>
        <div class="input-container">
            <span>
                <input type="text" class="chatting-input">
                <button class="send-button">전송</button>
            </span>
            
        </div>
    </div>
    <!-- express사용하고 있기 때문에 절대경로 사용해서 다운 받은 라이브러리에 접근가능. -->
    <script src="/socket.io/socket.io.js"></script>
    <script src="js/chat.js"></script>
</body>
</html>

src-js-chat.js

"use strict"
const socket = io();

const nickname = document.querySelector("#nickname");
const chatList =document.querySelector(".chatting-list");
const chatInput = document.querySelector(".chatting-input");
const sendButton = document.querySelector(".send-button");
const displayContainer = document.querySelector(".display-container");

chatInput.addEventListener("keypress", (e)=>{
    if(e.keycode ===13){
    send();

    }
})

function send(){
    const param = {
        name: nickname.value,   // input이라서 value 접근 가능.
        msg : chatInput.value,
    };

socket.emit("chatting",param);
}

sendButton.addEventListener("click",send)

// 받아 줄 때는 socket.on 사용.
socket.on("chatting", (data)=>{
    const {name, msg, time} = data;
    const item = new LiModel(name, msg, time);
    item.makeLi()

    // 스크롤 밑으로
    displayContainer.scrollTo(0, displayContainer.scrollHeight)
})

function LiModel(name, msg, time){
    this.name = name;
    this.msg = msg;
    this.time = time;

    this.makeLi = ()=>{

        const li = document.createElement("li");
        li.classList.add(nickname.value === this.name ? "sent" : "received")
        const dom = ` <span class="profile">
        <span class="user">${this.name}</span>
        <img  class="image"src="http://placeimg.com/50/50/any" alt="any">
    </span>
    <span class="message">${this.msg}</span>
    <span class="time">${this.time}</span>`;
    li.innerHTML = dom;
    chatList.appendChild(li);
    }
}

// 정상적으로 불러와졌는지 확인
console.log(socket);

코드 파헤치기

chat.js

function LiModel(name, msg, time){
  // 초기화 할당
  // 아래 만든 makeLi라는 메서드에서 값들에 접근해서 사용하기 위해.
    this.name = name;
    this.msg = msg;
    this.time = time;

    this.makeLi = ()=>{
        const li = document.createElement("li");

  		// 내가 보낸 메시지는 오른쪽으로 오도록
        li.classList.add(nickname.value === this.name ? "sent" : "received")
        const dom = ` <span class="profile">
        <span class="user">${this.name}</span>
        <img  class="image"src="http://placeimg.com/50/50/any" alt="any">
    </span>
    <span class="message">${this.msg}</span>
    <span class="time">${this.time}</span>`;
    li.innerHTML = dom;
    chatList.appendChild(li);
    }
}
  • index.htmlli 부분을 가져와서 넣어주기.
socket.on("chatting", (data)=>{
    const {name, msg, time} = data;

  // LiModel 인스턴스화
    const item = new LiModel(name, msg, time);
    item.makeLi()

    // 스크롤 밑으로
    displayContainer.scrollTo(0, displayContainer.scrollHeight)
})
  • 서버에서 데이터를 받았을 때 마다 LiModel을 찍어냄.

발송 시간 처리

app.js

const moment = require("moment");
.
.
.
io.on("connection",(socket)=>{
    socket.on("chatting",(data)=>{
        const {name, msg} = data;
        io.emit("chatting",{
            name,
            msg,
            time: moment(new Date()).format("h:mm A") // 현재시간 가져오기
        })
    })
});
  • moment 불러오기
  • emit하는 부분에 시간 넘겨주기
  • 여기서 datachat.jsparam 데이터
  • format("YYYY-MM-DD HH:mm:ss") -> 년 - 월 - 일 - 시 - 분 - 초 순서대로!

스크롤 처리

chat.js

const displayContainer = document.querySelector(".display-container");
.
.
.
socket.on("chatting", (data)=>{
    const {name, msg, time} = data;
    const item = new LiModel(name, msg, time);  
    item.makeLi()

    // 스크롤 밑으로
    displayContainer.scrollTo(0, displayContainer.scrollHeight)
})
  • displayContainer의 스크롤 위치를 읽어서 위치를 스크롤의 높이로 이동.

enter로 전송하기

chatInput.addEventListener("keypress", (e)=>{
    if(e.keycode ===13){
    send();
    }
})

function send(){
    const param = {
        name: nickname.value,   // input이라서 value 접근 가능.
        msg : chatInput.value,
    };
socket.emit("chatting",param);
}
  • keypress이벤트가 발생할 때, 키코드 값이 13(= enter) 이면 실행.

ngrok

ngrok설치

npm install -g ngrok
  • 외부 사람들이 접속할 수 있또록 만들어주는 라이브러리.
  • 간단하게 테스트 한 것을 공유할 때 유용!

ngrok실행

ngrok http 5000
  • 5000->현재보여주고 싶은 PORT
  • 실행 전에 node.js 실행해주기
  • Forwarding된 주소 = 외부에서 접속할 수 있는 주소
    http://f2d1-125-137-175-211.ngrok.io

TEST


오....뭔가 잘못된듯......?...
일단 http://localhost:5000/로 실행해보면 !

잘 실행된다 👏👏 위 오류는 한번 찾아와야겠다@!!

학습 : 데브리 _ 바닐라 자바 스크립트 채팅앱

profile
Front-end developer 👩‍💻✍

0개의 댓글