ν νλ¦Ώ νμ₯ - extends / block
ν νλ¦Ώμ λ³μ μ λ¬νκΈ° - #{λ³μ} / =λ³μ / res.render()
쑰건문 / each 문 / mixins
μ΄μ 곡λΆμμ μ΄μ΄μ
pug ν
νλ¦Ώ μμ§ λ°°μ°λ μ€
μΌλ¨ μμ μ μ edit.pug νμΌλ μΆκ°ν ν res.render("edit")κΉμ§ ν μν
μμ includeλ₯Ό μ΄μ©ν΄ pug νμΌμ λ§λ€μμ§λ§ μ¬μ ν λ°λ³΅λλ λΆλΆμ΄ μλ€.
home.pugμ see.pug νμΌμ μλΉ λΆλΆμ΄ λ°λ³΅λλ€.
μ΄λ₯Ό κ°μ νκΈ° μν΄ μμ λ° νμ₯
μ μ¬μ©ν μ μλ€.
λ² μ΄μ€κ° λ νμΌλ‘ base.pugλ₯Ό λ§λ λ€.
doctype html
html(lang="ko")
head
title Wetube
body
h1 Welcome to Wetube
include partials/footer.pug
λ€λ₯Έ νμΌλ€(home.pug, see.pug, edit.pug)μ base.pug νμΌμ νμ₯(extends)ν΄ λ§λ λ€.
extends base.pug
μ΄μ λͺ¨λ νμΌλ€μ base.pug νμΌμ μμνλ€.
κ·Έλ¬λ, μ΄λ κ²λ§ νλ©΄ λͺ¨λ νμΌμ΄ κ°μ λ΄μ©μ κ°μ§κ² λλ€.
νμΌλ§λ€ λ€λ₯΄κ² νμλ λΆλΆμ μ±μλ£λ λ°©λ²μ΄ νμνλ€.
cf. pug μμμ extends νΉμ include μ¬μ©μ .pugλ μλ΅ν΄λ λλ€.
μΌμ’ μ μ°½λ¬Έ κ°μ κ²μΌλ‘ μ΄ μμ μλ‘ λ€λ₯Έ λ΄μ©μ μ±μλ£μ μ μλ€.
π‘ base.pug νμΌμ block λ§λ€κΈ°
doctype html
html(lang="ko")
head
block head
body
block content
include partials/footer.pug
base.pug νμΌμ headμ contentλΌλ blockμ μν 곡κ°μ΄ λ§λ ¨λμλ€.
π‘ base.pug νμΌμ μμν νμΌμ blockμ λ΄μ© μ±μλ£κΈ°
extends base.pug
block head
title Home | Wetube
block content
h1 Home
extends base.pug
block head
title See | Wetube
block content
h1 See Video
extends base.pug
block head
title Edit | Wetube
block content
h1 Edit Video
μ΄μ κ°κ°μ νμΌλ€μ base.pug νμΌμ μμνλ©΄μλ κ°μ λ€λ₯Έ λΆλΆλ€μ κ°μ§λ€.
κ·Έλ¬λ, μ¬μ ν title νκ·Έμ | wetube ν
μ€νΈκ° λ°λ³΅λκ³ μμ΄ κ°μ μ΄ νμνλ€.
μμ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ ~pug νμΌμ block head λΆλΆμ λͺ¨λ μμ ν ν base.pug νμΌμ μλμ κ°μ΄ μμ νλ€.
doctype html
html(lang="ko")
head
title #{pageTitle} | Wetube
body
block content
include partials/footer.pug
λ°°μ΄λλ‘λΌλ©΄ #{ } μμλ μλ°μ€ν¬λ¦½νΈ μ½λκ° μμΌ νλ€.
κ·Έλ¬λ pageTitleμ κ·Έ μμ²΄λ‘ κ°μ κ°μ§λ μ½λκ° μλ λ³μμ΄κΈ° λλ¬Έμ ν
νλ¦Ώμ ν΄λΉ λ³μμ κ°μ 보λ΄μ€μΌ νλ€.
{ν
νλ¦Ώμ λ³΄λΌ λ³μλ€}
)λ λλ§μ νλ κ²μ controller ν¨μμ΄λ―λ‘ controller ν¨μ
μ ν
νλ¦ΏμΌλ‘ 보λ΄κ³ μΆμ λͺ¨λ λ³μλ₯Ό μΆκ°νλ€.
μ°μ , videoController.js νμΌμ trending controllerλ₯Ό μμ ν΄λ³΄μ.
export const trending = (req, res) => res.render("home", { pageTitle: "Home" });
μ΄μ localhost:4000 μΌλ‘ λ€μ΄κ°λ©΄ titleλμ Home | Wetube λΌκ³ λ¬λ€.
λ°±μλλ‘λΆν° λ³μμ κ°μ λ°μμμ νλ‘ νΈμλμμ λλλ§ν κ²μ΄λ€.
μ΄λ²μλ ν νλ¦Ώμμ 쑰건문μ μ¬μ©νλ λ°©λ²μ λ°°μλ³΄κ³ μ νλ€.
λ€μ΄κ°κΈ° μ μ μ κΉ, κ°λ¨νκ² CSSλ₯Ό μ νκ³ κ°μ.
π‘ MVP.css
MVPλ HTML νκ·Έμ λͺ κ°μ§ κΈ°λ³Έ μ€νμΌμ μ νμ£Όλ λ―Έλλ©λ¦¬μ€νΈ μ€νμΌμνΈλ₯Ό λ§νλ€.
base.pug
doctype html html(lang="ko") head title #{pageTitle} | Wetube link(rel="stylesheet" href="https://unpkg.com/mvp.css") <!-- MVP.css μ μ© --> body main <!-- κ°μ΄λ° μ λ ¬ --> block content include partials/footer.pug
home.pug
extends base.pug block content h1 Home input(placeholder="What's your name?") <!-- μμλ‘ μΆκ°ν κ² --> button send <!-- γ -->
μμ νκ·Έμ λ³μ κ°μ λ£λ λ°©λ²μΌλ‘ #{λ³μ}λ₯Ό λ°°μ λ€.
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
κ·Έλ¬λ, νκ·Έμ νλμ λ³μ κ°λ§ κ²½μ°λΌλ©΄ =λ³μ λΌκ³ μΈ μλ μλ€.
doctype html
html(lang="ko")
head
title #{pageTitle} | Wetube
link(rel="stylesheet" href="https://unpkg.com/mvp.css")
body
header
h1=pageTitle <!-- μΆκ° -->
main
block content
include partials/footer.pug
home.pug νμΌμ headerμ navλ₯Ό μΆκ°ν΄ loginκ³Ό log out λ§ν¬λ₯Ό λ§λ λ€.
userκ° λ‘κ·ΈμΈ μνλΌλ©΄ log out λ§ν¬λ₯Ό, λ‘κ·Έμμ μνλΌλ©΄ login λ§ν¬λ₯Ό 보μ¬μ€μΌ νλ€.
μ΄λ₯Ό μν΄ μ‘°κ±΄λ¬Έμ μ¬μ©ν μ μλ€.
μ°μ , μμ λ₯Ό μν΄ κ°μ§ μ μ λ₯Ό λ§λ€μ΄μΌ νλ€.
/(Home)μ λ€μ΄κ° μ μ€νλλ trending controller ν¨μκ° μλ videoController.js νμΌμ κ°μ§ μ μ κ°μ²΄λ₯Ό λ§λ ν μ΄λ₯Ό home.pug νμΌμ 보λΈλ€.
videoController.js
const fakeUser = {
username: "Syong",
loggedIn: "false" // λ‘κ·Έμμ μν
}
export const trending = (req, res) => res.render("Home", { pageTitle: "Home", fakeUser: fakeuser });
// κ·Έλ₯ fakeUserμ΄λΌκ³ λ§ μ¨λ λ¨
base.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.username
small Hello #{fakeUser.username}
nav
ul
if fakeUser.loggedIn
li
a(href="/users/logout") Log out
else
li
a(href="/login") Login
h1=pageTitle
main
block content
include partials/footer.pug
μ΄μ μ€μ ν 쑰건μ λ§κ² λ§ν¬κ° 보μ΄κ² λλ€.
μμ λ₯Ό μν μ½λμμΌλ―λ‘ κ΄λ ¨ μ½λλ₯Ό λͺ¨λ μ§μ쀬λ€.
pug - Iteration μ°Έκ³
μμμλ λ¬Έμμ΄μ κ°μΌλ‘ κ°μ§λ λ³μλ₯Ό HTMLλ‘ μ λ¬νλ λ°©λ²μ λ°°μ λ€.
κ·Έλ λ€λ©΄ λ¬Έμμ΄ λμ λ°°μ΄
μ μ λ¬νλ €λ©΄ μ΄λ»κ² ν΄μΌ ν κΉ?
μ΄ λ¬Έμ μ λ΅νλ €λ©΄ Iterationμ λν΄ λ°°μμΌ νλ€
iteration
λ κΈ°λ³Έμ μΌλ‘ listμ λͺ¨λ elementsλ₯Ό HTMLμ 보μ¬μ€λ€.
μ°μ , μμ λ₯Ό μν΄ κ°μ§ λΉλμ€ λ°°μ΄μ λ§λ€μ΄μΌ νλ€.
/(Home)μ λ€μ΄κ° μ μ€νλλ trending controller ν¨μκ° μλ videoController.js νμΌμ κ°μ§ λΉλμ€ λ°°μ΄μ λ§λ ν μ΄λ₯Ό home.pug νμΌμ 보λΈλ€.
videoController.js
export const trending = (req, res) => {
const videos = [1, 2, 3, 4, 5, 6, 7, 8];
res.render("Home", { pageTitle: "Home", videos });
}
home.pug νμΌμ λ°°μ΄μ κ°μΌλ‘ κ°μ§λ λ³μλ₯Ό λ§λ λ€. (each ~ in ~)
pugλ λ°°μ΄μ κ°μ΄ μλμ§ μλμ§ μ²΄ν¬ν νμ μλ€λ©΄ λ°°μ΄μ κ° μμλ€μ 보μ¬μ£Όκ³ , μλ€λ©΄ λ°λ‘ μ€μ ν λ΄μ©μ 보μ¬μ€λ€. (else ~)
home.pug
extends base.pug
block content
h1 Welcome here you will see the trending videos
ul
each video in videos
li=video
else
li sorry nothing found
π‘ κ°μ²΄λ₯Ό iterate ν κ²½μ°
videoController.js
export const trending = (req, res) => { const videos = [ // μμ { title: "a" }, { title: "b" }, { title: "c" } ]; return res.render("Home", { pageTitle: "Home", videos }); }
home.pug
extends base.pug block content h1 Welcome here you will see the trending videos ul each video in videos li=video.title <!-- μμ --> else li sorry nothing found
π‘ λ§μ½ Cannot read property 'length' of undefined λΌλ μλ¬κ° λμ¨λ€λ©΄, each x in y μμ yκ° undefined λΌλ λ»μ΄λ€.
π partialsμ mixinμ μ°¨μ΄μ
μ μ λ§λ€μλ footer.pug νμΌμ HTMLμ ν μ‘°κ°μΌλ‘μ λ°μ΄ν°λ₯Ό λ°μ§λ λͺ»νλ partialμ΄λ€.
λκ°μ μ½λλ₯Ό λ°λ³΅νμ§ μκΈ° μν΄ λ§λ κ²μΌλ‘ νμ΄μ§κ° λ°λμ΄λ λ΄μ©μ λ°λμ§ μλλ€.
λ°λ©΄μ, Mixinsλ λ°μ΄ν°λ₯Ό λ°μ μ μλ
partialμ΄λ€.
μ¦, ννλ κ°μ§λ§ μλ‘ λ€λ₯Έ λ°μ΄ν°κ° λ°λ³΅ν΄μ λ±μ₯νλ HTML λΈλ‘μ λ»νλ€.
π component
videoController.js
export const trending = (req, res) => {
const videos = [
{
title: "First Video",
rating: 5,
comments: 2,
createdAt: "2 months ago",
views: 59,
id: 1,
},
{
title: "Second Video",
rating: 5,
comments: 2,
createdAt: "2 months ago",
views: 59,
id: 1,
},
{
title: "Third Video",
rating: 5,
comments: 2,
createdAt: "2 months ago",
views: 59,
id: 1,
},
];
return res.render("home", { pageTitle: "Home", videos });
};
home.pug
extends base.pug
block content
h1 Welcome here you will see the trending videos
each video in videos
div
h4=video.title
ul
li #{video.rating}/5.
li #{video.comments} comments.
li Posted #{video.createdAt}.
li #{video.views} views.
else
li sorry nothing found
μ΄λ₯Ό μ΄λ κ³³μμλ μ¬μ¬μ© κ°λ₯ν component
λΌκ³ νλ€.
μλ₯Ό λ€μ΄, μ νλΈμ λ€μ΄κ°λ©΄ νν λ³Ό μ μλ μΈλ€μΌ, μ λͺ©, μ‘°νμ λ±μ video blockμ΄ μ΄μ ν΄λΉνλ€. μ§μ μμμ λ³Ό λλ 보μ΄κ³ μΆμ² μμλμλ 보μΈλ€. κ·Έ μΈ μ°κ΄ λμμμ΄λ λ€λ₯Έ μ¬λμ νλ‘νμ λλ¬ λ¬ μμμλ μ΄μ λκ°μ κ²λ€μ 보μ¬μ€μΌ νλ€.
μ΄μ²λΌ ννλ κ°μ§λ§ λ°μ΄ν°λ μλ‘ λ€λ₯Έ HTML λΈλ‘
μ μ¬λ¬ νμ΄μ§μμ 보μ¬μ£Όκ³ μΆμ λ, UI componentλ₯Ό μ΄μ©ν μ μλ€. 볡λΆμ μ΅μννλ©΄μ λκ°μ ννλ₯Ό μ¬μ©νλ €λ κ²μ΄λ€.
π₯ Mixin λ§λ€κΈ° π₯
views ν΄λ μμ mixins ν΄λλ₯Ό λ§λ ν, κ·Έ μμ video.pug νμΌμ μΆκ°νλ€.
video.pug
mixin video(info)
div
h4=info.title
ul
li #{info.rating}/5.
li #{info.comments} comments.
li Posted #{info.createdAt}.
li #{info.views} views.
μ¬κΈ°μ videoλ mixinμ μ΄λ¦μ΄λ€
mixin video
λ info κ°μ²΄λ₯Ό λ°λλ€. ( μμμλ videoλ‘ μ μμ§λ§ videoκ° λ무 λ°λ³΅λΌμ infoλ‘ κ³ μΉ¨ )
info
λ mixin videoκ° λ°κ² λ λ°μ΄ν°λ₯Ό μ μ₯νλ€.
divλΆν° μμλλ μ½λλ, infoμ μκ±°νμ¬ μ»κ² λλ HTML μ½λμ΄λ€.
μ¦, mixin videoλ HTML μ½λλ₯Ό return νλ ν¨μμ΄λ€.
π₯ Mixin μ¬μ©νκΈ° π₯
home.pug νμΌμ μμ νλ€.
home.pug
extends base.pug
include mixins/video.pug
block content
h1 Welcome here you will see the trending videos
each potato in videos
+video(potato)
else
li sorry nothing found
home.pug νμΌμ mixins/video.pug νμΌμ κ°μ Έμ¨λ€.
videos(λ°°μ΄) μμ κ°κ°μ potato(κ°μ²΄)μ λν΄μ, video mixinμ νΈμΆνμ¬ potatoλ₯Ό video mixinμ 보λΈλ€.
video mixinμ potatoλ₯Ό λ°μΌλ©΄μ video.pug νμΌμ μμ±ν λλ‘ potato μ¦, infoμ λͺ¨λ μ 보μ μ κ·Όν΄ HTML μ½λλ₯Ό return νλ€.
μ΄ mixinμ μ΄λμμλ μΈ μ μλ€.
μ¦, ν΄λΉ HTML μ½λλ μ΄λμλ μ¬μ¬μ©ν μ μλ€.
Error: listen EADDRINUSE: address already in use :::4000
VS code νμ₯ νλ‘κ·Έλ¨μ μ€μΉνλ μ€μ node.jsκ° λΉμ μμ μΌλ‘ μ’
λ£λμλ€.
κ·Έ λ€μλΆν° μμ κ°μ μλ¬κ° λ¨λ©΄μ μ°κ²°μ΄ μλλ€.
μλ²λ₯Ό μ’
λ£νλ€.
wslμμ 4000 ν¬νΈλ₯Ό μ¬μ© μ€μΈ νλ‘μΈμ€ λͺ©λ‘μ νμΈνλ€.
μλ²κ° μ΄λ €μμ§λ μμλ° 4000 ν¬νΈλ₯Ό μ°¨μ§νκ³ μλ νλ‘μΈμ€κ° μμ κ²μ΄λ€.
lsof -i :4000
ν΄λΉ νλ‘μΈμ€λ₯Ό κ°μ μ’ λ£νλ€.
kill -9 [PID]
λ€μ μλ²λ₯Ό μ°λ€. μ μ μλλλ€.