Search

๋„Œ์ ์Šค Nunjucks

๋„Œ์ ์Šค

Node.js ์˜ ํ…œํ”Œ๋ฆฟ ์—”์ง„
Nunjucks๋Š” ํ…œํ”Œ๋ฆฟ ์—”์ง„ ์ค‘ ํ•˜๋‚˜๋กœ, JavaScript๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๊ฐ•๋ ฅํ•˜๊ณ  ์œ ์—ฐํ•œ ํ…œํ”Œ๋ฆฟ ์—”์ง„์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ Node.js ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, Express.js์™€ ํ•จ๊ป˜ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
ํ™•์žฅ์ž : *.njk

์ฃผ์š” ๋ฌธ๋ฒ•

๋ฌธ๋ฒ•
์˜ˆ์‹œ
์„ค๋ช…
๋ณ€์ˆ˜ ์ถœ๋ ฅ
{{ variableName }}
๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ถœ๋ ฅ
์กฐ๊ฑด๋ฌธ
{% if condition %} ... {% endif %}
์กฐ๊ฑด์— ๋”ฐ๋ผ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰
๋ฐ˜๋ณต๋ฌธ
{% for item in itemList %} ... {% endfor %}
๋ฐฐ์—ด์ด๋‚˜ ๊ฐ์ฒด์˜ ๊ฐ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ๋ฐ˜๋ณต
ํ•„ํ„ฐ
{{ variableName | filterName }}
๋ณ€์ˆ˜์— ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜์—ฌ ์ถœ๋ ฅ
๋งคํฌ๋กœ
{% macro myMacro(param) %} ... {% endmacro %}
์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ ๋ธ”๋ก ์ •์˜
๋งคํฌ๋กœ ํ˜ธ์ถœ
{{ myMacro(param) }}
์ •์˜๋œ ๋งคํฌ๋กœ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‚ฌ์šฉ
ํ…œํ”Œ๋ฆฟ ์ƒ์†
{% extends layoutTemplate %}
๋‹ค๋ฅธ ํ…œํ”Œ๋ฆฟ์„ ํ™•์žฅํ•˜์—ฌ ์‚ฌ์šฉ
๋ธ”๋ก ์ •์˜์™€ ์žฌ์ •์˜
{% block content %} ... {% endblock %}
ํ…œํ”Œ๋ฆฟ ์ƒ์† ์‹œ ๋ธ”๋ก์„ ์ •์˜ํ•˜๊ณ  ์žฌ์ •์˜
์ฃผ์„
{# ์ฃผ์„ ๋‚ด์šฉ #}
์ฃผ์„ ์ฒ˜๋ฆฌ

์„œ๋ฒ„์—์„œ ๋ทฐ๋กœ ๋ณ€์ˆ˜ ์ „๋‹ฌ ๋ฐฉ๋ฒ•

1.
Nunjucks ์„ค์ • ๋ฐ ๋ทฐ ์—”์ง„ ์„ค์ •
2.
์„œ๋ฒ„์—์„œ ๋ทฐ๋กœ ๋ณ€์ˆ˜ ์ „๋‹ฌ
3.
Nunjucks ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ (example.njk)

Nunjucks ์„ค์ • ๋ฐ ๋ทฐ ์—”์ง„ ์„ค์ •

const express = require('express'); const nunjucks = require('nunjucks'); const app = express(); nunjucks.configure('views', { autoescape: true, express: app, }); app.set('view engine', 'njk');
JavaScript
๋ณต์‚ฌ

์„œ๋ฒ„์—์„œ ๋ทฐ๋กœ ๋ณ€์ˆ˜ ์ „๋‹ฌ

app.get('/example', (req, res) => { const data = { title: 'Nunjucks Example', message: 'Hello World', itemList: ['Item 1', 'Item 2', 'Item 3'], }; res.render('example', data); });
JavaScript
๋ณต์‚ฌ

Nunjucks ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ (example.njk)

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ title }}</title> </head> <body> <h1>{{ message }}</h1> <ul> {% for item in itemList %} <li>{{ item }}</li> {% endfor %} </ul> </body> </html>
JavaScript
๋ณต์‚ฌ

๊ฒŒ์‹œํŒ ์˜ˆ์‹œ์ฝ”๋“œ

