Pug는 템플릿 언어로 express의 view engine이다. Pug는 MVC 의 View를 다룬다.
express로 HTML을 보여주는 엔진 으로. res.send 대신 res.render를 통해서 실제 html을 전달 해준다.pug가 p hello
코드를 html의 <p>HELLO</p>
코드로 수정해준다.
$ npm install pug
express.js 의 API 가이드에 따라서 set 함수를 통해서 설정을 변경 할 수 있다.view engine설정을 undefined(기본값)에서 pug로 변경 해준다.
-> pug 를 view engined으로 사용하도록 변경 한다.
//app.js
const app = express();
app.set("view engine","pug") //view 엔진을 pug 확장자로 정해준다.
app.use(cookieParser());
app.use(bodyParser.json());
express에는 html파일을 저장해야 하는 폴더의 기본값은 프로젝트의 작업 디렉토리의 '/views' 이다.이 설정을 바꾸고 싶다면set 함수를 통해서 views의 설정을 바꿀 수 있다.우리는 기본 설정을 이용하므로 views 폴더를 만들고 home.pug 파일을 만든다. 이 파일은 wetube의 home에서 보이는 화면이된다.
home.pug 파일을 웹 사이트에 보여주려면 controller에서 res.send 대신 res.render를 사용한다.home.pug 파일을 렌더링해서 화면에 보여주는 역할을 한다.
//videoController.js
//export const home=(req, res) => res.send("HOME");
export const home = (req, res) => res.render("home")
views폴더에서 파일명이 home이고 확장자가 pug인 템플릿 파일을 찾은 후에 보여준다.
HTML과 CSS만으로 작업을 하다보면 똑같은 코드를 반복하는 경우가 많아서 효율적이지 않다.예를 들어 모든 페이지의 기본(header, footer,HTML head 태그, CSS link)를 필요로 하는 작업이 있다.우리는 계속 복사-붙여넣기보다 더 효율적인 작업을 위해서 pug를 사용한다.
pug의 작동 방식은 HTML 의 태그가 아닌 들여쓰기이다 .
모든 페이지의 기본 적인 요소들을 layout을 만들어 놓고 덮어 쓰는 방식으로 효율 적으로 사용 할 수있다.
// views/layouts/main.pug
doctype html
html
head
title WeTube
body
header
h1 WeTube
main
block content
footer
span © WeTube
만약 header 부분에 변화를 주고싶다면 모든 pug 파일을 수정 하는게 아닌 main.pug 파일의 header 부분을 바꿔주면 된다.
다른 pug 파일에서는 이 layout을 이용해서 덮어쓰는 것으로 각 페이지를 수정 할 수있다.
layout을 살펴보면 docype은 html로 설정
head 안에 title ,body 안에 header main footer 가 있고,main의 block content에 화면의 내용들이 들어간다.
// /views/home.pug
extends layouts/main
block content
p Home page
home.pug 에서 main layout 파일을 extstion을 해준다.
extends layouts/main
main 레이아웃을 확장해서 사용(덮어씀) 하겠다는 말.main layout 을 덮어 쓰는 부분이 block content ....
부분!
partials는 페이지의 일부분이다.조직적인 목적으로 만든다.
views 폴더 안에 partials폴더를 만들고footer.pug와 header.pug를 만들어 준다.
//views/partials/footer.pug
footer.footer
.footer_icon
span.footer_text #{siteName} #{new Date().getFullYear()} ©
pug 에서 js 코드를 사용 할때는 #{}여기 안에.
doctype html
html
head
title | #{siteName}
body
include ../partials/header
main
block content
include ../partials/footer
main.pug의 footer 부분을 지우고,include 태그를 이용해서 footer.pug, header.pug 와 연결 해준다.
조직적인 방식으로 컴포넌트를 분리하는 방식이다.웹 사이트의 분리하고 싶은 부분을 분리 할 수 있다.footer와 header는 각각 한 곳에 모아 둘 수있다.
One single source of truth(한 곳에서만 정보를 보관).
더 나은 코드를 만들어 주는 원칙.이러한 습관은 버그를 최소화 할 수 있다.왜냐하면 많은 곳에 영향을 주는 하나를 바꾼다면 그 하나만으로 많은 것들이 바뀌기 때문이다.
controller에 있는 정보를 템플릿에 추가 해보자.한 템플릿에 추가하거나 전체 템플릿에 추가 할 수있는 경우가 있다.
템플릿 전체에 추가하는 방법으로는 header가 routes객체에 접근할 수 있도록 middleware를 사용한다. middleware는 레이어와 같이 위에서 밑으로 한단계씩 내려가면서 실행되기 때문에 순서가 중요하다.
//app.js
//middleware
....
import { localsMiddleware } from "./middlewares";
app.use(bodyParser.urlencoded({extended : true})); //form
app.use(morgan("dev"));
app.use(localsMiddleware)
app.use(routes.home, globalRouter);
....
local 변수를 global변수로 사용하도록 만들기 위해서 local 변수에 접근하기 위한 localsMiddleware를 사용한다.
한 기능만 하게 코드가 짜여야 하기 때문에 middleawares.js 파일에 추가 해준다.파일에 locals를 추가한다. locals가 추가되면 이제 그것들을 템플릿,컨트롤러 등 어디에서든 쓸 수 있다.
express가이드의 locals 를 보면 'locals는 로컬 변수 응답을 포함하는 객체입니다... 이 프로퍼티를 유용한 정보를 내보내는 데에 유용합니다."
//middleware.js
import routes from "./routes";
export const localsMiddleware = (req, res, next) =>{
res.locals.siteName="WeTube";
res.locals.routes = routes;
next()
//middleware가 커넥션과 라우트들 사이에 있으므로 next에 req를 전달,다음 라우터로 전달
};
//locals에 있는 건 템플릿에서 변수명 처럼 존재
//main.pug
html
head
link
title #{siteName}
export const localsMiddleware = (Req, res, next) =>{
res.local.routes = routes;
};
다른locals도 추가routes에 routes.js 객체를 추가.
partial/header에서 #대신 routes. 이 가능
//header.pug
header.haeder
.header_column
a(href=routes.home)
i.fab.fa-youtube
.header_column
ul
li
a(href=routes.join) Join
li
a(href=routes.login) LogIn
템플릿 마다 다른 정보를 가질 경우를 위해서 한 템플릿에만 변수를 추가 해줄수도 있어야 한다.어떤 템플릿에는 비디오 , 어떤 템플릿에만 유저 정보 이렇게 다를 경우를 위해서!
pageTitme 을 추가해서 한 템플릿에서 사용할 수 있도록 한다.
//main.pug
doctype html
html
head
link(rel="stylesheet", href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU", crossorigin="anonymous")
title #{pageTitle} | #{siteName}
body
include ../partials/header
main
block content
include ../partials/footer
videoController에서 한 화면에만 변수를 추가.res.render("home",{pageTitle:"Home"});
render 함수의 첫번째 인자는 템플릿(화면)이고,두번째 인자는 템플릿에 추가할 정보가 담긴 객체이다. pageTitle 이 home 템플릿으로 전달되고, home 템플릿은 layouts/main 을 extend하고 있기때문에 main 화면의 pug 코드가 home템플릿에도 적용이 된다.
변수를 템플릿에 전달하는 방식
//videoController.js
export const home = (req, res) => res.render("home",pageTitle:"Home"});
export const search = (req,res) => res.render("search",pageTitle:"search"});
export const upload =(req,res) =>res.render("Upload",{pageTitle: "Upload"});
export const videoDetail =(req,res) =>res.render("Video Detail",{pageTitle:"Video Detail"});
export const editVideo =(req,res) =>res.render("Edit Video",{pageTitle: "Edit Video"});
export const deleteVideo =(req,res) =>res.render("Delete Video",{pageTitle: "Delete Video"});
videoController를 통해서 한 템플릿의 pageTitle에 값을 넘겨줘서 화면에 보여주는걸 해봄. 다음강의에서는 화면에서 보여주는것 말고도 다른 것들을 배운다!