์‚ฌ์šฉ์ž ๋„๊ตฌ

์‚ฌ์ดํŠธ ๋„๊ตฌ


wiki:it:dream_of_enc:metaverse:nodejs

๋ฌธ์„œ์˜ ์ด์ „ ํŒ์ž…๋‹ˆ๋‹ค!


๐ŸŸข Node.js ๋ฐฑ์—”๋“œ ์„ค์ •

Phaser Baduk Metaverse ํ”„๋กœ์ ํŠธ์˜ Node.js ๋ฐฑ์—”๋“œ ์„ค์ •๊ณผ ๊ตฌ์„ฑ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.


1. Node.js๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?

Node.js๋Š” JavaScript๋ฅผ ์„œ๋ฒ„์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค. ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ๋งŒ ์‹คํ–‰๋˜๋˜ JavaScript๋ฅผ ์„œ๋ฒ„์—์„œ๋„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

์ฃผ์š” ํŠน์ง•:

  • JavaScript๋กœ ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๊ฐ•์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • npm์„ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋น ๋ฅธ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

2. ํ”„๋กœ์ ํŠธ ๊ฐœ์š”

์ด ํ”„๋กœ์ ํŠธ๋Š” Node.js๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋ฉฐ, ์›น ํŽ˜์ด์ง€๋ฅผ ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋งํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์™€์˜ ์‹ค์‹œ๊ฐ„ ํ†ต์‹  ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ๊ธฐ์ˆ  ์Šคํƒ:

  • Express.js - ์›น ํ”„๋ ˆ์ž„์›Œํฌ
  • Socket.IO - ์‹ค์‹œ๊ฐ„ ํ†ต์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • PM2 - ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌ ๋„๊ตฌ

3. ์„œ๋ฒ„ ๊ตฌ์กฐ ๋ฐ ์ฃผ์š” ํŒŒ์ผ

Phaser Baduk Metaverse ํ”„๋กœ์ ํŠธ์˜ ํ•ต์‹ฌ ์„œ๋ฒ„ ํŒŒ์ผ์ธ server.js์˜ ๊ตฌ์กฐ์™€ ๊ฐ ๋ถ€๋ถ„์˜ ์—ญํ• ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

1) ์ดˆ๊ธฐ ์„ค์ • ๋ฐ ๋ชจ๋“ˆ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

์„œ๋ฒ„ ๊ตฌ๋™์— ํ•„์š”ํ•œ ๋ชจ๋“ˆ๋“ค์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ , ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

const express = require('express'); // ์›น ์„œ๋ฒ„ ํ”„๋ ˆ์ž„์›Œํฌ
const http = require('http');     // HTTP ์„œ๋ฒ„ ๋ชจ๋“ˆ
const socketIo = require('socket.io'); // ์‹ค์‹œ๊ฐ„ ์›น ์†Œ์ผ“ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
const path = require('path');     // ํŒŒ์ผ ๊ฒฝ๋กœ ์ฒ˜๋ฆฌ ์œ ํ‹ธ๋ฆฌํ‹ฐ

๊ฐ ๋ชจ๋“ˆ์˜ ์—ญํ• :

  • express - ์›น ์„œ๋ฒ„๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ
  • http - HTTP ์„œ๋ฒ„๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋ณธ ๋ชจ๋“ˆ
  • socket.io - ์‹ค์‹œ๊ฐ„ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • path - ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ

2) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ

const app = express(); // Express ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ
const server = http.createServer(app); // HTTP ์„œ๋ฒ„ ์ƒ์„ฑ (Express ์•ฑ์„ ๊ธฐ๋ฐ˜์œผ๋กœ)
const io = socketIo(server); // Socket.IO ์„œ๋ฒ„ ์ƒ์„ฑ (HTTP ์„œ๋ฒ„์— ์—ฐ๊ฒฐ)

์„ค๋ช…:

  • app - Express ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐ์ฒด
  • server - HTTP ์„œ๋ฒ„ ๊ฐ์ฒด (Express ์•ฑ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ)
  • io - Socket.IO ์„œ๋ฒ„ ๊ฐ์ฒด (HTTP ์„œ๋ฒ„์— ์—ฐ๊ฒฐ)