1.
๋ผ์šฐํ„ฐ ํŒŒ์ผ ์ƒ์„ฑ ๋ฐ ์„ค์ •
2.
๋ผ์šฐํ„ฐ ์ •์˜
3.
njk ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ ์ž‘์„ฑ
4.
style.css ์—ฐ๊ฒฐ
5.
index.njk ์ž‘์„ฑ
6.
header, footer ์ถ”๊ฐ€
7.
๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž… ํ™”๋ฉด ์ž‘์„ฑ
8.
๊ฒŒ์‹œํŒ ํ™”๋ฉด ์ž‘์„ฑ

๋ผ์šฐํ„ฐ ํŒŒ์ผ ์ƒ์„ฑ ๋ฐ ์„ค์ •

1.
routes ํด๋” ์ƒ์„ฑ
2.
index.js, board.js ํŒŒ์ผ ์ƒ์„ฑ
3.
app.js ์— import ๋ฐ ๋ฏธ๋“ค์›จ์–ด ์„ค์ •

routes ํด๋” ์ƒ์„ฑ

index.js, board.js ํŒŒ์ผ ์ƒ์„ฑ

app.js ์— import ๋ฐ ๋ฏธ๋“ค์›จ์–ด ์„ค์ •

// nunjucks import const nunjucks = require('nunjucks'); // ๐Ÿ‘ฉโ€๐Ÿ’ป ๋ผ์šฐํ„ฐ ๋ชจ๋“ˆ import const indexRouter = require('./routes/index'); const boardRouter = require('./routes/board');
JavaScript
๋ณต์‚ฌ
// Nunjucks ์„ค์ • nunjucks.configure('views', { express: app, watch: true, }); app.set('view engine', 'njk'); // ๐Ÿ‘ฉโ€๐Ÿ’ป ๋ผ์šฐํ„ฐ ์„ค์ • app.use('/', indexRouter); app.use('/board', boardRouter);
JavaScript
๋ณต์‚ฌ

๋ผ์šฐํ„ฐ ์ •์˜

1.
index.js
2.
board.js

index.js

const express = require('express'); const router = express.Router(); // GET / ๋ผ์šฐํ„ฐ router.get('/', (req, res) => { res.render('index', { title: 'Main' }); }); // ๋กœ๊ทธ์ธ router.get('/login', (req, res) => { res.render('login', { title: 'Login' }); }); // ํšŒ์›๊ฐ€์ž… router.get('/join', (req, res) => { res.render('join', { title: 'Join' }); }); module.exports = router;
JavaScript
๋ณต์‚ฌ

board.js

const express = require('express') const router = express.Router() let boardList = [ { title : '์ œ๋ชฉ1', writer : '์ž‘์„ฑ์ž1', content : '๋‚ด์šฉ1' }, { title : '์ œ๋ชฉ2', writer : '์ž‘์„ฑ์ž2', content : '๋‚ด์šฉ2' }, { title : '์ œ๋ชฉ3', writer : '์ž‘์„ฑ์ž3', content : '๋‚ด์šฉ3' }, ] // ๐Ÿ‘ฉโ€๐Ÿ’ป ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก router.get('/', (req, res) => { res.render('board/list', {boardList} ) }) // ๐Ÿ‘ฉโ€๐Ÿ’ป ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก router.get('/insert', (req, res) => { res.render('board/insert') }) // ๐Ÿ‘ฉโ€๐Ÿ’ป ๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก router.post('/', (req, res) => { // ๊ตฌ์กฐ๋ถ„ํ•ดํ• ๋‹น const { title, writer, content } = req.body; // const title = req.body.title // const writer = req.body.writer // const content = req.body.content const newBoard = { title, writer, content }; boardList.push(newBoard); res.redirect('/board'); }); // ๐Ÿ‘ฉโ€๐Ÿ’ป ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ • ํŽ˜์ด์ง€ router.get('/update/:id', (req, res) => { console.log(`id : ${req.params.id}`); let id = req.params.id const board = boardList[id]; res.render('board/update', { board, id }); }); // ๐Ÿ‘ฉโ€๐Ÿ’ป ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ • router.post('/update', (req, res) => { const { id, title, writer, content } = req.body; boardList[id] = { title, writer, content }; res.redirect(`/board/${id}`); }); // ๐Ÿ‘ฉโ€๐Ÿ’ป ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ router.post('/delete', (req, res) => { const id = req.params.id; boardList.splice(id, 1); res.redirect('/board'); }); // ๐Ÿ‘ฉโ€๐Ÿ’ป ๊ฒŒ์‹œ๊ธ€ ์ฝ๊ธฐ // ์š”์ฒญ ๊ฒฝ๋กœ์— ํŒŒ๋ผ๋ฏธํ„ฐ ๋งคํ•‘ ๋ฐฉ๋ฒ• โžก '/:ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…' router.get('/:id', (req, res) => { console.log(`id : ${req.params.id}`); let id = req.params.id let board = boardList[id] res.render('board/read', {board, id}) }) module.exports = router;
JavaScript
๋ณต์‚ฌ

njk ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ ์ž‘์„ฑ

1.
layout.njk
{# layout.njk #} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}My App{% endblock %}</title> {# ์—ฌ๊ธฐ์— CSS ์—ฐ๊ฒฐ #} </head> <body> <div id="content"> {% block content %}{% endblock %} </div> </body> </html>
JavaScript
๋ณต์‚ฌ

style.css ์—ฐ๊ฒฐ

1.
public/css ํด๋” ์ƒ์„ฑ
2.
style.css ํŒŒ์ผ ์ƒ์„ฑ
3.
์Šคํƒ€์ผ ์ž‘์„ฑ

public/css ํด๋” ์ƒ์„ฑ

style.css ํŒŒ์ผ ์ƒ์„ฑ

์Šคํƒ€์ผ ์ž‘์„ฑ

* { margin: 0; padding: 0; box-sizing: border-box; } ul { list-style-type: none; } a { text-decoration: none; } body { font-family: Arial, sans-serif; } /* header */ header { display: flex; justify-content: space-between; align-items: center; background-color: #333; color: #fff; padding: 0 20px; text-align: center; height: 80px; } header h1 { margin: 0; } header nav { height: 100%; } header nav ul { height: 100%; } header nav li { display: inline-block; height: 100%; } header nav a { display: flex; justify-content: center; align-items: center; color: #fff; text-decoration: none; min-width: 100px; height: 100%; } header nav a:hover { background-color: #fff; color: #333; } /* footer */ footer { background-color: #333; color: #fff; padding: 10px; text-align: center; } .container { border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); padding: 20px; width: 300px; margin: 100px auto; } .container-md { border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); padding: 20px; width: 480px; margin: 100px auto; } .container-lg { border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); padding: 20px; width: 1024px; margin: 100px auto; } .container h2 { text-align: center; } .form-group { margin-bottom: 15px; } .form-group label { display: block; margin-bottom: 8px; font-weight: bold; } .form-group input, .form-group .btn { display: inline-block; font-size: 14px; width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } .form-group .btn { text-align: center; background-color: #4caf50; color: #fff; border: none; border-radius: 4px; cursor: pointer; margin-bottom: 10px; } .form-group .btn:hover { background-color: #45a049; } /* table */ .table { width: 100%; border-collapse: collapse; margin-top: 20px; } .table th, .table td { border: 1px solid #ddd; padding: 8px; text-align: left; } .table th { background-color: #f2f2f2; } .table tr:hover { background-color: #f5f5f5; } /* button */ .btn-box { display: flex; justify-content: space-between; align-items: center; margin: 20px 0; } .btn { display: inline-block; text-align: center; font-size: 14px; padding: 8px 18px; box-sizing: border-box; background-color: #4caf50; color: #fff; border: none; border-radius: 4px; cursor: pointer; margin-bottom: 10px; }
JavaScript
๋ณต์‚ฌ

layout.njk

{# layout.njk #} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}My App{% endblock %}</title> <link rel="stylesheet" href="/css/style.css"> {# ์—ฌ๊ธฐ์— CSS ์—ฐ๊ฒฐ #} </head> <body> <div id="content"> {% block content %}{% endblock %} </div> </body> </html>
HTML
๋ณต์‚ฌ

index.njk ์ž‘์„ฑ

{% extends 'layout.njk' %} {% block content %} <div class="container-lg"> <h1>{{ title }}</h1> <h3>{{ title }} ํ™”๋ฉด์ž…๋‹ˆ๋‹ค</h3> </div> {% endblock %}
HTML
๋ณต์‚ฌ
1.
extends layout: ํ˜„์žฌ ํ…œํ”Œ๋ฆฟ์ด layout.njk๋ผ๋Š” ๋‹ค๋ฅธ ํ…œํ”Œ๋ฆฟ์„ ํ™•์žฅํ•œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ธฐ๋ณธ ๋ ˆ์ด์•„์›ƒ์„ ์ •์˜ํ•˜๊ณ , ๋‹ค์–‘ํ•œ ํŽ˜์ด์ง€์—์„œ ์ด ๋ ˆ์ด์•„์›ƒ์„ ํ™•์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.
2.
block content: ์ด ๋ถ€๋ถ„์€ layout.njk์—์„œ ์ •์˜ํ•œ block content์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค. block content๋Š” ๋‹ค๋ฅธ ํ…œํ”Œ๋ฆฟ์—์„œ ํ™•์žฅ๋  ๋•Œ ์ฑ„์›Œ์งˆ ๋ถ€๋ถ„์„ ์ •์˜ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
3.
div.container-lg: ์ด ๋ถ€๋ถ„์€ ํŠน์ • ํŽ˜์ด์ง€์˜ ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ์‹ธ๋Š” div ์š”์†Œ๋กœ, Bootstrap์˜ container-lg ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปจํ…์ธ ์˜ ๋„ˆ๋น„๋ฅผ ์กฐ์ ˆํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
4.
h1= title: title ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์ถœ๋ ฅํ•˜๋Š” ํ—ค๋”ฉ(์ œ๋ชฉ) ์š”์†Œ์ž…๋‹ˆ๋‹ค.
5.
h3 #{title} ํ™”๋ฉด์ž…๋‹ˆ๋‹ค: title ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ํฌํ•จํ•œ ๊ฐ„๋‹จํ•œ ์„ค๋ช…์„ ์ถœ๋ ฅํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ํ—ค๋”ฉ(๋ถ€์ œ๋ชฉ) ์š”์†Œ์ž…๋‹ˆ๋‹ค.

header, footer ์ถ”๊ฐ€

header.njk

<header> <h1>Nunjucks</h1> <nav> <ul> <li><a href="/">Home</a></li> <li><a href="/login">Login</a></li> <li><a href="/board">Board</a></li> </ul> </nav> </header>
HTML
๋ณต์‚ฌ

footer.njk

<footer> <p>Copyright ยฉ 2023 Pug</p> </footer>
HTML
๋ณต์‚ฌ

layout.njk

{# layout.njk #} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}My App{% endblock %}</title> <link rel="stylesheet" href="/css/style.css"> </head> <body> {% include "fragment/header.njk" %} <div id="content"> {% block content %}{% endblock %} </div> {% include "fragment/footer.njk" %} </body> </html>
HTML
๋ณต์‚ฌ

๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž… ํ™”๋ฉด ์ž‘์„ฑ

login.njk

{% extends 'layout.njk' %} {% block content %} <div class="container"> <h2>Login</h2> <form> <div class="form-group"> <label for="username">Username:</label> <input type="text" id="username" name="username" required> </div> <div class="form-group"> <label for="password">Password:</label> <input type="password" id="password" name="password" required> </div> <div class="form-group"> <button class="btn" type="submit">Login</button> <a class="btn" href="/join">Sign Up</a> </div> </form> </div> {% endblock %}
HTML
๋ณต์‚ฌ

join.njk

{% extends 'layout.njk' %} {% block content %} <div class="container"> <h2>Sign Up</h2> <form> <div class="form-group"> <label for="username">Username:</label> <input type="text" id="username" name="username" required> </div> <div class="form-group"> <label for="email">Email:</label> <input type="email" id="email" name="email" required> </div> <div class="form-group"> <label for="password">Password:</label> <input type="password" id="password" name="password" required> </div> <div class="form-group"> <button class="btn" type="submit">Sign Up</button> </div> </form> </div> {% endblock %}
HTML
๋ณต์‚ฌ

๊ฒŒ์‹œํŒ ํ™”๋ฉด ์ž‘์„ฑ

1.
board/list.njk (๋ชฉ๋ก)
2.
board/insert.njk(๊ธ€์“ฐ๊ธฐ)
3.
board/read.njk (๊ธ€์ฝ๊ธฐ)
4.
board/update.njk(๊ธ€์ˆ˜์ •)

board/list.njk

{% extends '../layout.njk' %} {% block content %} <div class="container-lg"> <div class="btn-box"> <h1>๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก</h1> <a class="btn" href="/board/insert">๊ธ€์“ฐ๊ธฐ</a> </div> <table class="table" border="1"> <thead> <tr> <th>No</th> <th>Title</th> <th>Writer</th> </tr> </thead> <tbody> {% for board in boardList %} <tr> <td width="80">{{ loop.index }}</td> <td> <a href="/board/{{ loop.index }}">{{ board.title }}</a> </td> <td width="200">{{ board.writer }}</td> </tr> {% endfor %} </tbody> </table> </div> {% endblock %}
HTML
๋ณต์‚ฌ

board/insert.njk

{% extends '../layout.njk' %} {% block content %} <div class="container-lg"> <h1>๊ฒŒ์‹œ๊ธ€ ๋“ฑ๋ก</h1> <form action="/board" method="post"> <table class="table form-group" border="1"> <tr> <th width="200">Title</th> <td> <input type="text" name="title"> </td> </tr> <tr> <th width="200">Writer</th> <td> <input type="text" name="writer"> </td> </tr> <tr> <th width="200">Content</th> <td> <input type="text" name="content"> </td> </tr> </table> <div class="btn-box"> <a class="btn" href="/board">๋ชฉ๋ก</a> <button class="btn" type="submit">๋“ฑ๋ก</button> </div> </form> </div> {% endblock %}
HTML
๋ณต์‚ฌ

board/read.njk

{% extends '../layout.njk' %} {% block content %} <div class="container-lg"> <h1>{{ board.title }}</h1> <table class="table" border="1"> <tr> <th width="200">No</th> <td>{{ id }}</td> </tr> <tr> <th width="200">Writer</th> <td>{{ board.writer }}</td> </tr> <tr> <th width="200">Content</th> <td>{{ board.content }}</td> </tr> </table> <div class="btn-box"> <a class="btn" href="/board">๋ชฉ๋ก</a> <a class="btn" href="/board/update/{{ id }}">์ˆ˜์ •</a> </div> </div> {% endblock %}
HTML
๋ณต์‚ฌ

board/update.njk

{% extends '../layout.njk' %} {% block content %} <div class="container-lg"> <h1>๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •</h1> <form action="/board/update" method="post"> <input type="hidden" name="id" value="{{ id }}"> <table class="table form-group" border="1"> <tr> <th width="200">No</th> <td>{{ id }}</td> </tr> <tr> <th width="200">Title</th> <td> <input type="text" name="title" value="{{ board.title }}"> </td> </tr> <tr> <th width="200">Writer</th> <td> <input type="text" name="writer" value="{{ board.writer }}"> </td> </tr> <tr> <th width="200">Content</th> <td> <input type="text" name="content" value="{{ board.content }}"> </td> </tr> </table> <div class="btn-box"> <a class="btn" href="/board">๋ชฉ๋ก</a> <button class="btn" type="submit">์ˆ˜์ •</button> </div> </form> </div> {% endblock %}
HTML
๋ณต์‚ฌ

app.js ์ „์ฒด์ฝ”๋“œ

const express = require('express'); const morgan = require('morgan'); const cookieParser = require('cookie-parser'); const session = require('express-session'); const nunjucks = require('nunjucks'); const path = require('path'); const app = express(); app.set('port', 3000); // Nunjucks ์„ค์ • nunjucks.configure('views', { express: app, watch: true, }); app.set('view engine', 'njk'); app.use(morgan('dev')); app.use('/', express.static(path.join(__dirname, 'public'))); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(session({ resave: false, saveUninitialized: false, secret: 'session-secret', cookie: { httpOnly: true, secure: false, }, name: 'session-cookie', })); // ๋ผ์šฐํ„ฐ ๋ชจ๋“ˆ import const indexRouter = require('./routes/index'); const boardRouter = require('./routes/board'); // ๋ผ์šฐํ„ฐ ์„ค์ • app.use('/', indexRouter); app.use('/board', boardRouter); // 404 ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ๋ฏธ๋“ค์›จ์–ด app.use((req, res, next) => { res.status(404).send('Not Found'); }); // ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฏธ๋“ค์›จ์–ด app.use((err, req, res, next) => { console.error(err); res.status(500).send(err.message); }); app.listen(app.get('port'), () => { console.log(app.get('port'), '๋ฒˆ ํฌํŠธ์—์„œ ๋Œ€๊ธฐ ์ค‘'); });
JavaScript
๋ณต์‚ฌ