Vaniila JS로 To-do 사이트 만들기(CRUD 구현, Rest API 활용)에 그치지 않고 부족한 부분을 보완했다. Webpack
,Typescript
, dot env
를 적용했고, 리팩토링과 의도에 맞도록 동작하는 것과 기능을 추가하는 것을 진행했다.
따로 포스팅을 하여 상세히 과정을 적어두기도 했다.
Webpack에 대한 이해도를 높이기 위해, Parcel 번들러를 걷어내고 Webpack 을 적용해봤다. 확실히 Parcel보다 사용자가 설정해줘야하는 것이 많았다. 하지만 Webpack5 버전까지 올라오면서 대부분 default 로 자동 설정되는 부분도 많았다.
Typescript는 여태 프로젝트에 참여하면서 다른 분들이 설정해주신 것을 쓰기만 했다. 혼자 설정도 해보고 언어에 익숙해지고자 도입했다. 또 Webpack과 Typescript로 개발환경을 혼자 만들어보고 싶었다! 환경을 구축하며 에러를 맞닥뜨렸고, 결국 도입한 프로그램들 간의 연결을 고려해야하는 것의 필요성을 깨달았다. 또 type 지정에 많이 능숙해졌다고 생각했는데, 아직 공부해야하는 게 많다는 걸 알게됐다.
이 프로젝트를 진행할 당시엔 js로 무언가를 만드는 걸 처음 해봤고, rest api 호출도 익숙하지 않았다. fetch도 뭔지 모르고 일단 구현하는 걸 목표로 하며 진행했다. 이 후 다른 팀 프로젝트들을 진행하면서 계속 초반에 진행했던 이 todo 사이트가 눈에 밟혔다. 내가 작성했지만 더 나은 (가독성과 유지보수 측면) 코드를 작성하고 싶었고, 못해봤던 것도 해보고 싶었다. 그래서 리팩토링을 진행하게 됐다.
┏ 📦css
┃ ┣ #️⃣reset-css.css
┃ ┗ 📜style.css
┣ 📦js
┃ ┣ 📜APIkey.js
┃ ┣ 📜APIs.js
┃ ┣ 📜clock.js
┃ ┣ 📜location-and-weather.js
┃ ┗ 📜main.js
┃ ┗ 📜username.js
┣ 📜index.html
┣ 📜package-lock.json
┣ 📜package.json
┗ 📜README.md
위는 기존 디렉터리 구조이다. main.js 에서 위젯(clock, location-and-weather, username)도 import 하고 todo와 관련된 crud 도 구현하는 등 한 파일에서 많은 것들이 이뤄지고 있었다. 가독성이 현저히 떨어졌다.
import '@/reset-css.css';
import '@/main.css';
import clock from '@utils/clock';
import { success, error } from '@utils/location-and-weather';
import username from '@utils/username';
import { todoFormEl, filterBtn, titlebarBtn } from '@utils/store';
import {
handleGetTodos,
handleAddTodos,
handleFilter,
} from '@utils/handleTodo';
// clock
setInterval(clock, 1000, '.taskbar-clock');
// weather and location
navigator.geolocation.getCurrentPosition(success, error);
// username
const signinFormEl = document.querySelector('.type-name-form');
const signinInputEl = document.querySelector('.type-name-input');
const printNameEl = document.querySelector('.print-name');
const signoutBtn = document.querySelector('.signoutbtn');
username(signinFormEl, signinInputEl, printNameEl, signoutBtn);
// titlebarBtn
titlebarBtn?.addEventListener('click', () => {
alert("can't close 😀");
});
// get
handleGetTodos();
// add
todoFormEl?.addEventListener('submit', handleAddTodos);
// filter
filterBtn?.addEventListener('click', handleFilter);
많은 것들을 모듈화시켜 분리해낸 현재의 main.ts 파일이다. 이 파일에서 기능을 동작하는 것은 피하고, 최대한 이미 선언한 함수들을 가져와 사용하려고 했다.
//get
export async function getServerTodos() {
try {
const res = await fetch(APIURL, {
method: "GET",
headers: HEADERS,
});
const json = await res.json();
return json;
} catch (error) {
console.log(error);
}
}
//add
export async function addServerTodos(title, order) {
try {
const res = await fetch(APIURL, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({
title: title,
order: order,
}),
});
const json = await res.json();
return json;
} catch (error) {
console.log(error);
}
}
.
.
.
api 관련 코드들은 한 파일에서 관리하고 있었는데, 위처럼 중복된 코드들이 많았다.
const request = async (
url: string,
method: string,
body: object | null = null
) => {
try {
const res = await fetch(url, {
method,
headers: HEADERS,
body: body ? JSON.stringify(body) : null,
});
const json = await res.json();
return json;
} catch (error) {
console.log(error);
}
};
//get
const getServerTodos = async () =>
(await request(TODO_BASE_URL, 'GET')) as IRes[];
//add
const addServerTodos = async ({ title, order = 0 }: IAddReq) =>
(await request(TODO_BASE_URL, 'POST', { title, order })) as IRes;
.
.
.
공통된 부분들은 함수(request
)로 만들어 중복되는 코드를 최대한 줄였다.
// 리팩토링 전
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
// 리팩토링 후
const [month, day, hours, minutes] = [
date.getMonth() + 1,
date.getDate(),
date.getHours(),
date.getMinutes(),
]
.map(String)
.map((el) => el.padStart(2, '0'));
map을 활용하여 중복코드를 줄이려고도 했다.
add
버튼은 동작하지 않고 있던 것! 버튼을 눌러도 submit 되도록 수정했다.sign in
버튼을 만들었고, 버튼으로도 submit 되도록 했다.