Node JS #5
Way to Return HTML
라우터에 대한 컨트롤러로 HTML을 리턴하는 방법은 다음과 같다.
globalRouter.get("/", (req, res) => {
res.send("<h1>this is home</h1>");
});
만일 HTML의 크기가 커진다면 이 방법은 매우 구리다.
res.send("<head><title>Hi</title></head><body><h1>this is home</h1></body>"); // 이렇게 써야 한다.
따라서 우리는 새로운 방법을 찾아야 한다.
PUG
PUG는 템플린 엔진이다.
HTML을 어썸하게 가지고 놀 수 있게 해준다.
템플릿 : 틀을 만들어놓고 데이터가 들어갈 공간을 주면 데이터가 알아서 그 틀에 맞게 들어가 완성되는 것
PUG overview
The general rendering process of Pug is simple.
pug.compile()
will compile the Pug source code into a JavaScript function that takes a data object (called “
locals`”) as an argument. Call that resultant function with your data, and voilà!, it will return a string of HTML rendered with your data.The compiled function can be re-used, and called with different sets of data.
Set up
- pug를 설치한다.
$ npm install pug
- express에게 지금부터 뷰 엔진을 pug로 쓸 것이라 알리고, pug 파일의 경로를 설정한다.
//app.js
import express from "express";
const app = express();
app.set("view engine","pug"); // view 엔진으로 pug 설정
app.set("views", process.cwd() + "/src/views"); // view 파일들의 경로 설정 (기본 값 : process.cwd() + '/views')
process.cwd() : 서버를 가동하는 파일의 위치에 따라 결정된다.
일반적으로는 app.js이 있는 위치가 된다.
따라서 우리가 view들을 저장할 공간을 따로 만들어 준다면 그에 맞게 설정해주어야 했다.
참고로 파일명에는 소문자를 쓰고 띄어쓰기는 쓰지 않는 것이 좋다.
How it works
pugfile은 pug에 의해서 JS로 컴파일되고 이것이 일반 HTML로 렌더링된다.
// base.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Document
body
h1 hello
footer © this is footer
이렇게 쉬운 HTML을 쓸 수 있게 해주고, 템플릿을 받아서 모든 것을 체크하여 JS코드로 실행, 유저에게 보여준다.(렌더링)
위 사진처럼 유저는 순수한 HTML 파일만을 제공받는다.
res.render("VIEW"); // VIEW를 랜더링한다.
// 예시
globalRouter.get("/", (req, res) => {
res.render("base");
});
Partial -> include
일반적으로 웹사이트에서는 반복되는 부분이 매우 많다.
특히 상단 부분과 하단의 footer부분은 반복이 빈번한데, 이를 복붙하고 변경이 일어날 때마다 하나하나 뒤져가며 수정해주는 것은 개발자스럽지 못하다.
따라서 우리는 PUG가 지원하는 partial을 이용할 것이다.
Partial Includes allow you to insert the contents of one Pug file into another.
먼저 partial 파일을 만들자.
//partials/footer.pug
footer © this is footer
그 후 이것을 include 하면 끝!
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Document
body
h1 hello
include partials/footer
위 include 부분에 footer 파일이 삽입된다.
이렇듯 partial은 복붙말고 include로 완전히 동일한 부분을 쉽게 재사용할 수 있게 한다.
Inheritance -> extends
PUG는 또한 HTML에서 상속 또한 지원한다.
Pug supports template inheritance. Template inheritance works via the
block
andextends
keywords.In a template, a
block
is simply a “block” of Pug that a child template may replace. This process is recursive.Pug blocks can provide default content, if appropriate. Providing default content is purely optional, though.
우리는 base.pug 파일을 베이스로 만들어, 이를 상속(extends)해서 다른 파일들을 만들어보자.
//base.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Document
body
block title
h1 I am default_title
include partials/footer
Block
Block은 상속받는 애들이 자신이 값을 채워넣을 수 있는 공간이다.
Block can be filled other files that inheriated.
In other words, block is the window allows you put content inside of template that you extend from - Nico
//home.pug
extends base
block title
h1 I am home
이렇게 작성하면 PUG에 의해 base.pug 템플릿을 사용하며, title block에는 설정한 h1태그가 들어간다.
Variable
변수를 부모 자식간에도 주고 받을 수 있다.
먼저, pug 파일에서 변수를 사용하기 위해서는 #{변수이름} 처럼 사용하면 된다.
//home.pug
extends base
block title
h1 this is home
h3 #{pageTitle}
그리고 위 뷰 파일을 렌더링 해줄때 함수를 JSON 형식으로 넘기면 된다.
res.render("뷰 파일 이름",{넘겨줄 변수들});
globalRouter.get("/", (req, res) => {
res.render("home", {
pageTitle: "value of pageTitle is home",
});
});
참고로 pug파일에서 아래 두 코드는 같다.
1) h1=pageTitle;
2) h1 #{pageTitle} // 1)과 2)는 정확히 같은 코드
x) h1 pageTitle // 이건 그냥 text pageTitle을 뜻함
1)과 2)를 비교했을때 1)이 편하지만, 다른 문자열과 변수를 함께 쓸 수는 없어 이 경우에는 2)를 사용해야한다.
Condition
PUG에서는 HTML에도 JS 변수를 쓸 수 있고, 심지어 조건문도 쓸 수 있다.
// home.pug 파일을 user 객체와 함께 렌더링
globalRouter.get("/", (req, res) => {
res.render("home", {
user: {
name: "KDH",
userID: 1,
},
});
});
// home.pug가 상속받는 base.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Document
header
if user
small Hello #{user.name}
nav
ul
li
if user
a(href="/logout") Log out
else
a(href="/login") Login
body
block title
h1 this is default title
include partials/footer
위 파일은 user가 있으면 환영 문구와 로그아웃 버튼을 나타내고
user가 없다면 로그인 버튼을 나타낸다.
Iterations
PUG는 반복문 또한 지원한다.
home.pug를 배열과 함께 렌더링하자.
globalRouter.get("/", (req, res) => {
const numList = [1, 2, 3, 4, 5, 6, 7];
res.render("home", { list: numList });
});
//home.pug가 상속받는 base.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Document
body
each item in list
h4=item
else
h4 there is no data.
block title
h1 this is default title
include partials/footer
each-in 구문으로 배열의 값을 하나 하나 꺼내올 수 있고, 배열이 비었다면 else 구문이 실행되어 데이터가 없다는 것을 나타낸다.
참고로 each-in과 이어지는 else는 JS문법이 아닌, PUG가 그냥 섹시하게 제공해주는 문법이다.
유저 리스트를 넘겨준다고 하자.
globalRouter.get("/", (req, res) => {
const userList = [
{ userID: 1, name: "KDH" },
{ userID: 2, name: "HKD" },
{ userID: 3, name: "LCS" },
];
res.render("home", { list: userList });
});
그러면 이 리스트를 보여주기 위해 반복문을 사용하여 아래와 같이 작성하면 된다.
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Document
body
each item in list
h4 userID #{item.userID}
h4 userName #{item.name}
else
h4 there is no data.
block title
h1 this is default title
include partials/footer
그러나, 유저 리스트를 보여주고자 하는 화면이 많다면,
each item in list
h4 userID #{item.userID}
h4 userName #{item.name}
else
h4 there is no data.
이 부분은 계속해서 반복될 것이고, 그때마다 복붙하는 것은 개발자에게 끔찍한 일이다.
따라서 우리는 컴포넌트처럼 HTML을 다룰 수 있어야 한다.
Mixins
Mixins은 복붙만 가능한 partial와 다르게 데이터를 알맞게 가져와 채울 수 있는 템플릿이다.
‘mixin’은 소프트웨어 개발에서 자주 사용되는 용어로, 객체 지향 프로그래밍에서 다른 클래스에 특정 기능을 추가하기 위해 사용되는 코드의 재사용 기법을 가리킵니다.
이는 코드를 모듈화하고 재사용성을 높이는 데 도움이 됩니다.
‘mixin’은 클래스에 직접적으로 상속되는 것이 아니라, 클래스의 인스턴스가 사용할 수 있는 메소드나 속성을 제공하는 클래스입니다.
이를 통해 다중 상속의 문제를 피하면서도 코드를 확장할 수 있습니다. JavaScript, Ruby, Python 등의 언어에서 널리 사용됩니다.
src/mixins 폴더에 mixin 파일을 만들자.
//src/mixins user.pug 파일
mixin user(info)
div
h4 userID #{info.userID}
h4 userName #{info.name}
베이스 파일은 아래와 같다.
//base.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Document
body
block title
h1 this is default title
block content
include partials/footer
그리고 home.pug에서는 정의된 mixin을 사용하기 위해
- include
- +연산자로 mixin호출
하면 된다.
extends base
include mixins/user
block title
h1 this is home
h3 #{pageTitle}
block content
h2 this is userList!
each item in list
+user(item)
else
h4 data isn't founded.
쉽게 말해 mixin은 HTML을 리턴하는 함수이다.
ETC
MVP.CSS
MVP란 “Minimum Viable Product”의 약어로, 제품 개발과 관련된 용어입니다.
이는 제품이 출시될 때 필요한 최소한의 기능을 갖춘 초기 버전을 말합니다.
MVP는 초기 아이디어나 제품 컨셉을 시험해보고, 사용자의 피드백을 수집하여 제품을 발전시키는 데 사용됩니다.
이는 시장에 빠르게 진입하고 비용을 절감하며, 사용자의 Bedminster 권장을 받을 수 있는 방법 중 하나입니다.
이러한 MVP를 만들때 CSS도 정성들여 만들기엔 시간이 부족하다.
따라서 기본적인 MVP의 CSS를 다른 곳에서 가져와서 사용하자.
사용법은 아래 코드를 헤더에 갖다놓으면 된다.
<link rel="stylesheet" href="https://unpkg.com/mvp.css">
ES6
ES6에서 속성값과 변수값이 같을때 이름을 한번만 써주어도 된다.
const user={
name:"KDH",
userID: 1,
}
1) res.render("home",{user:user});
2) res.render("home",{user});
// 1)과 2)는 동일
Summary
PUG는 HTML 재사용성을 높여주는 템플릿을 제공하는 템플릿 엔진이다.
PUG는 PUG파일을 컴파일하여 렌더링하며 다양한 기능을 지원한다.
-
컴포넌트화
- partial : 완전한 복붙, 해당 위치에 include하여 사용
- mixin : 데이터를 받아서 가공 가능, include후 +연산자로 사용
-
상속
부모의 형식을 따를 수 있음, extends로 사용
block을 사용해 자식이 데이터를 채워넣을 공간을 만들고 variable을 사용할 수 있음
또한 PUG는 HTML에서 반복문과 조건문을 사용할 수 있게 함으로써 우리를 복붙 지옥에서 구원해주었다.
Leave a comment