위 사진과 같이 서버에서 클라이언트로 보낼 HTML의 형태를 미리 탬플릿으로 저장 ->
동작 시에 미리 작성된 템플릿에 데이터를 넣어서 완성된 HTML 생성
//코드 예시
html
head // HTML 닫기 태그없이 들여쓰기로 블럭을 구분
title = title // = 을 이용해서 전달받은 변수 사용 가능
body
h1#greeting 안녕하세요
a.link(href="/") 홈으로 // id나 class 태그 뒤에 이어서 바로 사용 () 을 이용해서 attribute 사용
each item in arr //each ~in 표현식으로 주어진 배열의 값 순환하며 HTML 태그 만들 수 있음
if item.name == 'new' // if, else if, else를 이용해 주어진 값의 조건을 확인하여 HTML 태그 만들 수 있음
h1 New Document
else
h1= `${item.name}`
--- layout.pug ---
html //block을 포함한 템플릿을 선언하면 해당 템플릿을 layout으로 사용할 수 있음
head
title= title
body
block content
--- main.pug ---
extends layout // layout을 extends하면 block 부분에 작성한 HTML 태그가 포함됨
block content // 반복되는 웹사이트의 틀을 작성해 두고 extends 하며 개발하면 매우 편리하게 쓸 수 있음
h1 Main Page
---title.pug---
h1= title
---main.pug
extend layout
block content
include title // 자주 반복되는 구문을 미리 작성 후 include하여 사용할 수 있음
div.content // 일반적인 텍스트 파일도 include하여 템플릿에 포함 가능
안녕하세요
pre
include article.txt
--- listItem.pug ---
mixin listItem(title, name) // mixin을 사용하여 템플릿을 함수처럼 사용할 수 있게 선언할 수 있음
tr
td title
td name
--- main.pug ---
include listItem //include는 값을 지정할 수 없지만 mixin은 파라미터를 지정하여 값을 넘겨받아 템플릿에 사용 가능
table
tbody
listItem('제목','이름')
const asyncHandler = (requestHandler) => { //asyncHandler는 requestHandler를 매개변수로 갖는 함수형 미들웨어
return async (req, res, next) => { //전달된 requestHandler는 try ~catch로 감싸져 asyncHandler 내에서 실행된다
try {
await requestHandler(req, res);
} catch (err) {
next(err);
}
}
}
---
router.get('/', asyncHandler(async (req, res) => {
const posts = await Posts.find({});
if (posts.length < 1) {
throw new Error('Not Found'); //throw되는 에러는 자동으로 오류처리 미들웨어로 전달되도록 구성
}
res.render('posts/list', { posts });
});
router.get(... => {
const page = // page - 현재 페이지
Number(req.query.page || 1)
const perPage = //perPage - 페이지 당 게시글 수
Number(req.query.perPage || 10) //query는 문자열로 전달되기 때문에 Number로 형변환이 필요함
///posts?page=1&perPage=10 일반적으로 url query 를 사용해 전달
...
//MongoDB 의 limit과 skip을 사용하여 pagination 구현 가능
router.get(... => {
...
const total = await Post
.countDocument({});
const posts = await Post.find({})
.sort({ createdAt: -1 }) //pagination 시에는 데이터의 순서가 유지될 수 있도록 sort를 사용할 수 있도록 함
.skip(perPage * (page - 1)) //skip - 검색 시 포함하지 않을 데이터 수
.limit(perPage); //limit - 검색 결과 수 제한
const totalPage =
Math.ceil(total / perPage);
...
//pagination을 mixin으로 선언
mixin pagination(path)
p
- for(let i = 1; i <= totalPage; i++)
a(href=`${path}?page=${i}&perPage=${perPage}`)
if i == page
b= i
else
= i
= " "
---
//pagination이 필요한 페이지에서 해당 템플릿을 include한 후, +pagination으로 mixin 을 사용 함
include pagination
tr
td
+pagination("/posts")
//$ pm2 init simple 혹은 $ pm2 init 명령어를 이용하여 pm2 설정파일 예제를 만들 수 있음.
module.exports = {
apps : [{
name: 'simple-board',
script: './bin/www',
watch: '.',
ignore_watch: 'views',
}],
};
---
$ pm2 start