[ NodeJS ] Pug - 템플릿 엔진

template engine

A template engine enables you to use static template files in your application. At runtime, the template engine replaces variables in a template file with actual values, and transforms the template into an HTML file sent to the client. This approach makes it easier to design an HTML page.

템플릿 엔진은 애플리케이션에서 정적 템플릿 파일을 사용할 수 있게 한다. 런타임환경에서 템플릿 엔진은 템플릿 파일의 변수에 값을 채우고 HTML 파일로 변환한 후에 클라이언트로 보낸다. 템플릿 엔진 사용시 HTML 페이지를 더욱 쉽게 디자인 할 수 있다. SSR을 할 때 사용한다.

  • 템플릿 엔진의 장점
    • HTML page를 쉽게 디자인 할 수 있음

pug

퍼그는 노드JS 환경에서 express와 함께 자주 쓰는 템플릿 엔진이다. 태그가 필요 없는 문법을 사용하기 때문에 정확하고 읽기 편한 템플릿들을 만들 수 있다.

  • pug의 특징
    • 간결한 문법
    • 템플릿 내에서 변수와 표현식 사용가능
    • mixins: 템플릿의 컴포넌트로서 재사용 가능
    • includes: 템플릿의 일부를 모듈화한 것.
    • filters:

pug 설정하기

템플릿들이 모여있는 폴더(views)로 경로를 설정하고 템플릿 엔진(pug)를 설정한다.

app.set("views", process.cwd() + "/views");
app.set("view engine", "pug");

pug 설치하기

npm i pug --save

views 디렉토리에서 index.pug를 생성한다.

html
  head
    title= title
  body
    h1= message

index.pug 파일을 렌더링할 수 있도록 라우트를 생성한다. 설정시 view engine 속성을 부여하지 않았다면 확장자까지 같이 써야한다.

app.get("/", (req, res) => {
    res.render("index", {title: "hey", message:"hello there"})
});

컴포넌트로 템플릿 생성하기

템플릿의 컴포넌트들을 모듈화하여 새로운 탬플릿을 생성할 수 있다.

partials

컴포넌트들을 보관하는 디렉토리다. partials 디렉토리 안에 footer.pug를 만들어보자.

footer © #{new Date().FullCurrentYear()} | Wetube

view로 사용할 템플릿인 home.pug를 만들어보자. home.pug에서 footer를 따로 구현하기 보다는 partials에서 footer를 include하자.

doctype html 
html(lang="ko")
    head 
        title Wetube 
    body 
        h1 Welcome Home!
    include partials/footer.pug

inheritance

기본 탬플릿을 토대로 새로운 탬플릿을 생성할 수 있다. base.pug를 만들고 다음과 같이 써보자.

base.pug

doctype html 
html(lang="ko")
    head 
        title #{pageTitle} | wetube
    body 
        block content
    include partials/footer.pug

템플릿 안에 includeblock이 들어 있는거 보인다. include는 재사용이 가능한 템플릿을 가져오는 키워드다. block은 base.pug를 사용할 템플릿이 채울 수 있는 공간이다. base.pug를 상속하는 home.pug를 만들어보자.

home.pug

extends base

block content 
    h1 Welcome Home!

home.pug는 extends 키워드를 통해 base를 상속한다. block content를 통해 내부에 들어갈 컴포넌트들을 정의한다. 즉, block은 특정 위치를 미리 정해주는 키워드고 상속받은 템플릿은 해당 위치에 필요한 컴포넌트들을 만들 수 있다.

템플릿 안에 변수 넣기

컨트롤러가 템플릿을 렌더링해야만 템플릿이 html 파일로 변환된다. 컨트롤러가 템플릿에 값을 전달해야하는 경우가 있다. 이때 탬플릿에는 #{} 문법을 사용하고 컨트롤러는 객체를 전달함으로써 값을 전달한다.

tempController.js

export const trending = (req, res) => res.render("home", { pageTitle: "Home" });

home.pug

doctype html 
html(lang="ko")
    head 
        title #{pageTitle} | wetube

home.pug는 렌더링되면서 컨트롤러부터 객체를 받아 값을 넣는다.

또 다른 방법으로는 컴포넌트 자체에 변수를 부여하는 방법이 있다.

doctype html 
html(lang="ko")
    head 
        title=pageTitle

css 적용하기

템플릿 엔진에도 css를 적용할 수 있다. mvp.css를 사용해보자. 홈페이지에 들어가서 cdn 태그를 가져 온 후에 링크의 속성값으로 넣자. 모든 탬플릿에 적용하기 위해 기본 템플릿인 base.pug에 설정한다.

doctype html 
html(lang="ko")
    head
        title #{pageTitle} | Wetube
        link(rel="stylesheet", href="https://unpkg.com/mvp.css")
    body 
        main
            block content
    include partials/footer.pug

조건문 적용하기

로그인 상태에 따라 홈페이지의 모습을 바꿀 수 있도록 템플릿을 수정 할 수 있다. 조건문을 통해 템플릿을 만들어보자.

base.pug

doctype html 
html(lang="ko")
    head
        title #{pageTitle} | Wetube
        link(rel="stylesheet", href="https://unpkg.com/mvp.css")
    body
        header 
            if fakeUser.loggedIn
                small Welcome #{fakeUser.name}
            nav 
                ul 
                    if fakeUser.loggedIn
                        li
                            a(href="/logout") Logout
                    else 
                        li
                            a(href="/login") Login
        main
            block content
    include partials/footer.pug

마찬가지로 템플릿이 값을 사용하기 위해서는 컨트롤러를 통해 객체를 전달해야한다.

controller.js

const fakeUser = {
    name: "Ben",
    loggedIn: true,
};

const trending = (req, res) =>
    res.render("home", { pageTitle: "Home", fakeUser });

반복문 적용하기

탬플릿에게 배열을 전달할 수 있다. each-else 구문을 사용한다. 이터러블 내부에 원소가 없는 경우에는 else문이 실행이 된다.

home.pug

extends base.pug

block content 
    h2 Welcome here you will see the trending videos

    ul 
        each video in videos 
            li=video 
        else 
            li Nothing is found

mixin 사용하기

mixin이란 값을 입력받을 수 있는 partials이다. pug의 관점에서 함수형 컴포넌트와 유사하다. 리액트의 컴포넌트와의 역할도 비슷한 것 같다. 자바스크립트를 통해 객체를 활용해서 데이터를 받고 각 위치의 변수에 값들을 받아서 로딩한다.

video.pug

mixin video(info)
    div 
        h4=info.title 
        ul 
            li Rating: #{info.rating}/5. 
            li #{info.comments} comments.
            li Posted #{info.createdAt}.
            li #{info.views} views

mixin을 사용하려면 다른 pug문서에서 include를 해야한다.

home.pug

extends base.pug
include mixins/video

block content 
    h2 Welcome here you will see the trending videos

    ul 
        each potato in videos 
            +video(potato)
        else 
            li Nothing is found

mixin을 사용할 때 앞에 +를 붙인다. 예제에서는 +video(인수) 의 형태로 사용했다.