MyPortfolio는 제가 프론트엔드 개발자로서 쌓아온 기술 역량과 프로젝트 성과를 한눈에 보여주기 위해 제작되었습니다. 각 프로젝트는 사용된 기술 스택, 구현 기능, 그리고 해결했던 문제를 구체적으로 담고 있습니다. GitHub 저장소와 배포 링크를 통해 제 코딩 스타일과 결과물을 직접 확인할 수 있으며 도메인이 만료된 프로젝트는 데모 영상을 통해 실제 동작을 확인하실 수 있습니다. 사용자(방문자)가 제 개발 스타일을 쉽게 파악하고 포트폴리오를 통해 저의 잠재력을 느낄 수 있도록 사용자 경험(UX)에 집중했습니다.
SEO 최적화와 링크 공유 가능성을 위해 기존 상태 기반 모달에서 Intercepting Routes로 전환했습니다.
Intercepting Routes 기능을 활용하여 프로젝트 상세 모달이 고유 URL을 가지도록 구현Next.js 앱에서 이미지 지연 로딩 및 깜빡임 현상을 해결하고 Vercel CDN 캐시 활용을 통해 LCP를 약 48% 단축하는 등의 성능 최적화를 달성했습니다.
모달 표시 지연 문제를 해결하기 위해 IntersectionObserver와 Next.js의 router.prefetch를 조합해 프로젝트 상세 페이지 관련 리소스를 사전에 로드하는 전략을 도입했습니다.
IntersectionObserver를 활용해 카드가 뷰포트 근처(100px 이내)에 들어올 때 상세 페이지 라우트를 자동 프리페칭router.prefetch를 호출하여 사용자 행동 기반 사전 로딩 보완실무 도입 전 사전 경험을 위해 Storybook을 사용하여 UI 컴포넌트를 문서화하고 시각적 테스트를 진행했습니다.
Jest와 React Testing Library를 도입해 단순한 동작 확인을 넘어 실제 사용자 경험과 가까운 시나리오까지 검증했습니다. 컴포넌트 단위의 안정성과 사용자 흐름 단위의 신뢰성을 동시에 확보하며 프로젝트 품질을 한 단계 끌어올렸습니다.
코드 품질 보장과 배포 전 자동 검증을 위한 CI 파이프라인을 구성했습니다.
SEO 설정 후 실제 검색 노출 및 방문자 변화 추이를 데이터 기반으로 측정하기 위해 Google Analytics를 도입했습니다.
Google Analytics 같은 외부 분석 도구를 사용하지 않고, Supabase를 활용해 방문자 수를 자체적으로 집계·표시할 수 있는 기능을 구현했습니다.
fetch(..., { cache: "no-store" })를 적용해 항상 서버의 최신 방문자 수를 반영, 캐시된 오래된 데이터 문제 방지방문자가 포트폴리오에 대해 피드백을 남길 수 있도록 서버리스 메일 전송 기능 구현했습니다.
상/하단 이동이 자유로운 버튼 구현으로 사용자의 편의성을 향상시켰습니다.
📌 문제 배경
프로젝트의 ProjectsSection에서 카드 클릭 시 모달이 열리고 닫히는 구조였는데 모달 종료 후 카드 이미지가 다시 렌더링되면서 이미지 깜빡임과 지연 로딩 현상이 발생했습니다.
🔍 원인 분석
public 폴더 이미지 사용 시 next/image의 최적화 기능이 적용되지 않음🛠 해결 과정
vercel.json 설정 파일을 추가하여 public 폴더 내 이미지 파일에 대해 max-age=31536000, immutable 설정을 적용✅ 결과
🧠 배운 점
이미지 깜빡임 문제를 해결하면서 웹 성능 최적화에 대한 시각이 완전히 바뀌었습니다. 처음에는 단순히 이미지 로딩 문제로만 생각했는데 실제로는 캐시 정책과 CDN 설정이 핵심이었습니다. vercel.json 하나로 이렇게 극적인 변화가 생길 줄 몰랐습니다. 450ms에서 59ms로 로딩 시간이 줄어든 것도 놀랍지만 캐시 HIT율이 90% 이상으로 올라간 건 정말 인상적이었습니다. 이 경험을 통해 프론트엔드 개발에서 정적 자원 관리의 중요성을 체감했고 앞으로는 초기 설정 단계에서부터 캐시 전략을 고민해야겠다고 생각했습니다.
📌 문제 배경
기존 ProjectsSection에서 카드 클릭 시 모달 관련 컴포넌트와 라우트 번들이 즉시 로드되었습니다. 이로 인해 스크립트 컴파일, 평가, 레이아웃 계산 등 여러 작업이 클릭 시점에 한꺼번에 발생하여 모달이 포함된 페이지의 전반적인 반응 속도가 느려졌습니다. 전체 이벤트 총 시간은 약 5.48초에 달했습니다.
🔍 원인 분석
router.prefetch) 기능이 활용되지 않아 사전 로딩이 이루어지지 않음🛠 해결 과정
IntersectionObserver를 활용하여 카드가 뷰포트 100px 이내에 들어오면 해당 프로젝트 상세 경로를 `router.prefetch`로 사전 로드하도록 구현onMouseEnter)하거나 포커스(onFocus)할 때도 router.prefetch를 호출해 인터랙션 기반의 사전 로딩을 보완✅ 결과
🧠 배운 점
단순히 클릭을 기다리던 기존 방식이 사용자에게 얼마나 큰 지연 시간으로 다가갔는지 체감할 수 있었습니다. 이번에 IntersectionObserver를 활용해 사용자의 시선이 머무를 만한 영역을 예측하고 리소스를 미리 로드하는 전략을 적용하면서 성능 최적화에 대한 시각이 완전히 바뀌었습니다. 개발자에게는 보이지 않는 수십 ms의 개선이 사용자에게는 '빠릿하다'와 '답답하다'의 차이를 만든다는 것을 숫자로 확인했습니다. 이제는 단순히 기능을 구현하는 데 그치지 않고 사용자의 다음 행동을 예측해 보이지 않는 곳에서 미리 준비해두는 습관을 들여야겠다고 다짐하게 되었습니다.