์ฒดํฌํฌ์ธํธ
FE
HTML & CSS
- HTML๋ ์ฉ๋์ ๋ง๋ tag๋ฅผ ์ฐพ์์ ์ฌ์ฉ
- HTML5 Layout ํ๊ทธ๋ฅผ ํ์ฉ
- ๋ชจ๋ ์๋ฆฌ๋จผํธ๋ค์ ๊ฐ์ง๋ฐํ ๋ฐฐ์นํด์ผํ๊ณ , ์ผ์ ํ ๊ฐ๊ฒฉ์ ์ ์ง.
- ๋ฐฐ์น๋ฅผ ํ ๋ flex ์์ฑ ๋๋ Position ์์ฑ์ ์ฌ์ฉ
- HTML,CSS ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์๋๊ตฌ๋ฅผ ํ์ฉํ ๋ฌธ์ ๋ถ์ ๋ฐฉ๋ฒ
JavaScript ์ DOM
- DOM ์ ๋ํ ์ ์์ DOM APIs ์ ๋ํ ๋ค์ํ ์ดํด
- DOM ๋ ธ๋๋ฅผ ํ์ํ๋ querySelector ์ ๊ฐ์ API ์ฌ์ฉ
- addEventListener ํจ์๋ฅผ ํ์ฉํ ์ด๋ฒคํธ ๋ฑ๋ก
- breakpoint๋ฅผ ํ์ฉํ ํ๋ก๊ทธ๋๋ฐ ์คํ ์ค๋จ๊ณผ ๋๋ฒ๊น
์์ ํ
- CSS ์ฝ๋์ ์ค๋ณต์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํด๋ณด์ธ์.
- ์ฃผ์์ฐฝ์ URL์ ์ ๋ ฅ ํ, ๋ธ๋ผ์ฐ์ ๋ ๋๋ง์ด ๋ ๋๊น์ง์ ๊ณผ์ ์ ์ค๋ช ํด๋ณด์ธ์.
BE
Node.js
- Node.js ์ค์น
- Node.js ์ ๋ด๋ถ ๊ตฌ์กฐ ๋ฐ ๋์์๋ฆฌ ํ์ต
- Node.js ๊ณต์๋ฌธ์์์ API ์ดํด๋ณด๊ธฐ
Express
- Express ์ค์น
- Express ์์ ์ฌ์ฉํ๋ ๋ชจ๋๊ณผ ํจํค์ง๋ค์ ์ญํ ์ดํด๋ณด๊ธฐ
- Middleware์ ๋์๋ฐฉ์ ์ดํด
- ํ ํ๋ฆฟ ์์ง ๋ฌธ๋ฒ ํ์ต ๋ฐ ํ์ฉ
์์ ํ
- ์ฃผ์์ฐฝ์์ย
http://localhost:3000/blog/230801.html์ ์ ๋ ฅํด์ ์๋ตํ๊ธฐ๊น์ง์ ์ผ์ด๋๋ ์ผ๋ค์ Express โ Node.js โ EventLoop โ LibUV โ OS(Linux) ์ ๊ด์ ์์ ์ค๋ช ํด ๋ณด์ธ์. - ํ ํ๋ฆฟ ์์ง์ ์ฌ์ฉํ๋ ์ด์ ๋ ๋ฌด์์ผ๊น์? ํ ํ๋ฆฟ ์์ง์ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด ์ด๋ค ๋์์ด ์์ ์ ์์๊น์?
ํต์ฌ ๊ฒฝํ ๊ณต์
์ด๋ฒคํธ ์์
๊ณตํต์ ์ธ ์์๋ค์ ๋ํด์ ๋๊ฐ์ html ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง ๋ถ๋ถ๋ค์ ์ฌ์ฌ์ฉ์ฑ์ ๋์ฌ ๋ค๋ฅธ ๊ณณ์์๋ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ๋ฟ๋ง ์๋๋ผ ๊ฐ๋ณ์ ์ธ ์๋ฒ์ templating ์์ ์์๋ ์ ์ฉํ๊ฒ ์ฐ์ผ ์ ์๋ ๋ฐฉ์์ ์ฌ์ฉํ๊ฒ ๋๋ฉด ์ ์ฒด์ ์ธ ์ฝ๋์ ๊ธธ์ด๋ฅผ ์ค์ผ ์ ์์ ๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ํ์ด์ง์์๋ ์ฌ์ฉํ ์ ์์ด ํ์ฉ๋๊ฐ ๋๋ค.
pug ํ ํ๋ฆฟ ์์ง์ ๊ฒฝ์ฐ, ์ด๋ฅผ mixin ๊ธฐ๋ฅ์ ํตํด ๊ตฌํํ ์ ์์๋๋ฐ, ์ด mixin์ argument๋ฅผ ๋ฐ๊ณ ์ด์ ํด๋นํ๋ html ์์๋ค์ ๋์ ์ผ๋ก ์์ฑํ ์ ์๋ค๋ ์ ์์ ์ฐ๋ฆฌ๊ฐ ์๋ ๋ฆฌ์กํธ์ ๊ฐ์ ์ปดํฌ๋ํธ์ ๊ตฌ์กฐ์ ๋น์ทํ์ฌ ์์๋ณด๊ฑฐ๋ ์ฒ๋ฆฌํ๊ธฐ ์ฝ๋ค๋ ์ฅ์ ์ ๊ฐ์ก๋ค.
mixin card(title,detail,author,date,id)
style
| @import url('/shared/card/css/card.css')
include /shared/deleteConfirm/component/deleteConfirm.pug
div.cardContainer(id=`${id}` draggable="true" data-date=`${date}`)
form(action="post").editform(hidden)
.form__div--cardForm
input.form__input--title(type="text" placeholder="์ ๋ชฉ์ ์
๋ ฅํ์ธ์" value=`${title}`)
textarea.form__textarea--cardDetail(type="text" placeholder="๋ด์ฉ์ ์
๋ ฅํ์ธ์" rows=1 maxlength=500)#cardDetail #{detail}
.form__div--buttonWrapper
input.form__input__cancel-button(type="button", value="์ทจ์")
input.form__input__submit-button(type="button", value="๋ฑ๋ก")
li.generalCard(data-drag=id)
.articleWrapper
article
p.title #{title}
p.detail #{detail}
p.author author by #{author}
aside
img.deleteTodo(src="../asset/close.svg", alt="delete", data-close=id)
img.activeEditmode(src="../asset/pen.svg", alt="edit", data-edit=id)
+deleteConfirm("todo")ํด๋นํ๋ ์ปดํฌ๋ํธ๋ ๊ฐ๊ฐ์ todolist ์์ ์นด๋๋ค์ด๋ฉฐ, ์ด๋ฅผ +card(title,detail,author,date,id)๋ฅผ ํตํด ๊ณ์ํด์ ์ฌ์ฌ์ฉํ ์ ์๋ ํํ๋ก ๋ฐ๊ฟ์ฃผ์๋ค.
ํ์ง๋ง ๊ฐ๋ณ ์นด๋์ ํด๋นํ๋ ์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ๊ธฐ ์ํด ํด๋น ์ปดํฌ๋ํธ ์์์ ์คํฌ๋ฆฝํธ๋ฅผ ์ ์ํ๊ณ ๋ถ์ฌ์ฃผ์๋๋ฐ, ๋ฌธ์ ๋ ํด๋นํ๋ ์ด๋ฒคํธ๊ฐ 3๋ฒ์ด ์คํ๋์๋ค.
๋ฌธ์ ๋ฅผ ํ์ ํด๋ณด๋ section์ด 3๊ฐ๋ก ๋๋์ด์ ธ ์ด ๋ํ ์ปดํฌ๋ํธ๋ก ๊ตฌํํ์๋๋ฐ, ์ฌ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ์ ๋ฌธ์ ์ ์ id๊ฐ ๋ชจ๋ ๊ฐ์ ์ด๋ฅผ ํ๋ณํ๊ธฐ ์ด๋ ต๋ค๋ ์ ์ด๋ค. ๋ชจ๋ ์ปดํฌ๋ํธ๋ค์์ ๋ฑ๋กํ๋ ์ด๋ฒคํธ๊ฐ ๊ฐ๊ฐ ์คํ๋์ด 3๋ฒ์ด ์คํ๋๋ ๋ฌธ์ ๊ฐ ์๊ธด ๊ฒ์ด๋ค.
๊ธฐ์กด์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ์์ ์ปดํฌ๋ํธ์์ ๊ฐ ์ปดํฌ๋ํธ์ ํด๋นํ๋ ์ด๋ฒคํธ๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๋ฑ๋กํด์ฃผ๋ ๋ฐฉ๋ฒ์ด ์์๋๋ฐ,
- querySelectorAll๋ฅผ ํตํด ๋ชจ๋ ์ปดํฌ๋ํธ๋ค์ ๊ฐ์ ธ์ forEach๋ฌธ์ ํตํด ๊ฐ๊ฐ์ ์์์ ์ด๋ฒคํธ ๋ฑ๋ก
- ์์ ์ปดํฌ๋ํธ์์ ์ด๋ฒคํธ๋ฅผ ์์ํ์ฌ ์ฒ๋ฆฌ ๊ฐ ์์๋ค. ํ์ง๋ง 1๋ฒ์ ๊ฒฝ์ฐ ๊ฐ๋ณ์ ์ธ ์ปดํฌ๋ํธ๋ค์ด ๋ง์์ง๊ฒ ๋๋ฉด ๊ฐ๊ฐ์ ๋ํด์๋ ๋ชจ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํด์ค์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์์ ์ด์๊ฐ ์๊ธธ ์ ์๋ค. ๋ฐ๋ผ์ ์์์์ ๋ชจ๋ ๊ณตํต์ ์ผ๋ก ์์ฉํ ์ ์๋ ์ด๋ฒคํธ๋ฅผ ํ๋ ๋ฑ๋กํ๊ณ , ์์ํ์ฌ ํด๋นํ๋ ์ปดํฌ๋ํธ๋ฅผ ๊ตฌ๋ถ ํ ํ์ ์ฒ๋ฆฌํ ์ ์๋๋ก ํ๋ ์ด๋ฒคํธ์์์ ์ ํํ์๋ค.
document.getElementById("sections").addEventListener("click", (event) => {
// ๊ฐ ์น์
๋ณ ์ด๋ฒคํธ๋ค
let addTodo = event.target.dataset.addform;
if (addTodo) {
// ๊ฐ ํผ์ ์ด๋ฒคํธ ์์
let form = document.getElementById(addTodo);
// ๋ณด์ด๊ฒ ํ๋ ์์ฑ
form.hidden = false;
// ํ ์ผ ์ถ๊ฐ ํผ ์
๋ ฅ๋ ํฌ๊ธฐ ์กฐ์
let detailInput = form.getElementsByClassName(
"form__textarea--cardDetail"
)[0];
detailInput.addEventListener("input", adjustTextInput);
// ์ฐฝ ๋ซ๊ธฐ ํผ
let cancelButton = form.getElementsByClassName(
"form__input__cancel-button"
)[0];
cancelButton.addEventListener("click", () => closeForm(form));
let submitButton = form.getElementsByClassName(
"form__input__submit-button"
)[0];
submitButton.addEventListener("click", () => {
console.log("submit event");
});
}
// ๊ฐ ์นด๋ ๊ด๋ จ ์ด๋ฒคํธ๋ค
// ์นด๋ ํํธ(ํธ์ง ๋ชจ๋ ์ด๊ธฐ)
let editId = event.target.dataset.edit;
if (editId) {
const editComponent = document.getElementById(editId);
// Edit mode ํ์ฑํ
editComponent.getElementsByClassName("editform")[0].hidden = false;
// ํ ์ผ ์ถ๊ฐ ํผ ์
๋ ฅ๋ ํฌ๊ธฐ ์กฐ์
let detailInput = editComponent.getElementsByClassName(
"form__textarea--cardDetail"
)[0];
detailInput.addEventListener("input", adjustTextInput);
// ์นด๋ ์์ -> ์ทจ์ ๋๋ ์ ๋
let cancelButton = editComponent.getElementsByClassName(
"form__input__cancel-button"
)[0];
cancelButton.addEventListener("click", () => closeEditForm(editComponent));
// ์ผ๋ฐ ์นด๋ ์จ๊ธฐ๊ธฐ
const generalCard = editComponent.getElementsByClassName("generalCard")[0];
if (generalCard) {
generalCard.style.display = "none";
}
}
// ์นด๋ ์ญ์ ํ๊ธฐ
let closeId = event.target.dataset.close;
if (closeId) {
const closeComponent = document.getElementById(closeId);
closeComponent.getElementsByClassName("modalBackground")[0].style.display =
"flex";
closeComponent
.getElementsByClassName("cancelButton")[0]
.addEventListener("click", () => {
closeComponent.getElementsByClassName(
"modalBackground"
)[0].style.display = "none";
});
closeComponent
.getElementsByClassName("conFirmButton")[0]
.addEventListener("click", () => {
closeComponent.getElementsByClassName(
"modalBackground"
)[0].style.display = "none";
closeComponent.remove();
});
}
});FSD ํจํด
Feature-sliced Design์ ๋ชจ๋ ๊ฐ์ ๋์จํ ๊ฒฐํฉ๊ณผ ๋์ ์์ง๋ ฅ์ ์ ๊ณตํ ์ ์์ผ๋ฉฐ, ์ฝ๊ฒ ํ์ฅํ ์ ์๋ ์ํคํ
์ฒ์ด๋ค.
์ด๋ฌํ ํจํด์ ์ธ ๊ฐ์ง ๊ตฌ๋ถ ๊ฐ๋
์ด ์๋ค.

Layer
- app
- ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ด ์ด๊ธฐํ๋๋ ๊ณณ
- ํ๋ก๋ฐ์ด๋, ๋ผ์ฐํฐ, ์ ์ญ ์คํ์ผ, ์ ์ญ ํ์ ์ ์ธ ๋ฑ
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์ง์ ์ ์ญํ
- processes(depricated)
- ์ด ๋ ์ด์ด๋ ์ฌ๋ฌ ๋จ๊ณ๋ก ์ด๋ฃจ์ด์ง ๋ฑ๋ก๊ณผ ๊ฐ์ด ์ฌ๋ฌ ํ์ด์ง์ ๊ฑธ์ณ ์๋ ํ๋ก์ธ์ค๋ฅผ ์ฒ๋ฆฌ
- ์ด ๋ ์ด์ด๋ ๋ ์ด์ ์ฌ์ฉ๋์ง ์๋ ๊ฒ์ผ๋ก ๊ฐ์ฃผ๋์ง๋ง ์ฌ์ ํ ๊ฐ๋์ฉ ๋ง์ฃผํ ์ ์์ต๋๋ค. ์ ํ์ ๋ ์ด์ด์ ๋๋ค.
- pages
- ์ด ๋ ์ด์ด์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ด์ง๊ฐ ํฌํจ๋ฉ๋๋ค.
- widgets
- ํ์ด์ง์ ์ฌ์ฉ๋๋ ๋ ๋ฆฝ์ ์ธ UI ์ปดํฌ๋ํธ
- features
- ์ด ๋ ์ด์ด๋ ๋น์ฆ๋์ค ๊ฐ์น๋ฅผ ์ ๋ฌํ๋ ์ฌ์ฉ์ ์๋๋ฆฌ์ค์ ๊ธฐ๋ฅ
- ์ข์์, ๋ฆฌ๋ทฐ ์์ฑ, ์ ํ ํ๊ฐ ๋ฑ์ด ์์ต๋๋ค.
- ์ ํ์ ๋ ์ด์ด
- entities
- ๋น์ฆ๋์ค ์ํฐํฐ
- ์ฌ์ฉ์, ๋ฆฌ๋ทฐ, ๋๊ธ ๋ฑ์ด ํฌํจ๋ ์ ์์ต๋๋ค.
- ์ ํ์ ๋ ์ด์ด
- shared
- ์ด ๋ ์ด์ด์๋ ํน์ ๋น์ฆ๋์ค ๋ก์ง์ ์ข ์๋์ง ์์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ์ ์ ํธ๋ฆฌํฐ
- ์ฌ๊ธฐ์๋ UI ํคํธ, axios ์ค์ , ์ ํ๋ฆฌ์ผ์ด์ ์ค์ , ๋น์ฆ๋์ค ๋ก์ง์ ๋ฌถ์ด์ง ์์ ํฌํผ ๋ฑ
Slices
์ฌ๋ผ์ด์ค๋ ํน์ ์ํฐํฐ์ ๋ํด์ ์ฝ๋๋ฅผ ๊ทธ๋ฃนํ ํ๋ค.
์ด์ ๊ฐ์ด ํ์ํ ๊ฐ์ ๋ํด์ ๋
๋ฆฝ์ ์ผ๋ก ๋ค๋ฃฐ ์ ์๋ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ๋ค.
์ธ๊ทธ๋จผํธ
๊ฐ ์ฌ๋ผ์ด์ค๋ ์ธ๊ทธ๋จผํธ๋ก ๊ตฌ์ฑ๋๋ฉฐ ๋ชฉ์ ์ ๋ฐ๋ผ ์ฌ๋ผ์ด์ค ๋ด์ ์ฝ๋๋ฅผ ๋๋๋๋ฐ ๋์์ด ๋ ์ ์๋ค.
- api - ํ์ํ ์๋ฒ ์์ฒญ.
- UI - ์ฌ๋ผ์ด์ค์ UI ์ปดํฌ๋ํธ.
- model - ๋น์ฆ๋์ค ๋ก์ง, ์ฆ ์ํ์์ ์ํธ ์์ฉ. actions ๋ฐ selectors๊ฐ ์ด์ ํด๋น
- lib - ์ฌ๋ผ์ด์ค ๋ด์์ ์ฌ์ฉ๋๋ ๋ณด์กฐ ๊ธฐ๋ฅ.
- config - ์ฌ๋ผ์ด์ค์ ํ์ํ ๊ตฌ์ฑ๊ฐ์ด์ง๋ง ๊ตฌ์ฑ ์ธ๊ทธ๋จผํธ๋ ๊ฑฐ์ ํ์ํ์ง ์์.
- consants - ํ์ํ ์์.
๋๋ ์ด๋ฌํ FSD๋ฅผ ์ผ๋ถ ์ฐธ๊ณ ํ์ฌ ๋๋ง์ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋ง๋๋๋ฐ ํ์ฉํ์๋ค. ํ์ง๋ง ์ค์ํ ์ ์ธ ์ฌ๋ผ์ด์ค์ ์ธ๊ทธ๋จผํธ์ ๋ณธ์ง์ ์ด๊ธ๋์ง ์๋๋ก ์กฐ์จํ์๋ค.
