cat

전체 글

FrontEnd

next-intl 없이 i18n 직접 만들기

왜 직접 만들었나다국어 지원을 위해 처음 떠올린 건 next-intl이었다. Next.js 생태계에서 가장 많이 쓰이고, 공식 문서에서도 추천하는 라이브러리다.그런데 요구사항을 정리해보니 의문이 생겼다.한국어, 영어 2개 언어만 지원URL에 locale 포함 불필요 (/ko/dashboard 같은 구조 X)서버 컴포넌트에서 번역 불필요 (클라이언트에서만 전환)이미 Zustand로 전역 상태 관리 중next-intl의 핵심 기능인 서버 컴포넌트 번역, 미들웨어 기반 라우팅, locale별 URL 구조를 전혀 쓰지 않을 예정이었다. 선택지 분석방식장점한계적합한 상황next-intl풍부한 기능, SSR 지원, 커뮤니티 검증설정 복잡, 라우팅 구조 강제, 번들 크기 증가locale별 URL 필요, 서버 번역 필..

FrontEnd

iframe 키 이벤트 재합성으로 Cross-Origin 우회하기

(부제: 내가 확장프로그램을 선택할 수 밖에 없는 이유 1만가지중 하나) 웹앱에 다른 사이트를 iframe으로 삽입했을 때, iframe 내부에 포커스가 있으면 웹앱의 단축키가 먹히지 않는다. Cross-Origin이라 iframe의 이벤트에 접근할 수도 없다. 이 문제를 키 이벤트 재합성으로 해결한 방법을 정리했다. 문제 정의상황웹앱이 외부 사이트를 iframe으로 로드react-hotkeys-hook으로 단축키 처리iframe 클릭 시 포커스가 iframe 내부로 이동이후 웹앱의 단축키가 전혀 작동하지 않음 왜 안 될까?// 웹앱에서iframe.contentWindow.addEventListener('keydown', handler);// → Blocked a frame with origin "ht..

FrontEnd/React

NextAuth.js 세션 전략: DB에서 JWT로 전환하여 400ms → 5ms 달성하기

NextAuth.js로 인증을 구현할 때 세션 전략 선택은 성능에 직접적인 영향을 미친다. pixelDiff 프로젝트에서 Figma OAuth를 구현하면서 DB 세션에서 JWT로 전환한 경험을 정리한다. 문제 상황Figma OAuth 연동 후 API 응답이 체감될 정도로 느렸다. 원인을 추적해보니 매 요청마다 세션 테이블을 조회하는 데서 병목이 발생하고 있었다.[요청] → [세션 테이블 조회] → [사용자 정보 반환] → [응답] ↑ 약 400ms 소요세션 조회 자체는 단순한 쿼리지만, 네트워크 왕복(Supabase PostgreSQL)과 커넥션 오버헤드가 누적되면서 체감 지연이 발생했다. 선택지 분석전략동작 방식장점단점DB 세션매 요청마다 세션 테이블 조회서버에서 세션 무효..

토이프로젝트

Figma 스타일 스냅 가이드 시스템 구현하기

디자인 툴에서 레이어를 드래그하면 다른 레이어에 "착!" 하고 달라붙는 스냅 가이드. 당연하게 느껴지지만 직접 구현하려면 생각보다 고민할 게 많다. 요구사항 정의내가 만들고 있는 pixelDiff는 이미지 비교 도구다. 사용자가 여러 이미지를 캔버스에 올려두고 위치를 조정하는데, 이때 정렬이 안 맞으면 비교가 힘들어진다. Figma처럼 자연스러운 스냅이 필요했다.필요한 기능:5개의 정렬 기준: left, right, centerX, top, bottom, centerY다중 레이어 동시 드래그: 여러 개를 한 번에 선택해서 움직일 때도 스냅줌 레벨 대응: 확대/축소 상태에서도 일관된 UX시각적 가이드라인: 스냅될 때 어디에 맞춰지는지 보여주기 선택지 분석스냅 로직을 어떻게 설계할지 몇 가지 방식을 검토했다..

