Elice SW 2/TIL
DAY 32 - TIL
자이구
2022. 5. 20. 09:36
템플릿 엔진
- 서버에서 클라이언트로 보낼 HTML의 형태를 미리 템플릿으로 저장
- 동작 시에 미리 작성된 템플릿에 데이터를 넣어서 완성된 HTML 생성
- 템플릿 엔진은 템플릿 작성 문법과 작성된 템플릿을 HTML로 변환하는 기능을 제공
- SSR 구현 방식
EJS
- HTML과 유사한 문법의 템플릿 엔진
Mustache
- 간단한 데이터 치환 정도만 제공하는 경량화된 템플릿 엔진
Pug
- 들여쓰기 표현식을 이용한 간략한 표기와 레이아웃 등 강력한 기능을 제공
- 가독성이 좋고 개발 생산성이 높음
- HTML을 잘 모르더라도 문법적인 실수를 줄일 수 있음
- layout, include, mixin등 강력한 기능 제공
html
head
title= title
body
h1#greeting 안녕하세요
a.link(href="/") 홈으로
each item in arr
if item.name == 'new'
h1 New Document
else
h1= `${item.name}`
block
- block을 포함한 템플릿을 선언하면 해당 템플릿을 layout으로 사용
- layout을 extends 하면 block 부분에 작성한 HTML 태그가 포함됨
- 반복되는 웹 사이트의 틀을 작성해 두고 extend하며 개발하면 매우 편리한 기능
--- layout.pug ---
html
head
title= title
body
block content
--- main.pug ---
extends layout
block content
h1 Main Page
include
- 자주 반복되는 구문을 미리 작성해 두고 include하여 사용
- 텍스트 파일도 include하여 템플릿에 포함 가능
---title.pug---
h1= title
---main.pug
extend layout
block content
include title
div.content
안녕하세요
pre
include article.txt
mixin
- 템플릿을 함수처럼 사용할 수 있게 선언할 수 있음
- include는 값을 지정할 수 없지만 mixin은 파라미터를 지정하여 값을 넘겨받아 템플릿에 사용할 수 있음
--- listItem.pug ---
mixin listItem(title, name)
tr
td title
td name
--- main.pug ---
include listItem
table
tbody
listItem('제목', '이름')
app.locals
- Express.js의 app.locals를 사용하면 render 함수에 전달되지 않은 값이나 함수를 사용할 수 있음
- 템플릿에 전역으로 사용될 값을 지정하는 역할
--- app.js ---
app.locals.appName = "Express"
--- main.pug ---
h1= appName
// <h1>Express</h1>
게시판 CRUD 만들기
ObjectID
- MongoDB의 ObjectID는 URL에 사용하기 좋은 값이 아니기 때문에 대체할 수 있는 아이디를 shortId로 생성
- ObjectId를 대체할 shortId 타입을 Mongoose Custom Type으로 선언
- 중복 없는 문자열을 생성해 주는 nanoid 패키지 활용
- default를 이용해 모델 생성 시 자동으로 ObjectId를 대체할 아이디 생성
const { nanoid } = require('nanoid');
const shortId = {
type: String,
default: () => {
return nanoid();
},
require: true,
index: true,
}
module.exports = shortId;
Ascync Request Handler
- request handler에서 오류를 처리하기 위한 방법
- promise().catch(next)
- async function, try ~ catch, next
- async 비동기 처리는 편리하지만 매번 try - catch 구문을 작성하는 것이 귀찮고 실수하기 쉬움
- request handler를 async function으로 작성하면서 try - catch, next를 자동으로 구현하는 아이디어
const asyncHandler = (requestHandler) => {
return async (req, res, next) => {
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');
}
res.render('posts/list', { posts });
});
- asyncHandler는 requestHandler를 매개변수로 갖는 함수형 미들웨어
- 전달된 requestHandler는 try - catch로 감싸져 asyncHandler 내에서 실행
- throw되는 에러는 자동으로 오류처리 미들웨어로 전달됨
pagination
router.get(... => {
const page = Number(req.query.page || 1);
const perPage = Number(req.query.perPage || 10);
- page - 현재 체이지
- perPage - 페이지 당 게시글 수
- 일발전으로 url query를 사용해 전달됨으로 문자열로 전달되기 때문에 Number로 형변환 필요
router.get(... => {
...
const total = await Post.countDocument({});
const posts = await Post.find({})
.sort({ createdAt: -1 })
.skip(perPage * (page - 1))
.limit(perPage);
const totalPage = Math.ceil(total / perPage);
- limit - 검색 결과 수 제한
- skip - 검색 시 포함하지 않을 데이터 수 (맨 앞 페이지부터 현재 페이지 전까지의 게시물의 수 )
- pagination 시에는 데이터의 순서가 유지될 수 있도록 sort를 사용할 수 있도록 함
- total page - 게시글 수 / 페이지 당 게시글 수
PM2
- Node.js 작업을 관리해주는 Process Manager
- node 명령어로 실행 시 오류 발생이나 실행 상태 관리를 할 수 없음
- pm2는 작업 관리를 위한 다양한 유용한 기능을 제공
- 안정적인 프로세스 실행 - 오류발생 시 자동 재실행
- 빠른 개발환경 - 소스 코드 변경 시 자동 재실행
- 배포 시 편리한 관리 - pm2에 모든 프로세스를 한 번에 관리