html 렌더링, pug? partial, conditional, iteration,mixin
1.렌더링
렌더링은
이 부분이다. 그전에는 res.send()로 단순한 텍스트를 보내는 식으로 req를 마무리 해줬지만, 사실 res.render()로 html을 보낼 수 있다.
그래서 rendering이라고 하는 것 같다. 위 코드는 home.pug라는 view파일을 랜더링 한다는 의미이고 두번째 인자로 오는 중괄호는
home을 랜더링 할때 home으로 같이 보내는 변수다. pageTitle이라는 변수와 video:video를 보내고 있는 것이다. 아마 home.pug에서 활용할 것이다.
2.pug
지금까지 서버를 만들고 라우터와 컨트롤러까지 만들었다. 이제 실제로 브라우저에 뿌려줄 html을 만들어서 렌더링 시킬준비를 해야한다.
강의에서는 html을 편하게 쓰기 위해 pug를 이용한다.
pug는 html문서를 쉬운 문법으로 만들 수 있고, partial이나 conditinal, mixin 같은 기능을 제공한다.
일반 html보다 훨씬 할수있는게 많다. 검색해보니 현업에서는 많이 사용하지는 않는 것 같지만 어렵지도 않으니 한번 쭉 배워볼만 하다.
일단 ejs,pug같은 것들을 view engine이라고 한다. 우리는 서버에게 view engine으로 pug를 사용할 것이라고 알려줘야한다.
server.js 에 app.set("view engine", "pug")를 적어주면 된다.
단, pug를 찾을때 default로 process.cwd() + /views 에서 찾으니 혹시 pug파일이 들어가는 폴더를 다르게 만들었다면 세팅을 다시 해줘야한다. cwd는 current working directory의 약자로써 우리 서버가 시작하는 위치를 말한다. 우리 서버는 package.json파일에서 시작하고 있다. 만약 package.json보다 폴더 하나라도 더 들어가서 views폴더를 위치시키면 아마 못찾을거다. 그때는
app.set("views", process.cwd() + "/src")이런식으로 default로 찾는 위치를 변경시키면 된다.
특이한 점은 footer에 보면 #{} 이렇게 써주면 html인데도 불구하고 자바스크립트 문법을 넣어줄 수 있다.
3. partial
footer같은 부분은 모든 페이지에 들어갈것이다. 그렇다고 모든 페이지에 footer를 복붙한다면.. 변경이 생기는 경우 모든 페이지를 돌아다니며 수정을 해줘야 할것이다. 그리고 실수도 나오겠지? 그런 경우에 유용하게 쓸수있는게 partial이다.
위 이미지와 비교해보면 footer대신 include partials/footer.pug로 바뀌었다. footer.pug라는 파일을 만들고 partials라는 폴더 안에 넣어줬고, 그 파일 안에 기존 footer코드가 들어가 있다. 이제 include를 써서 partial을 붙여주면 footer파일 하나로 모든 페이지에 넣을 수 있다. 근데 하다보니 footer뿐만 아니라 html, head, body, title, main 같은 태그도 계속 반복된다. 그래서 상속의 개념이 필요하다. 위 기본 틀을 base.pug로 만들어주고 다른 home 이나 login 같은 view 파일에서 extends base를 해서 상속을 받아오면 된다.
watch 파일에서 base.pug를 상속받은 것이다. 즉, watch 파일은 아무것도 없지만 base.pug에서 볼수있는 html, head,body 등의 태그가 모두 달린 형태를 갖춘 html이 되는 것이다. 근데 페이지 수 만큼 base를 만들수도 없는 노릇이고? 상속받으면 각자 다른 코드는 어떻게 처리하느냐, 그래서 block이 필요하다. base에서 볼수있듯이 애초에 block content라는 공간을 만들었다. block은 통로? 포탈? 구멍? 그런 이미지로 생각하면 되는데, 아무래도 homepage 와 loginpage는 body에 들어갈 내용물이 다르다. 그러므로 base에 구멍을 내놓고 나중에 상속받은 파일에서 채우면 되는것이다. watch.pug에서 보듯이, block content 태그를 써주고 그 아래에 h1태그로 내용물을 넣었다. 아마 watch페이지에서는 base.pug의 틀에 Watch video! 라는 택스트를 가진 html이 뜰것이다.
4. conditional
또 특이한 것은 pug파일 안에서 조건문 비슷하게 쓸 수 있다. if elseif else같은것들.
예를들면 로그인한 유저에게는 logout이라는 버튼이 보여야하고 로그인을 안한 유저에게는 login이라는 버튼이 보여야 한다.
이런경우
if user.loggedIn
a(href="/logout") logout
else
a(href="/login") login
이렇게 써주면 pug가 찰떡같이 알아듣는다. 물론 controller에서 loggedIn이 true 인지 false인지 판단할 수 있는 데이터를 잘 보내줘야 한다.
5. iteration
만약 controller에서 변수를 받았는데 단순한 텍스트가 아니라 [] 배열이라면? 아니면 다양한 user데이터가 들어있는 리스트라면?
pug는 이 배열을 돌아가면서 전부 처리할 수 있다.
each video in videos
li=video
each video in videos 중에 뒤에있는 videos는 controller에서 받는 배열의 이름과 같다. 다르다면 undefined가 뜰것이다.
하지만 앞에있는 video는 상관없다. video는 videos 배열 안의 내용물을 말하는 것이기 때문에
each haha in videos
li=haha
이렇게 써도 videos의 내용이 잘 나올것이다. videos안에 있는 모든 haha 가 li로 출력될것이다.
6. mixins
mixin의 개념이 약간 헷갈리는데, css의 컴포넌트를 생각하면 비슷하다. partial 이긴 한데 데이터를 받아올 수 있는 partial이다.
더 자세히 알아보자면
두번째 이미지가 mixin파일이다. mixin video(video)라고 만들었는데, 앞에있는 video는 mixin의 이름이고 괄호안에 있는 두번째 video는 받아오는 변수의 이름이다. 즉
이렇게 써도 문제없다. 유튜브를 생각해보면 어딜가든 [영상, 제목, 유튜버이름, 조회수, 업로드날짜]가 하나로 묶여서 계속 반복되어 사용된다. home에도 저렇게, 비디오를 클릭해도 사이드바에 저렇게, 내 동영상에 들어가도 저렇게, 추천비디오에 들어가도 저렇게 항상 묶여서 반복된다. 우리는 그것을 계속해서 반복사용 할 수 있도록 mixin을 만든다. 그럼 partial이랑 똑같지 않아? 라는 생각이 드는데
mixin은 훌륭하게도 데이터를 받을 수 있다. 위 코드에서 보면 어떤 video를 받느냐에 따라 html의 내용물이 달라진다. 즉, partial이긴 한데 데이터를 받을 수 있는 똑똑한 partial이다.