FrontEnd

Sharp + WebP로 이미지 30-50% 용량 절감하기

이미지 최적화는 웹 성능의 기본이다. 특히 이미지가 핵심인 서비스라면 더욱 그렇다.pixelDiff를 만들면서 이미지를 다루는 일이 많았다. Figma에서 4K 해상도로 export한 PNG를 저장하고, 목록에서 썸네일로 보여주고, 로딩 중에는 blur placeholder를 띄워야 했다. 매번 원본 이미지를 그대로 쓸 수는 없었다.Node.js에서 이미지 처리를 한다면 Sharp가 사실상 표준이다. libvips 기반이라 빠르고, API도 직관적이다. Sharp가 뭘까Sharp는 Node.js용 고성능 이미지 처리 라이브러리다. ImageMagick이나 GraphicsMagick보다 4-5배 빠르다고 알려져 있다.왜 이렇게 빠를까? Sharp가 사용하는 libvips의 아키텍처 덕분이다.ImageMag..

FrontEnd/React

Next.js로만 백엔드, 프론트엔드 구축하기

사이드 프로젝트를 시작할 때마다 같은 고민이 반복된다. 프론트엔드는 React나 Next.js로 금방 결정되는데, 백엔드는 어떻게 할 것인가. Express? NestJS? 별도 서버를 띄우면 인프라가 두 배가 된다. pixelDiff를 만들면서 "Next.js API Routes만으로 얼마나 갈 수 있을까?"를 실험해봤다. 결론부터 말하면, 프로덕션급 서비스까지 충분히 가능하다. 38개 엔드포인트, OAuth 인증, PostgreSQL 연동, Rate Limiting까지 모두 Next.js 안에서 해결했다. 왜 별도 백엔드를 두지 않았나 선택지는 세 가지였다.방식장점단점Express/Fastify + React자유도 높음, 검증된 패턴두 개의 배포, 두 개의 인프라NestJS + React체계적인 구조..

FrontEnd

S3 Presigned URL로 클라이언트 직접 업로드

pixelDiff에서 스크린샷 업로드 기능을 구현하면서, 처음에는 서버를 경유하는 방식으로 시작했다. 클라이언트가 이미지를 Base64로 인코딩해서 서버로 보내면, 서버가 S3에 업로드하는 구조였다. 단순하고 CORS 걱정도 없었다.그런데 파일 크기가 커지면서 문제가 생겼다. 10MB짜리 이미지를 Base64로 인코딩하면 약 13MB가 된다. 이걸 JSON으로 감싸서 서버로 보내고, 서버가 다시 S3로 보내는 동안 서버 메모리와 CPU를 잡아먹었다. 여러 사용자가 동시에 업로드하면 서버 부하가 급격히 증가할 게 뻔했다. Presigned URL이란Presigned URL은 "미리 서명된 URL"이다. S3에 업로드할 수 있는 권한이 담긴 임시 URL을 서버가 발급해주면, 클라이언트가 그 URL로 직접 S..

FrontEnd

풀페이지 스크린샷 타일 스티칭 구현

문제 정의웹앱에서 대상 페이지의 풀페이지 스크린샷이 필요했다. 핵심 제약은 두 가지였다.로그인 세션 유지 - 대시보드, 마이페이지 등 인증이 필요한 페이지를 캡처해야 한다렌더링 정확도 - CSS, Shadow DOM, 동적 콘텐츠가 실제 화면과 동일하게 캡처되어야 한다 캡처 방식 선택웹에서 스크린샷을 찍는 방식은 크게 세 가지가 있다.방식동작 원리장점한계Playwright 서버 캡처서버에서 headless 브라우저 실행fullPage: true 한 줄로 구현새 세션 생성 → 로그인 상태 없음html2canvasDOM을 Canvas로 재렌더링클라이언트에서 동작, 세션 유지iframe DOM 접근불가(확장 프로그램으로 우회 가능하긴함.)재렌더링시 css 정확도가 떨어질가능성이 있음captureVisibleT..

여행 가고싶다
blanc