Hayden's Archive
처음부터 직접 만든 나의 개발자 웹사이트 제작기 #1 본문
모든 것은 단순한 결심에서 시작되었다: “그냥 만들어야겠다.”
개발자인 나에게는 늘 머릿속 한 켠에 남아 있던 생각이 있었다. 내 자신을 제대로 표현하는 웹사이트가 없다는 것.
내 블로그 글, 포트폴리오, 이력서 등이 여러 플랫폼에 흩어져 있었다. 단순히 이것들을 한곳에 모으는 것을 넘어서, 내 커리어와 철학, 그리고 작업물을 하나의 일관된 흐름으로 엮고 싶었다.
내가 직접 만들고 다듬을 수 있는 공간이 필요했다. 내 정체성과 방향성을 정의하고 표현할 수 있는 장소 말이다.
그러다 짧은 휴식 기간 동안 드디어 여유가 생겼고, 가장 먼저 떠오른 프로젝트가 바로 이것이었다.
“지금 하지 않으면 아마 평생 못 할 거야.”
그래서 결심했다. 그리고 바로 만들기 시작했다.
기획, 콘텐츠 구조, 디자인, 프론트엔드와 백엔드 개발, 배포까지. 모든 걸 혼자 완성한 풀스택 사이드 프로젝트였다.
결국 기술은 도구일 뿐이고, 우리가 어떻게 자신을 표현하느냐가 가장 중요하니까.
컨셉과 디자인 배경
이 웹사이트는 내가 좋아하는 테마인 ‘고양이'와 '우주’를 중심으로 만들었다.
메인 페이지에 들어서면, AI 이미지 생성 도구로 만든 우주복을 입은 고양이 이미지가 방문자를 맞이한다. 전체 배경에는 내가 직접 React와 HTML5 Canvas API로 코딩한 부드럽게 움직이는 별 애니메이션이 있다. 사용자가 콘텐츠에 집중하는 동안 은은한 분위기를 더해준다.
useEffect 훅과 Canvas API를 사용해 애니메이션을 구현했으며, 각 별은 위치, 크기, 속도, 깜박임 강도 등의 속성을 가진 객체로 관리된다.
interface Star {
x: number;
y: number;
radius: number;
speedX: number;
speedY: number;
baseOpacity: number;
opacityDirection: 1 | -1;
}
화면 크기 변화에 대응해 lodash.debounce로 최적화된 resize handler가 실행되며, 디바이스 픽셀 비율(DPR)에 맞춰 렌더링을 조정해 그래픽의 선명도를 유지한다.
다국어, 단순히 텍스트를 번역하는 게 아니었다
다국어 지원을 도입한 이유는 개인적인 고민에서 출발했다. 영어와 한국어로 자기소개할 때의 어조와 표현 차이를 깨달았기 때문이다.
영어는 개발자로서의 국제 커뮤니케이션 언어이기에 기본 UI 언어로 설정했고, 한국어는 내가 가장 진솔하고 깊이 있게 표현할 수 있는 언어로 남겨두었다.
이렇게 언어의 특성에 따라 다르게 나를 소개할 수 있다는 점이 매우 매력적이었고, 이 가능성을 웹사이트에 직접 구현하고 싶었다.
또한, 나는 특정 지역에 국한되지 않고 전 세계 사용자들에게 사랑받는 서비스, 그리고 그렇게 다양한 유저층이 점점 두터워지는 과정에 깊은 관심과 보람을 느낀다. 이런 가치관은 내가 앞으로 만들고 싶은 제품의 방향성과도 맞닿아 있기에, 웹사이트 역시 글로벌한 접근성을 갖추는 것이 자연스러운 선택이었다.
이 프로젝트에서는 next-intl과 Contentlayer를 중심으로 기술 스택을 구성했다.
- next-intl은 Next.js App Router와 호환되며, 언어별 JSON 파일을 간단하게 관리할 수 있다.
- 다국어 라우팅과 SEO 최적화도 자연스럽게 가능해 /en/projects, /ko/projects 같은 URL 구조를 만들 수 있었다.
- Contentlayer + MDX를 통해 언어별 정적 콘텐츠 관리를 하고, 정적 빌드로 빠르고 안정적인 서비스 제공이 가능했다.
UI 텍스트와 콘텐츠를 완전히 분리해 유지보수성과 확장성도 극대화했다.
아래 코드는 현재 사용자 언어에 따라 프로젝트를 필터링하고 정렬하는 예시다.
const currentLocale = useLocale();
const sortedProjects = allProjects
.filter((p) => p.locale === currentLocale && p.published)
.sort(sortProjects);
MDX + Contentlayer: 콘텐츠를 코드처럼 다루다
프로젝트 콘텐츠는 MDX 파일로 관리했고, 타입 안전성을 위해 Contentlayer를 활용했다.
MDX 덕분에 React 컴포넌트를 자유롭게 삽입할 수 있어, 정적인 마크다운 구조 안에서도 인터랙티브하고 동적인 콘텐츠를 만들 수 있었다.
예를 들어, 이미지 슬라이더나 유튜브 임베드 같은 커스텀 컴포넌트를 직접 콘텐츠 안에 구현했다.
Contentlayer는 MDX 파일을 빌드 시점에 타입 안전 JSON으로 변환하며, Next.js의 정적 사이트 생성(SSG)과 결합해 빠른 로딩과 뛰어난 SEO 성능을 가능하게 했다.
또한 MDX 파일이 Git에 커밋될 때마다 새 페이지가 자동 생성돼 콘텐츠 관리가 매우 효율적이었다.
동적 콘텐츠 예시: YoutubeEmbed 컴포넌트
아래는 MDX 문서 안에 유튜브 영상을 자연스럽게 삽입하기 위해 만든 컴포넌트이다.
"use client";
import React from "react";
export interface YoutubeEmbedProps {
videoId: string;
title?: string;
}
const YoutubeEmbed: React.FC<YoutubeEmbedProps> = ({
videoId,
title = "YouTube video",
}) => {
return (
<div className="relative w-full pb-[56.25%] h-0">
<iframe
className="absolute top-0 left-0 w-full h-full border-0"
src={`https://www.youtube.com/embed/${videoId}`}
title={title}
loading="lazy"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</div>
);
};
export default YoutubeEmbed;
MDX 파일에서 이렇게 사용한다.
<YoutubeEmbed videoId="40smY5TtYb4" title="2025 포트폴리오 소개 영상" />
이 컴포넌트는 완전 반응형이라 화면 크기에 맞춰 자동으로 크기가 조정된다.
디자인? 전문 툴 없이 내 감각으로 만들었다
전문 디자이너가 아니고, 개인 프로젝트였기 때문에 Figma, Sketch 같은 디자인 툴은 사용하지 않았다.
Tailwind CSS만 사용해 내 머릿속 구조와 느낌에 따라 디자인했다.
“이 간격이 더 읽기 편할까?”, “이 색 조합이 더 보기 좋을까?” 같은 작은 실험들을 거쳐 내가 원하는 형태를 손으로 직접 만들어냈다.
Tailwind의 모바일 우선 접근 덕분에 다양한 화면 크기에 자연스럽게 대응하는 UI를 빠르고 효율적으로 만들 수 있었고, 컴포넌트 단위 레이아웃으로 코드 중복을 줄이고 유지보수성을 향상시켰으며 그 결과 관리 부담도 낮아졌다
결과적으로 전문 디자이너의 세련된 마감은 아니지만, 내가 직접 만든 깔끔하고 실용적인 UI에 만족한다.
진정 나만의 손길이 담긴 개인 웹사이트가 완성된 것이다.
마치며
지금까지 1편에서는 웹사이트 제작의 시작, 핵심 구조, 콘텐츠 관리 방식을 살펴보았다. 다음 2편에서는 블로그 연동, 보안 강화된 연락 폼, 그리고 이번 프로젝트를 통해 얻은 인사이트를 나눌 예정이다.