μ‚¬μš©μž 도ꡬ

μ‚¬μ΄νŠΈ 도ꡬ


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 이벀트 ν•Έλ“€λŸ¬λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

// 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);
    });
});

μ„€λͺ…:

  • io.on('connection') - μƒˆλ‘œμš΄ ν΄λΌμ΄μ–ΈνŠΈκ°€ 연결될 λ•Œ μ‹€ν–‰λ©λ‹ˆλ‹€.
  • socket.on('join-game') - ν΄λΌμ΄μ–ΈνŠΈκ°€ κ²Œμž„ μ°Έκ°€ μš”μ²­μ„ 보낼 λ•Œ μ‹€ν–‰λ©λ‹ˆλ‹€.
  • socket.join(gameId) - νŠΉμ • κ²Œμž„λ°©μ— μ†ŒμΌ“μ„ μΆ”κ°€ν•©λ‹ˆλ‹€.
  • socket.on('disconnect') - ν΄λΌμ΄μ–ΈνŠΈ 연결이 λŠμ–΄μ§ˆ λ•Œ μ‹€ν–‰λ©λ‹ˆλ‹€.

5) μ„œλ²„ 포트 μ„€μ • 및 μ‹€ν–‰

ν™˜κ²½ λ³€μˆ˜μ—μ„œ 포트 번호λ₯Ό κ°€μ Έμ˜€κ±°λ‚˜ κΈ°λ³Έκ°’(3000)을 μ‚¬μš©ν•˜μ—¬ μ„œλ²„λ₯Ό μ§€μ •λœ ν¬νŠΈμ—μ„œ μ‹€ν–‰ν•©λ‹ˆλ‹€.

// ν™˜κ²½ λ³€μˆ˜μ—μ„œ PORTλ₯Ό κ°€μ Έμ˜€κ±°λ‚˜ κΈ°λ³Έκ°’ 3000 μ‚¬μš©
const PORT = process.env.PORT || 3000;
 
// μ„œλ²„λ₯Ό μ§€μ •λœ ν¬νŠΈμ—μ„œ μ‹€ν–‰ν•˜κ³ , 성곡 μ‹œ μ½˜μ†”μ— λ©”μ‹œμ§€ 좜λ ₯
server.listen(PORT, () => {
    console.log(`μ„œλ²„κ°€ 포트 ${PORT}μ—μ„œ μ‹€ν–‰ μ€‘μž…λ‹ˆλ‹€.`);
    console.log(`http://localhost:${PORT}μ—μ„œ μ ‘μ†ν•˜μ„Έμš”.`);
});

μ„€λͺ…:

  • 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 νŒŒμΌμ„ μƒμ„±ν•˜μ—¬ ν™˜κ²½ λ³€μˆ˜λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€:

# μ„œλ²„ 포트 μ„€μ •
PORT=3000
 
# λ°μ΄ν„°λ² μ΄μŠ€ μ—°κ²° 정보
MONGODB_URI=mongodb://localhost:27017/baduk_metaverse
 
# JWT μ‹œν¬λ¦Ώ ν‚€
JWT_SECRET=your-secret-key-here
 
# ν™˜κ²½ μ„€μ •
NODE_ENV=development

μ£Όμš” ν™˜κ²½ λ³€μˆ˜:

  • PORT - μ„œλ²„κ°€ 싀행될 포트 번호
  • MONGODB_URI - MongoDB λ°μ΄ν„°λ² μ΄μŠ€ μ—°κ²° λ¬Έμžμ—΄
  • JWT_SECRET - JWT 토큰 μ•”ν˜Έν™”μ— μ‚¬μš©ν•  μ‹œν¬λ¦Ώ ν‚€
  • NODE_ENV - ν˜„μž¬ ν™˜κ²½ (development/production)

2) ν™˜κ²½ λ³€μˆ˜ μ‚¬μš©λ²•

// 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;