3) ์ •์  ํŒŒ์ผ ์„œ๋น™ ๋ฐ ๋ผ์šฐํŒ…

ํด๋ผ์ด์–ธํŠธ(ํ”„๋ก ํŠธ์—”๋“œ)์— ์ œ๊ณต๋  ์ •์  ํŒŒ์ผ(HTML, CSS, JS, ์ด๋ฏธ์ง€ ๋“ฑ)์„ ์„ค์ •ํ•˜๊ณ , ๊ธฐ๋ณธ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ๋ผ์šฐํŠธ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

// 'public' ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ๋Š” ์ •์  ํŒŒ์ผ๋“ค์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ œ๊ณต
app.use(express.static(path.join(__dirname, 'public')));
 
// ๋ฃจํŠธ ๊ฒฝ๋กœ('/')๋กœ ์ ‘๊ทผ ์‹œ 'public' ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์˜ 'index.html' ํŒŒ์ผ ์ „์†ก
app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

์„ค๋ช…:

  • express.static() - ์ •์  ํŒŒ์ผ์„ ์›น์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • path.join(dirname, 'public') - ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์˜ public ํด๋” ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค. * app.get('/') - ๋ฃจํŠธ ๊ฒฝ๋กœ๋กœ ์ ‘๊ทผํ–ˆ์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. === 4) Socket.IO ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ === ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์„ ๋‹ด๋‹นํ•˜๋Š” Socket.IO ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. <file javascript> Socket.IO ์—ฐ๊ฒฐ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ io.on('connection', (socket) โ‡’ { ์ƒˆ๋กœ์šด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋  ๋•Œ๋งˆ๋‹ค ์‹คํ–‰ console.log('์ƒˆ๋กœ์šด ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ:', socket.id); 'join-game' ์ด๋ฒคํŠธ ์ˆ˜์‹  ์‹œ ํŠน์ • ๊ฒŒ์ž„๋ฐฉ์— ํด๋ผ์ด์–ธํŠธ ์กฐ์ธ socket.on('join-game', (gameId) โ‡’ { socket.join(gameId); ํ•ด๋‹น gameId๋ฅผ ๊ฐ€์ง„ ๋ฐฉ์— ์†Œ์ผ“์„ ์ถ”๊ฐ€ console.log(`ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๊ฒŒ์ž„ ${gameId}์— ์ฐธ๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.`); }); ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ํ•ด์ œ ์‹œ ์‹คํ–‰ socket.on('disconnect', () โ‡’ { console.log('ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ํ•ด์ œ:', socket.id); }); }); </file> ์„ค๋ช…: * io.on('connection') - ์ƒˆ๋กœ์šด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋  ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. * socket.on('join-game') - ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฒŒ์ž„ ์ฐธ๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. * socket.join(gameId) - ํŠน์ • ๊ฒŒ์ž„๋ฐฉ์— ์†Œ์ผ“์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. * socket.on('disconnect') - ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ์ด ๋Š์–ด์งˆ ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. === 5) ์„œ๋ฒ„ ํฌํŠธ ์„ค์ • ๋ฐ ์‹คํ–‰ === ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ ํฌํŠธ ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๊ธฐ๋ณธ๊ฐ’(3000)์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ ์ง€์ •๋œ ํฌํŠธ์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. <file javascript> ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ PORT๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๊ธฐ๋ณธ๊ฐ’ 3000 ์‚ฌ์šฉ const PORT = process.env.PORT || 3000; ์„œ๋ฒ„๋ฅผ ์ง€์ •๋œ ํฌํŠธ์—์„œ ์‹คํ–‰ํ•˜๊ณ , ์„ฑ๊ณต ์‹œ ์ฝ˜์†”์— ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ server.listen(PORT, () โ‡’ { console.log(`์„œ๋ฒ„๊ฐ€ ํฌํŠธ ${PORT}์—์„œ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค.`); console.log(`http://localhost:${PORT}์—์„œ ์ ‘์†ํ•˜์„ธ์š”.`); }); </file> ์„ค๋ช…: * process.env.PORT - ํ™˜๊ฒฝ ๋ณ€์ˆ˜์—์„œ ํฌํŠธ ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. * || 3000 - ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ 3000์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. * server.listen() - ์„œ๋ฒ„๋ฅผ ์ง€์ •๋œ ํฌํŠธ์—์„œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. * ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์„œ๋ฒ„ ์‹œ์ž‘ ์„ฑ๊ณต ์‹œ ์‹คํ–‰๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. โ€”- ==== 4. ์˜์กด์„ฑ ๊ด€๋ฆฌ (package.json) ==== ํ”„๋กœ์ ํŠธ์— ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” package.json ํŒŒ์ผ์˜ ์ฃผ์š” ๋‚ด์šฉ์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. === 1) ํ”„๋กœ์ ํŠธ ์ •๋ณด === ^ ํ‚ค ^ ์„ค๋ช… ^ | name | ํ”„๋กœ์ ํŠธ ์ด๋ฆ„ | | version | ํ”„๋กœ์ ํŠธ ๋ฒ„์ „ | | description | ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ ๊ฐ„๋žตํ•œ ์„ค๋ช… | | main | ํ”„๋กœ์ ํŠธ์˜ ์ง„์ž…์  ํŒŒ์ผ (์—ฌ๊ธฐ์„œ๋Š” server.js) | === 2) ์Šคํฌ๋ฆฝํŠธ === ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ช…๋ น์–ด๋ฅผ ๋‹จ์ถ•ํ•˜์—ฌ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ^ ์Šคํฌ๋ฆฝํŠธ ^ ์„ค๋ช… ^ ๋ช…๋ น์–ด ^ | start | ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. | node server.js | | dev | ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ nodemon์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‹œ ์ž๋™ ์žฌ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. | nodemon server.js | | pm2 | PM2๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. (ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌ์šฉ) | pm2 start server.js | === 3) ์˜์กด์„ฑ ๋ชฉ๋ก === ^ ์˜์กด์„ฑ ^ ๋ฒ„์ „ ^ ์„ค๋ช… ^ | express | 4.18.2 | Node.js ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋ ˆ์ž„์›Œํฌ | | socket.io | 4.7.2 | ์‹ค์‹œ๊ฐ„ ์–‘๋ฐฉํ–ฅ ์›น ์†Œ์ผ“ ํ†ต์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ | | cors | 2.8.5 | ๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ  (CORS) ๋ฏธ๋“ค์›จ์–ด | | helmet | 7.0.0 | ๋ณด์•ˆ ํ—ค๋” ์„ค์ • ๋ฏธ๋“ค์›จ์–ด | | compression | 1.7.4 | ์‘๋‹ต ์••์ถ• ๋ฏธ๋“ค์›จ์–ด | | express-rate-limit | 6.7.0 | ์š”์ฒญ ์ œํ•œ ๋ฏธ๋“ค์›จ์–ด | === 4) ๊ฐœ๋ฐœ ์˜์กด์„ฑ ๋ชฉ๋ก === ^ ์˜์กด์„ฑ ^ ๋ฒ„์ „ ^ ์„ค๋ช… ^ | nodemon | 2.0.22 | ๊ฐœ๋ฐœ ์‹œ ์ฝ”๋“œ ๋ณ€๊ฒฝ ๊ฐ์ง€ํ•˜์—ฌ ์„œ๋ฒ„ ์ž๋™ ์žฌ์‹œ์ž‘ | | jest | 29.5.0 | JavaScript ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ | | supertest | 6.3.3 | HTTP ํ…Œ์ŠคํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ | โ€”- ==== 5. ํ™˜๊ฒฝ ์„ค์ • ==== === 1) ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ • === ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— .env ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์—ฌ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: <file bash> # ์„œ๋ฒ„ ํฌํŠธ ์„ค์ • PORT=3000 # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์ •๋ณด MONGODB_URI=mongodb:localhost:27017/baduk_metaverse # JWT ์‹œํฌ๋ฆฟ ํ‚ค JWT_SECRET=your-secret-key-here # ํ™˜๊ฒฝ ์„ค์ • NODE_ENV=development </file> ์ฃผ์š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜: * PORT - ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋  ํฌํŠธ ๋ฒˆํ˜ธ * MONGODB_URI - MongoDB ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๋ฌธ์ž์—ด * JWT_SECRET - JWT ํ† ํฐ ์•”ํ˜ธํ™”์— ์‚ฌ์šฉํ•  ์‹œํฌ๋ฆฟ ํ‚ค * NODE_ENV - ํ˜„์žฌ ํ™˜๊ฒฝ (development/production) === 2) ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์‚ฌ์šฉ๋ฒ• === <file javascript> dotenv ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ .env ํŒŒ์ผ ๋กœ๋“œ require('dotenv').config(); ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์‚ฌ์šฉ const PORT = process.env.PORT || 3000; const MONGODB_URI = process.env.MONGODB_URI; const JWT_SECRET = process.env.JWT_SECRET; </file> ์„ค๋ช…: * require('dotenv').config() - .env ํŒŒ์ผ์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. * process.env.๋ณ€์ˆ˜๋ช… - ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. * || ๊ธฐ๋ณธ๊ฐ’ - ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ์—†์„ ๋•Œ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. โ€”- ==== 6. ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ==== ๊ถŒ์žฅํ•˜๋Š” ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ: <file> baduk-metaverse/ โ”œโ”€โ”€ server.js # ๋ฉ”์ธ ์„œ๋ฒ„ ํŒŒ์ผ โ”œโ”€โ”€ package.json # ํ”„๋กœ์ ํŠธ ์„ค์ • ํŒŒ์ผ โ”œโ”€โ”€ .env # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ํŒŒ์ผ โ”œโ”€โ”€ .gitignore # Git ๋ฌด์‹œ ํŒŒ์ผ ๋ชฉ๋ก โ”œโ”€โ”€ public/ # ์ •์  ํŒŒ์ผ ํด๋” โ”‚ โ”œโ”€โ”€ index.html # ๋ฉ”์ธ HTML ํŒŒ์ผ โ”‚ โ”œโ”€โ”€ css/ # CSS ํŒŒ์ผ๋“ค โ”‚ โ”œโ”€โ”€ js/ # ํด๋ผ์ด์–ธํŠธ JavaScript ํŒŒ์ผ๋“ค โ”‚ โ””โ”€โ”€ images/ # ์ด๋ฏธ์ง€ ํŒŒ์ผ๋“ค โ”œโ”€โ”€ routes/ # ๋ผ์šฐํŠธ ํŒŒ์ผ๋“ค โ”‚ โ”œโ”€โ”€ games.js # ๊ฒŒ์ž„ ๊ด€๋ จ ๋ผ์šฐํŠธ โ”‚ โ”œโ”€โ”€ users.js # ์‚ฌ์šฉ์ž ๊ด€๋ จ ๋ผ์šฐํŠธ โ”‚ โ””โ”€โ”€ statistics.js # ํ†ต๊ณ„ ๊ด€๋ จ ๋ผ์šฐํŠธ โ”œโ”€โ”€ controllers/ # ์ปจํŠธ๋กค๋Ÿฌ ํŒŒ์ผ๋“ค โ”‚ โ”œโ”€โ”€ BadukGameController.js โ”‚ โ”œโ”€โ”€ UserController.js โ”‚ โ””โ”€โ”€ StatisticsController.js โ”œโ”€โ”€ models/ # ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ํŒŒ์ผ๋“ค โ”‚ โ”œโ”€โ”€ BadukGame.js โ”‚ โ”œโ”€โ”€ User.js โ”‚ โ””โ”€โ”€ BadukGameState.js โ”œโ”€โ”€ middleware/ # ๋ฏธ๋“ค์›จ์–ด ํŒŒ์ผ๋“ค โ”‚ โ”œโ”€โ”€ auth.js # ์ธ์ฆ ๋ฏธ๋“ค์›จ์–ด โ”‚ โ””โ”€โ”€ errorHandler.js # ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฏธ๋“ค์›จ์–ด โ”œโ”€โ”€ utils/ # ์œ ํ‹ธ๋ฆฌํ‹ฐ ํŒŒ์ผ๋“ค โ”‚ โ”œโ”€โ”€ BadukMoveValidator.js โ”‚ โ””โ”€โ”€ helpers.js โ””โ”€โ”€ tests/ # ํ…Œ์ŠคํŠธ ํŒŒ์ผ๋“ค โ”œโ”€โ”€ server.test.js โ””โ”€โ”€ game.test.js </file> ๊ฐ ํด๋”์˜ ์—ญํ• : * public/ - ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ œ๊ณตํ•  ํŒŒ์ผ๋“ค * routes/ - URL ๊ฒฝ๋กœ๋ณ„ ์ฒ˜๋ฆฌ ๋กœ์ง * controllers/ - ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ * models/ - ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜ * middleware/ - ์š”์ฒญ ์ฒ˜๋ฆฌ ์ค‘๊ฐ„ ๋‹จ๊ณ„ * utils/ - ๊ณตํ†ต ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋“ค * tests/ - ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋“ค โ€”- ==== 7. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ • ==== === 1) Node.js ์„ค์น˜ === Windows์—์„œ Node.js ์„ค์น˜: * Node.js ๊ณต์‹ ์›น์‚ฌ์ดํŠธ (https://nodejs.org) ๋ฐฉ๋ฌธ * LTS ๋ฒ„์ „ ๋‹ค์šด๋กœ๋“œ ๋ฐ ์„ค์น˜ * ์„ค์น˜ ์™„๋ฃŒ ํ›„ ํ„ฐ๋ฏธ๋„์—์„œ ํ™•์ธ: <file bash> node โ€“version npm โ€“version </file> === 2) ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐํ™” === <file bash> # ์ƒˆ ํด๋” ์ƒ์„ฑ ๋ฐ ์ด๋™ mkdir baduk-metaverse cd baduk-metaverse # npm ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐํ™” npm init -y # ํ•„์š”ํ•œ ํŒจํ‚ค์ง€ ์„ค์น˜ npm install express socket.io cors helmet compression express-rate-limit # ๊ฐœ๋ฐœ์šฉ ํŒจํ‚ค์ง€ ์„ค์น˜ npm install โ€“save-dev nodemon </file> === 3) ๊ธฐ๋ณธ ์„œ๋ฒ„ ํŒŒ์ผ ์ƒ์„ฑ === server.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ๊ธฐ๋ณธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค: <file javascript> const express = require('express'); const http = require('http'); const socketIo = require('socket.io'); const path = require('path'); const app = express(); const server = http.createServer(app); const io = socketIo(server); ์ •์  ํŒŒ์ผ ์„œ๋น™ app.use(express.static(path.join(dirname, 'public'))); ๊ธฐ๋ณธ ๋ผ์šฐํŠธ app.get('/', (req, res) โ‡’ { res.sendFile(path.join(dirname, 'public', 'index.html')); }); Socket.IO ์—ฐ๊ฒฐ ์ฒ˜๋ฆฌ io.on('connection', (socket) โ‡’ { console.log('์ƒˆ๋กœ์šด ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ:', socket.id); socket.on('disconnect', () โ‡’ { console.log('ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ ํ•ด์ œ:', socket.id); }); }); ์„œ๋ฒ„ ์‹œ์ž‘ const PORT = process.env.PORT || 3000; server.listen(PORT, () โ‡’ { console.log(`์„œ๋ฒ„๊ฐ€ ํฌํŠธ ${PORT}์—์„œ ์‹คํ–‰ ์ค‘์ž…๋‹ˆ๋‹ค.`); }); </file> === 4) package.json ์Šคํฌ๋ฆฝํŠธ ์„ค์ • === <file json> { โ€œnameโ€: โ€œbaduk-metaverseโ€, โ€œversionโ€: โ€œ1.0.0โ€, โ€œdescriptionโ€: โ€œPhaser Baduk Metaverse ํ”„๋กœ์ ํŠธโ€, โ€œmainโ€: โ€œserver.jsโ€, โ€œscriptsโ€: { โ€œstartโ€: โ€œnode server.jsโ€, โ€œdevโ€: โ€œnodemon server.jsโ€, โ€œtestโ€: โ€œjestโ€ }, โ€œdependenciesโ€: { โ€œexpressโ€: โ€œ^4.18.2โ€, โ€œsocket.ioโ€: โ€œ^4.7.2โ€, โ€œcorsโ€: โ€œ^2.8.5โ€, โ€œhelmetโ€: โ€œ^7.0.0โ€, โ€œcompressionโ€: โ€œ^1.7.4โ€, โ€œexpress-rate-limitโ€: โ€œ^6.7.0โ€ }, โ€œdevDependenciesโ€: { โ€œnodemonโ€: โ€œ^2.0.22โ€, โ€œjestโ€: โ€œ^29.5.0โ€ } } </file> โ€”- ==== 8. ์„œ๋ฒ„ ์‹คํ–‰ ๋ฐ ํ…Œ์ŠคํŠธ ==== === 1) ๊ฐœ๋ฐœ ๋ชจ๋“œ๋กœ ์„œ๋ฒ„ ์‹คํ–‰ === <file bash> npm run dev </file> ์„ค๋ช…: * nodemon์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. * ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‹œ ์ž๋™์œผ๋กœ ์„œ๋ฒ„๊ฐ€ ์žฌ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. * ๊ฐœ๋ฐœ ์ค‘์— ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. === 2) ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ๋กœ ์„œ๋ฒ„ ์‹คํ–‰ === <file bash> npm start </file> ์„ค๋ช…: * node๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. * ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‹œ ์ˆ˜๋™์œผ๋กœ ์„œ๋ฒ„๋ฅผ ์žฌ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. * ์‹ค์ œ ์„œ๋น„์Šค ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. === 3) ์„œ๋ฒ„ ํ…Œ์ŠคํŠธ === ๋ธŒ๋ผ์šฐ์ €์—์„œ ํ…Œ์ŠคํŠธ: * ๋ธŒ๋ผ์šฐ์ € ์—ด๊ธฐ * http://localhost:3000 ์ ‘์† * ์„œ๋ฒ„๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‘๋‹ตํ•˜๋Š”์ง€ ํ™•์ธ ํ„ฐ๋ฏธ๋„์—์„œ ํ…Œ์ŠคํŠธ: <file bash> curl http://localhost:3000 </file> โ€”- ==== 9. ๋””๋ฒ„๊น… ๋ฐ ๋กœ๊น… ==== === 1) ์ฝ˜์†” ๋กœ๊น… === <file javascript> ๊ธฐ๋ณธ ๋กœ๊น… console.log('์ผ๋ฐ˜ ๋ฉ”์‹œ์ง€'); console.error('์—๋Ÿฌ ๋ฉ”์‹œ์ง€'); console.warn('๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€'); ๊ฐ์ฒด ๋กœ๊น… const gameData = { id: 1, name: '๋ฐ”๋‘‘ ๊ฒŒ์ž„' }; console.log('๊ฒŒ์ž„ ๋ฐ์ดํ„ฐ:', gameData); ์‹œ๊ฐ„๊ณผ ํ•จ๊ป˜ ๋กœ๊น… console.log(`${new Date().toISOString()} - ์„œ๋ฒ„ ์‹œ์ž‘๋จ`); </file> === 2) ๋กœ๊น… ๋ฏธ๋“ค์›จ์–ด === <file javascript> ์š”์ฒญ ๋กœ๊น… ๋ฏธ๋“ค์›จ์–ด app.use1)
1)
req, res, next) โ‡’ {
  console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
  next();
}); ์—๋Ÿฌ ๋กœ๊น… ๋ฏธ๋“ค์›จ์–ด app.use((err, req, res, next) โ‡’ {
  console.error('์„œ๋ฒ„ ์—๋Ÿฌ:', err);
  res.status(500).json({ error: '์„œ๋ฒ„ ๋‚ด๋ถ€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.' });
}); </file> === 3) ๋””๋ฒ„๊น… ๋„๊ตฌ === Node.js ๋‚ด์žฅ ๋””๋ฒ„๊ฑฐ ์‚ฌ์šฉ:
node --inspect server.js
Chrome DevTools์—์„œ ๋””๋ฒ„๊น…:
  • Chrome ๋ธŒ๋ผ์šฐ์ € ์—ด๊ธฐ
  • chrome:inspect ์ ‘์† * โ€œOpen dedicated DevTools for Nodeโ€ ํด๋ฆญ โ€”- ==== 10. ์„ฑ๋Šฅ ์ตœ์ ํ™” ==== === 1) ์••์ถ• ์„ค์ • === <file javascript> const compression = require('compression'); ์‘๋‹ต ์••์ถ• ๋ฏธ๋“ค์›จ์–ด app.use(compression()); </file> === 2) ์บ์‹ฑ ์„ค์ • === <file javascript> ์ •์  ํŒŒ์ผ ์บ์‹ฑ app.use(express.static(path.join(__dirname, 'public'), { maxAge: '1d', 1์ผ๊ฐ„ ์บ์‹œ etag: true ETag ์‚ฌ์šฉ })); </file> === 3) ์š”์ฒญ ์ œํ•œ === <file javascript> const rateLimit = require('express-rate-limit'); API ์š”์ฒญ ์ œํ•œ const limiter = rateLimit({ windowMs: 15 * 60 * 1000, 15๋ถ„ max: 100, IP๋‹น ์ตœ๋Œ€ 100๊ฐœ ์š”์ฒญ message: '๋„ˆ๋ฌด ๋งŽ์€ ์š”์ฒญ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.' }); app.use('/api/', limiter); </file> โ€”- ==== 11. ๋ณด์•ˆ ์„ค์ • ==== === 1) Helmet ๋ฏธ๋“ค์›จ์–ด === <file javascript> const helmet = require('helmet'); ๋ณด์•ˆ ํ—ค๋” ์„ค์ • app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: [โ€œ'self'โ€], styleSrc: [โ€œ'self'โ€, โ€œ'unsafe-inline'โ€], scriptSrc: [โ€œ'self'โ€, โ€œ'unsafe-inline'โ€], imgSrc: [โ€œ'self'โ€, โ€œdata:โ€, โ€œhttps:โ€], connectSrc: [โ€œ'self'โ€, โ€œws:โ€, โ€œwss:โ€] } } })); </file> === 2) CORS ์„ค์ • === <file javascript> const cors = require('cors'); CORS ์„ค์ • app.use(cors({ origin: process.env.NODE_ENV === 'production' ? ['https://yourdomain.com'] : ['http://localhost:3000'], credentials: true })); </file> === 3) ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ === <file javascript> ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ ์˜ˆ์ œ app.post('/api/games', (req, res) โ‡’ { const { gameType, settings } = req.body; ํ•„์ˆ˜ ํ•„๋“œ ๊ฒ€์ฆ if (!gameType) { return res.status(400).json({ error: '๊ฒŒ์ž„ ํƒ€์ž…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.' }); } ๋ฐ์ดํ„ฐ ํƒ€์ž… ๊ฒ€์ฆ if (typeof gameType !== 'string') { return res.status(400).json({ error: '๊ฒŒ์ž„ ํƒ€์ž…์€ ๋ฌธ์ž์—ด์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.' }); } ์ถ”๊ฐ€ ์ฒ˜๋ฆฌโ€ฆ }); </file> โ€”- ==== 12. ๋‹ค์Œ ๋‹จ๊ณ„ ==== Node.js ๊ธฐ๋ณธ์„ ๋ฐฐ์› ๋‹ค๋ฉด ๋‹ค์Œ์„ ํ•™์Šตํ•ด๋ณด์„ธ์š”: * Express.js - ์›น ํ”„๋ ˆ์ž„์›Œํฌ ์‹ฌํ™” ํ•™์Šต * Socket.IO - ์‹ค์‹œ๊ฐ„ ํ†ต์‹  ๊ตฌํ˜„ * ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™ - MongoDB, MySQL ๋“ฑ * ์ธ์ฆ ์‹œ์Šคํ…œ - JWT, Passport.js ๋“ฑ * ํ…Œ์ŠคํŠธ ์ž‘์„ฑ - Jest, Mocha ๋“ฑ ์ถ”์ฒœ ํ•™์Šต ์ˆœ์„œ: - ๐Ÿš€ Express.js ์›น ํ”„๋ ˆ์ž„์›Œํฌ - ๐Ÿ”Œ Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹  - โšก PM2 ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌ โ€” ์ด ํŽ˜์ด์ง€๋Š” ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. โ€”
wiki/it/dream_of_enc/metaverse/nodejs.1753772547.txt.gz ยท ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋จ: ์ €์ž 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki