Next.js 미드레벨 코딩 면접
새 면접Q. Next.js App Router의 Route Handler에서 대용량 CSV 파일(수백 MB)을 생성하여 클라이언트에 전송해야 하는 상황입니다. 전체 파일을 메모리에 올리지 않고 스트리밍 방식으로 응답을 보내는 방법을 설명하고, ReadableStream과 TransformStream을 활용한 구현 전략을 제시해주세요. 또한 이 방식이 서버 메모리와 TTFB에 미치는 영향을 분석해주세요.
Route Handler에서 ReadableStream을 반환하면 Next.js가 자동으로 청크 단위로 응답을 스트리밍합니다. TransformStream을 사용하여 데이터베이스에서 조회한 레코드를 즉시 CSV 형식으로 변환하고 클라이언트로 전송할 수 있습니다. 이 방식은 전체 파일을 메모리에 올리지 않으므로 서버 메모리 사용량이 일정하게 유지되며, 첫 번째 청크가 즉시 전송되므로 TTFB가 크게 개선됩니다. new ReadableStream()의 pull 메서드 내에서 데이터를 배치로 읽어 controller.enqueue()로 청크를 푸시하는 패턴을 사용하며, 완료 시 controller.close()를 호출합니다.
- • ReadableStream을 사용하여 청크 단위로 데이터를 생성하고 전송
- • TransformStream으로 데이터 변환 파이프라인 구성
- • 메모리 사용량을 일정하게 유지하여 OOM 방지
- • 첫 번째 청크 즉시 전송으로 TTFB 개선
- • Response 객체에 적절한 Content-Type과 Content-Disposition 헤더 설정
스트리밍 중 데이터베이스 연결이 끊기거나 에러가 발생한 경우, 이미 전송된 청크를 취소하거나 클라이언트에 에러를 알리는 방법은 무엇인가요?
Q. Next.js 애플리케이션에서 실시간 협업 기능을 구현할 때, WebSocket을 통해 받은 외부 상태 업데이트와 사용자의 로컬 상태 변경이 충돌하는 상황을 처리해야 합니다. Operational Transformation(OT) 또는 CRDT(Conflict-free Replicated Data Types)의 기본 개념을 설명하고, React의 상태 관리와 결합하여 충돌 해결을 구현하는 전략을 제시해주세요.
OT는 동시 편집 시 각 작업(operation)을 변환하여 순서를 조정하는 방식이고, CRDT는 교환법칙과 결합법칙이 성립하도록 데이터 구조를 설계하여 자동으로 수렴하는 방식입니다. React에서는 useReducer를 사용하여 로컬 작업과 원격 작업을 모두 처리하되, 각 작업에 타임스탬프와 클라이언트 ID를 부여합니다. CRDT의 LWW(Last-Write-Wins) 전략을 사용하면 타임스탬프가 큰 작업이 우선되며, 동일 시간에는 클라이언트 ID로 결정론적 순서를 보장합니다. 낙관적 업데이트를 적용하되, 서버로부터 확인을 받기 전까지 작업을 pending 큐에 보관하고, 충돌 발생 시 로컬 작업을 재적용하는 롤백 메커니즘을 구현합니다.
- • OT는 작업 변환, CRDT는 수렴 가능한 데이터 구조 사용
- • useReducer로 로컬/원격 작업을 단일 상태 흐름으로 관리
- • 타임스탬프와 클라이언트 ID로 결정론적 충돌 해결
- • pending 큐로 미확인 작업 추적 및 재적용
- • Vector Clock 또는 Lamport Timestamp로 인과관계 추적
여러 사용자가 동시에 배열의 같은 인덱스에 요소를 삽입하려고 할 때, CRDT 방식으로 어떻게 일관된 순서를 보장할 수 있나요?
Q. Next.js 클라이언트 컴포넌트에서 대규모 테이블(수천 개의 행)을 렌더링할 때 가상 스크롤링(Virtual Scrolling)을 구현해야 합니다. 가상 스크롤링의 동작 원리를 설명하고, 가변 높이의 행을 처리할 때 발생하는 문제점과 해결 방법을 제시해주세요. 또한 스크롤 성능 최적화를 위해 requestAnimationFrame을 활용하는 방법도 설명해주세요.
가상 스크롤링은 뷰포트에 보이는 행만 실제로 렌더링하고, 전체 높이는 계산된 값으로 스크롤바를 유지하는 기법입니다. 스크롤 위치를 기준으로 startIndex와 endIndex를 계산하여 해당 범위의 행만 DOM에 추가하고, transform: translateY()로 위치를 조정합니다. 가변 높이의 경우 각 행의 높이를 미리 측정하거나 추정값을 사용한 후, 실제 렌더링 시 ResizeObserver로 측정하여 높이 맵을 업데이트합니다. 스크롤 이벤트는 requestAnimationFrame으로 감싸서 브라우저의 리페인트 주기에 맞춰 처리하고, 과도한 재계산을 방지하기 위해 스크롤 이벤트를 throttle 처리합니다.
- • 뷰포트 내 요소만 렌더링하여 DOM 노드 수 최소화
- • 전체 높이를 계산하여 스크롤바 크기 유지
- • 가변 높이는 ResizeObserver로 동적 측정 및 높이 맵 업데이트
- • requestAnimationFrame으로 스크롤 처리를 리페인트 주기에 동기화
- • 오버스캔(overscan) 버퍼로 스크롤 시 깜빡임 방지
가상 스크롤링을 구현할 때 키보드 네비게이션(화살표 키, Page Up/Down)을 지원하려면 어떤 추가 로직이 필요한가요?
Q. Next.js 프로젝트에서 번들 크기가 지속적으로 증가하여 초기 로딩 시간이 느려지고 있습니다. Webpack Bundle Analyzer를 사용하여 발견할 수 있는 일반적인 번들 비대화 원인들을 설명하고, Tree Shaking이 제대로 동작하지 않는 상황과 이를 해결하기 위한 방법을 제시해주세요. 또한 동적 import의 청크 분할 전략과 prefetch 최적화 방법도 설명해주세요.
번들 비대화의 주요 원인은 중복 의존성(여러 버전의 같은 라이브러리), 사용하지 않는 코드 포함, 무거운 라이브러리의 전체 import입니다. Tree Shaking이 실패하는 경우는 CommonJS 모듈 사용, 사이드 이펙트가 있는 코드, package.json의 sideEffects 설정 누락 등이 있으며, ESM 형식의 라이브러리를 사용하고 named import를 활용해야 합니다. 동적 import 시 webpackChunkName 주석으로 청크 이름을 지정하고, 관련된 모듈을 같은 청크로 그룹화합니다. Link 컴포넌트의 prefetch 속성은 뷰포트에 들어올 때 자동으로 작동하지만, 중요하지 않은 페이지는 prefetch={false}로 설정하여 초기 네트워크 요청을 줄입니다.
- • Bundle Analyzer로 중복 의존성과 큰 모듈 식별
- • ESM과 named import로 Tree Shaking 활성화
- • package.json의 sideEffects 필드로 부수효과 명시
- • webpackChunkName으로 청크 분할 전략 제어
- • 선택적 prefetch로 초기 로딩 최적화
lodash와 같은 유틸리티 라이브러리를 사용할 때 Tree Shaking을 최대화하기 위한 import 방식과, lodash-es를 사용해야 하는 이유는 무엇인가요?
Q. Next.js 애플리케이션에서 JWT 기반 인증을 구현할 때, Access Token과 Refresh Token을 사용하는 이중 토큰 전략의 보안 이점을 설명하고, 토큰을 안전하게 저장하는 방법(HttpOnly Cookie vs LocalStorage)을 비교해주세요. 또한 Token Rotation과 Refresh Token의 자동 갱신 로직을 구현할 때 고려해야 할 Race Condition과 이를 방지하는 전략을 설명해주세요.
Access Token은 짧은 만료 시간(15분)으로 탈취 위험을 최소화하고, Refresh Token은 긴 만료 시간(7일)으로 사용자 편의성을 제공합니다. HttpOnly Cookie는 JavaScript로 접근 불가하여 XSS 공격에 안전하지만 CSRF 공격에 취약하므로 SameSite=Strict 속성과 CSRF 토큰을 함께 사용해야 합니다. LocalStorage는 XSS에 취약하므로 민감한 토큰 저장은 피해야 합니다. Token Rotation 시 여러 요청이 동시에 401을 받아 refresh를 시도하는 Race Condition이 발생할 수 있으므로, 전역 Promise 변수로 refresh 요청을 단일화하고, 진행 중인 요청이 있으면 같은 Promise를 반환하도록 구현합니다. Refresh Token도 사용 시마다 새로 발급받아 이전 토큰을 무효화하는 Rotation 전략을 적용합니다.
- • Access Token은 짧은 만료, Refresh Token은 긴 만료로 보안과 편의성 균형
- • HttpOnly Cookie + SameSite + Secure 속성으로 XSS/CSRF 방어
- • 전역 Promise로 동시 refresh 요청 중복 방지
- • Refresh Token Rotation으로 재사용 공격 차단
- • Axios/Fetch 인터셉터에서 401 응답 시 자동 토큰 갱신
Refresh Token이 탈취당했을 때 피해를 최소화하기 위한 Detection 메커니즘과, Refresh Token Reuse Detection을 구현하는 방법은 무엇인가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!