μ„€λͺ…:

  • require('dotenv').config() - .env νŒŒμΌμ„ λ‘œλ“œν•©λ‹ˆλ‹€.
  • process.env.λ³€μˆ˜λͺ… - ν™˜κ²½ λ³€μˆ˜ 값을 κ°€μ Έμ˜΅λ‹ˆλ‹€.
  • || κΈ°λ³Έκ°’ - ν™˜κ²½ λ³€μˆ˜κ°€ 없을 λ•Œ 기본값을 μ‚¬μš©ν•©λ‹ˆλ‹€.

6. ν”„λ‘œμ νŠΈ ꡬ쑰

ꢌμž₯ν•˜λŠ” ν”„λ‘œμ νŠΈ 폴더 ꡬ쑰:

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

각 ν΄λ”μ˜ μ—­ν• :

  • public/ - ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ μ œκ³΅ν•  νŒŒμΌλ“€
  • routes/ - URL κ²½λ‘œλ³„ 처리 둜직
  • controllers/ - λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 처리
  • models/ - 데이터 ꡬ쑰 μ •μ˜
  • middleware/ - μš”μ²­ 처리 쀑간 단계
  • utils/ - 곡톡 μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜λ“€
  • tests/ - ν…ŒμŠ€νŠΈ μ½”λ“œλ“€

7. 개발 ν™˜κ²½ μ„€μ •

1) Node.js μ„€μΉ˜

Windowsμ—μ„œ Node.js μ„€μΉ˜:

  • Node.js 곡식 μ›Ήμ‚¬μ΄νŠΈ (https://nodejs.org) λ°©λ¬Έ
  • LTS 버전 λ‹€μš΄λ‘œλ“œ 및 μ„€μΉ˜
  • μ„€μΉ˜ μ™„λ£Œ ν›„ ν„°λ―Έλ„μ—μ„œ 확인:
node --version
npm --version

2) ν”„λ‘œμ νŠΈ μ΄ˆκΈ°ν™”

# μƒˆ 폴더 생성 및 이동
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

3) κΈ°λ³Έ μ„œλ²„ 파일 생성

