가끔 생각을 해요 ʕتʔ

 

🍒 Template Engine

 

Template Engine이란?

서버에서 클라이언트로 보낼 HTML의 형태를 미리 템플릿으로 저장

동작 시에 미리 작성된 템플릿에 데이터를 넣어서 완성된 HTML 생성

템플릿 엔진은 템플릿 작성 문법과 작성된 템플릿을 HTML로 변환하는 기능을 제공

템플릿 엔진은 EJS, Mustache, Pug 등이 있다.

✔️ EJS - html과 유사한 문법의 템플릿 엔진

✔️ Mustache - 간단한 데이터 치환 정도만 제공하는 경량화된 템플릿 엔진

✔️ Pug - 들여쓰기 표현식을 이용한 간략한 표기와 레이아웃 등 강력한 기능을 제공

 

Pug

들여쓰기 표현식을 이용해 가독성이 좋고 개발 생산성이 높음

HTML을 잘 모르더라도 문법적 실수를 줄일 수 있음

layout, include, mixin 등 강력한 기능 제공

 

express-generater 사용할 때 view 옵션으로 pug 템플릿 지정하는 방법

vscode에 기본적으로 있는 터미널 사용

$ express —view=pug simple-board 입력 후 만들어진 simple-board 폴더를 연다.

app.js파일을 살펴보면 view engine이 setup 되어있는 걸 확인할 수 있다.

‘views’ 디렉터리를 사용하고 있고, ‘view engine’은 ‘pug’를 사용하고 있다는 뜻이다.

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

views 디렉터리를 확인해보면 기본적인 index, layout, error.pug 템플릿 파일들이 존재하는 것을 알 수 있다.

 

🍒 Async Request Handler

 

Async Request Handler란?

공식적인 express의 기술은 아니다. express를 사용하는 패턴 중 하나

async의 비동기 처리는 매우 편리하지만, 매번 try/catch 구문을 작성하는 것은 귀찮고 실수하기 쉽다.

async request handler을 사용하게 되면 async 함수를 좀 더 쉽게 사용할 수 있고, request handler을 처리하는 데 있어서 공통적으로 오류처리를 할 수 있는 부분을 간단하게 구현할 수 있는 패턴이기 때문에 만약 express project를 할 때 좀 더 유용하게 할 수 있다.

// ./utils/async-handler.js
module.exports = (requestHandler) => {
  return async (req, res, next) => {
    try {
        await requestHandler(req, res);
    } catch (err) {
        next(err);
    }
  }
}
---
// ./routes/posts.js
router.get('/', asyncHandler(async (req, res) => {
  const posts = await Post.find({});
if (posts.length < 1) {
	throw new Error('Not Found');
}
  res.render('post/list', { posts });
}));

asyncHandler는 requestHandler를 매개변수로 갖는 함수형 미들웨어다.

전달된 requestHandler는 try/catch로 감싸져 asyncHandler 내에서 실행되고, throw되는 에러는 자동으로 오류처리 미들웨어로 전달되도록 구성된다.

만약 async를 사용하지 않으면 request handler 안에서 제대로 throw를 잡지 않고, next(err) 오류처리 미들웨어로 전달하지 않으면 express app이 심각한 오류가 아닌데도 종료되거나 큰 문제가 발생할 수 있다. 따라서 항상 오류처리를 올바르게 해주는 것이 중요한데 오류처리를 편안하게 해줄 수 있는 방법이 async request handler이다.

 

🍒 Pagination

Pagination이란?

데이터가 많아지면 한 페이지의 목록에 모든 데이터를 표현하기 어렵다.

pagination은 데이터를 균일한 수로 나누어 페이지로 분리하는 것을 말한다.

Ex) 10개씩 나누어 1페이지에는 1~10번까지, 2페이지엔 11~20번까지 보여주기

router.get('/', asyncHandler(async (req, res) => {
  if (req.query.write) {
    res.render('post/edit');
    return;
  }
  // 쿼리에 값이 없는 경우 기본값을 선언하기 위해 ||(or)를 사용
  const page = Number(req.query.page || 1) // url 쿼리에서 page 받기, 기본값 1
  const perPage = Number(req.query.perPage || 10)// url 쿼리에서 perPage 받기, 기본값 10
// 특정 쿼리로 Document 의 개수를 확인하기 위해 countDocuments 함수를 이용
//   const total = await Post.countDocument({});// 전체 게시글 수 쿼리하기
// page와 perPage를 이용해 게시글 검색 쿼리를 작성
//   const posts = Post.find({})
//     .sort({ createdAt: -1 }) // sort를 이용해 최근 게시글 순으로 정렬
//     .skip(perPage * (page - 1)) // pagination을 위해 skip과 limit을 이용
//     .limit(perPage);
  // total, posts 를 Promise.all 을 사용해 동시에 호출하기
  const [total, posts] = await Promise.all([
      Post.countDocuments({}),
      Post.find({})
        .sort({ createdAt: -1 })
        .skip(perPage * (page - 1))
        .limit(perPage)
  ])
// total과 posts를 가져오는 동작은 비동기 동작이고 서로 연관이 없기 때문에 동시에 실행할 수 있다.
// Promise.all 을 이용해 두 동작을 병렬로 수행

  const totalPage = Math.ceil(total / perPage);
.sort({ createdAt: -1 })
// createdAt -> timestamp 옵션으로 생성됐던 데이터 생성 시간
// -1을 붙이면 역순으로 출력
// 즉, 데이터를 최근 순으로 정렬하겠다는 뜻1

.skip(perPage * (page - 1))
// perPage가 10이라고 했을 때 1page로 왔을 땐 10 * (1 - 1) skip = 0
// 0~9까지 출력
// perPage가 10이라고 했을 때 2page로 왔을 땐 10 * (2 - 1) skip = 10
// 10부터 19까지 출력
// 이런 식으로 10개씩 자르는데 앞에 몇 개를 생략할 것인가를 페이지로써 계산할 수 있게 만든 부분

const totalPage = Math.ceil(total / perPage);
// 전체 게시글 수를 perPage로 나눈 값
// 예를 들어 전체 게시글이 99개가 있고 perPage가 10개라고 하면 결과값은 9.9
// 9개의 글이 있고 마지막 하나의 글이 비더라도 총 페이지는 10개가 되어야 하기 때문에 Math.ceil 사용

✔️ page - 현재 페이지

✔️ perPage - 페이지 당 게시글 수

✔️ /posts?page=1&perPage=10  -> 일반적으로 url query를 사용, query는 문자열로 전달되기 때문에 Number로 형변환 필요

✔️ MongoDB의 limit과 skip을 사용하여 pagination 구현 가능

✔️ limit - 검색 결과 수 제한

✔️ skip - 검색 시 포함하지 않을 데이터 수

✔️ Mongoose를 이용해 Pagination을 구현하기 위해서는 한 페이지에 보일 자료의 개수를 limit으로 제한하고 특정 페이지로 넘어가기 위해 skip으로 자료를 건너뛴다.

✔️ 게시글 수 / 페이지 당 게시글 수 = 총 페이지 수

 

 

공유하기

facebook twitter kakaoTalk kakaostory naver band