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에 모든 프로세스를 한 번에 관리