server.js νŒŒμΌμ„ μƒμ„±ν•˜κ³  κΈ°λ³Έ μ½”λ“œλ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€:

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}μ—μ„œ μ‹€ν–‰ μ€‘μž…λ‹ˆλ‹€.`);
});

4) package.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"
  }
}

8. μ„œλ²„ μ‹€ν–‰ 및 ν…ŒμŠ€νŠΈ

1) 개발 λͺ¨λ“œλ‘œ μ„œλ²„ μ‹€ν–‰

npm run dev

μ„€λͺ…:

  • nodemon을 μ‚¬μš©ν•˜μ—¬ μ„œλ²„λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.
  • μ½”λ“œ λ³€κ²½ μ‹œ μžλ™μœΌλ‘œ μ„œλ²„κ°€ μž¬μ‹œμž‘λ©λ‹ˆλ‹€.
  • 개발 쀑에 맀우 μœ μš©ν•©λ‹ˆλ‹€.

2) ν”„λ‘œλ•μ…˜ λͺ¨λ“œλ‘œ μ„œλ²„ μ‹€ν–‰

npm start

μ„€λͺ…:

  • nodeλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„œλ²„λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.
  • μ½”λ“œ λ³€κ²½ μ‹œ μˆ˜λ™μœΌλ‘œ μ„œλ²„λ₯Ό μž¬μ‹œμž‘ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • μ‹€μ œ μ„œλΉ„μŠ€ ν™˜κ²½μ—μ„œ μ‚¬μš©ν•©λ‹ˆλ‹€.

3) μ„œλ²„ ν…ŒμŠ€νŠΈ

λΈŒλΌμš°μ €μ—μ„œ ν…ŒμŠ€νŠΈ:

  • λΈŒλΌμš°μ € μ—΄κΈ°
  • http://localhost:3000 접속
  • μ„œλ²„κ°€ μ •μƒμ μœΌλ‘œ μ‘λ‹΅ν•˜λŠ”μ§€ 확인

ν„°λ―Έλ„μ—μ„œ ν…ŒμŠ€νŠΈ:

curl http://localhost:3000

9. 디버깅 및 λ‘œκΉ…

1) μ½˜μ†” λ‘œκΉ…

// κΈ°λ³Έ λ‘œκΉ…
console.log('일반 λ©”μ‹œμ§€');
console.error('μ—λŸ¬ λ©”μ‹œμ§€');
console.warn('κ²½κ³  λ©”μ‹œμ§€');
 
// 객체 λ‘œκΉ…
const gameData = { id: 1, name: 'λ°”λ‘‘ κ²Œμž„' };
console.log('κ²Œμž„ 데이터:', gameData);
 
// μ‹œκ°„κ³Ό ν•¨κ»˜ λ‘œκΉ…
console.log(`${new Date().toISOString()} - μ„œλ²„ μ‹œμž‘λ¨`);

2) λ‘œκΉ… 미듀웨어

// μš”μ²­ λ‘œκΉ… 미듀웨어
app.use((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: 'μ„œλ²„ λ‚΄λΆ€ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.' });
});

3) 디버깅 도ꡬ

Node.js λ‚΄μž₯ 디버거 μ‚¬μš©:

node --inspect server.js

Chrome DevToolsμ—μ„œ 디버깅:

  • Chrome λΈŒλΌμš°μ € μ—΄κΈ°
  • chrome://inspect 접속
  • β€œOpen dedicated DevTools for Node” 클릭

10. μ„±λŠ₯ μ΅œμ ν™”

1) μ••μΆ• μ„€μ •

const compression = require('compression');
 
// 응닡 μ••μΆ• 미듀웨어
app.use(compression());

2) 캐싱 μ„€μ •

// 정적 파일 캐싱
app.use(express.static(path.join(dirname, 'public'), {
    maxAge: '1d', // 1일간 μΊμ‹œ
    etag: true    // ETag μ‚¬μš©
}));

3) μš”μ²­ μ œν•œ

const rateLimit = require('express-rate-limit');
 
// API μš”μ²­ μ œν•œ
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15λΆ„
    max: 100, // IPλ‹Ή μ΅œλŒ€ 100개 μš”μ²­
    message: 'λ„ˆλ¬΄ λ§Žμ€ μš”μ²­μ΄ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.'
});
 
app.use('/api/', limiter);

11. λ³΄μ•ˆ μ„€μ •

1) Helmet 미듀웨어

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:"]
        }
    }
}));

2) CORS μ„€μ •

const cors = require('cors');
 
// CORS μ„€μ •
app.use(cors({
    origin: process.env.NODE_ENV === 'production' 
        ? ['https://yourdomain.com'] 
        : ['http://localhost:3000'],
    credentials: true
}));

3) μž…λ ₯ 데이터 검증

// μž…λ ₯ 데이터 검증 예제
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: 'κ²Œμž„ νƒ€μž…μ€ λ¬Έμžμ—΄μ΄μ–΄μ•Ό ν•©λ‹ˆλ‹€.' });
    }
 
    // μΆ”κ°€ 처리...
});

12. λ‹€μŒ 단계

Node.js 기본을 λ°°μ› λ‹€λ©΄ λ‹€μŒμ„ ν•™μŠ΅ν•΄λ³΄μ„Έμš”:

  • Express.js - μ›Ή ν”„λ ˆμž„μ›Œν¬ 심화 ν•™μŠ΅
  • Socket.IO - μ‹€μ‹œκ°„ 톡신 κ΅¬ν˜„
  • λ°μ΄ν„°λ² μ΄μŠ€ 연동 - MongoDB, MySQL λ“±
  • 인증 μ‹œμŠ€ν…œ - JWT, Passport.js λ“±
  • ν…ŒμŠ€νŠΈ μž‘μ„± - Jest, Mocha λ“±

μΆ”μ²œ ν•™μŠ΅ μˆœμ„œ:

β€” 이 νŽ˜μ΄μ§€λŠ” μžλ™μœΌλ‘œ μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€. β€”

wiki/it/dream_of_enc/metaverse/nodejs.txt Β· λ§ˆμ§€λ§‰μœΌλ‘œ μˆ˜μ •λ¨: (λ°”κΉ₯ νŽΈμ§‘)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki