돌멩이,

"늘 새로운 것을 탐구하고 분석하고, 일상 속 익숙해진 불편함을 해결하는 데 집중하면서 내 맘대로 작업물을 업로드하고 있습니다. 이 페이지는 개인 작업과 기술 실험을 모아 둔 포트폴리오이자 블로그입니다."

archive

자바스크립트의 비동기 동작원리... 내가 이해한 콜스택과 태스크 큐

이 글을 "왜" 쓰는가?프론트 개발에서 화면에 보여지는 data는 백엔드와 통신을 통해 데이타를 주고 받아 화면에 알 맞는 데이타를 보여주는 역할을 한다.특히 백엔드와 통신하며 데이터를 주고받을 때, 호출 타이밍이 꼬여서 내가 의도한 순서가 아닌 다른 함수가 먼저 실행되는 상황을 빈번하게 겪곤 한다.분명 머릿속으로는 흐름을 그리고 있는데, 왜 실제 실행 결과는 다를까? 싱글 스레드인 자바스크립트가 어떻게 이런 '동시성'을 가질 수 있는지, 그리고 내가 생각하는 호출 순서가 맞는지 확인하기 위해 잊고 있었던 머릿속 지식을 다시 한번 깊게 정리하고 복습해 보려 한다.1. 콜스택 (Call Stack): 모든 실행의 시작점콜스택은 자바스크립트 엔진이 함수 호출을 관리하는 핵심 장치다. 말 그대로 '스택(Stack)' 구조라 LIFO(Last In, First Out) 방식으로 작동한다. 현재 어떤 함수가 실행 중인지, 그 함수가 끝나면 어디로 돌아가야 하는지를 기록한다.항상 염두에 두어야 할 점은 자바스크립트 엔진의 콜스택은 하나뿐이라는 것이다. 한 번에 하나의 함수만 실행할 수 있다는 뜻이다. function first() { second(); console.log('첫 번째'); } function second() { console.log('두 번째'); } first(); // 실행 흐름: first() 함수 호출 -> second() 함수 호출 -> second() 함수에 로그 출력 -> first 함수에 로그 출력 // '두번째' -> '첫 번째'2. Web APIs자바스크립트 엔진 자체는 비동기 처리를 하지 못한다. 대신 브라우저(또는 Node.js) 런타임 환경이 제공하는 Web APIs가 이 역할을 대신해 준다.setTimeout, fetch, DOM Events 같은 비동기 함수들은 호출되는 즉시 콜스택에서 빠져나와 Web API 세션으로 넘겨진다. 덕분에 메인 스레드는 멈추지 않고 다음 코드를 바로 실행할 수 있는 것이다.3. 이벤트 루프와 대기실 (Queue)비동기 처리가 끝난 콜백 함수들은 곧장 실행되지 않고 큐(Queue)라는 대기실에서 대기한다. 여기서 이벤트 루프(Event Loop)가 등장한다.이벤트 루프는 콜스택이 비어 있는지 끊임없이 확인한다. 만약 콜스택이 텅 비어 있다면, 대기 중인 콜백을 순서대로 콜스택으로 옮겨준다. 이것이 자바스크립트가 비동기를 처리하는 근본적인 메커니즘이다.4. 마이크로태스크 vs 매크로태스크 (가장 헷갈렸던 부분)가장 흥미로웠던 점은 큐가 하나가 아니라는 사실이다. 비동기 콜백에도 엄격한 우선순위가 존재한다.1) Microtask Queue (마이크로태스크 큐)

2026. 01. 12

자바스크립트의 비동기 동작원리... 내가 이해한 콜스택과 태스크 큐
archive

SSR(Server Side Rendering)이란?

SSR(Server Side Rendering)이란?SSR(Server Side Rendering) 방식은 서버에서 완성된 정적 HTML을 클라이언트에 내려주는 방식이다. 클라이언트 측에서는 해당 HTML을 파싱만 하여 화면을 그리게 된다.반면, CSR(Client Side Rendering) 방식은 브라우저가 서버로부터 비어있는 뼈대 HTML을 받아온 후, 필요한 자바스크립트 번들을 다운로드하고 번들을 실행하여 동적으로 컨텐츠를 채우는 방식이다.Next.js에서는, SSR 방식으로 정적인 HTML을 내려주어 초기 화면을 빠르게 렌더한 이후, hydration을 통해 이벤트 리스너 부착 등의 자바스크립트 작업을 수행하여 정적인 화면을 동적으로 전환하는 작업을 수행하기도 한다.SSR의 장점은 무엇인가?SEO(검색 엔진 최적화) 측면에서 유리하다. 화면이 동적으로 그려지는 CSR에 비해 크롤러가 컨텐츠를 쉽게 인식하며, 초기 로드가 상대적으로 빨라 우선순위가 부여되어 상위에 노출될 가능성이 높아지기 때문이다. 이런 점에서 SSR은 블로그나 커머스 등 SEO가 중요한 웹 애플리케이션에 특히 적합하다.또한, SSR 방식에서는 사용자가 빠른 초기 로딩 속도를 경험할 수 있다. CSR과 달리 SSR에서는 번들을 다운로드 받거나 번들을 실행하여 동적으로 화면을 그려야 할 필요가 없기 때문이다.SSR의 단점은 없는가?전통적인 SSR 방식에서는 클라이언트 사이드 라우팅이 불가능하기 때문에 빠르고 매끄러운 페이지 전환 경험을 제공하기 어렵다. 또한, 단순히 정적인 리소스를 내려주는 것이 아니라, 요청 시마다 페이지를 동적으로 구성해서 내려주어야 하는 경우에는 WAS 서버 구동으로 인해 서버 비용이 증가할 수 있다는 단점이 있다.Next.js를 통한 최신의 방식으로 SSR을 구현할 경우에는 다음과 같은 단점이 있다.첫째, hydration을 통해 동적인 화면으로 전환할 경우 상호작용 초기화가 비교적 느리다. 이는 페이지가 표시되기까지 걸리는 시간(TTV)과 상호작용까지 걸리는 시간(TTI) 사이에 격차가 발생한다는 의미이다. 그 사이에 사용자가 버튼을 클릭해도 동작하지 않는 등의 답답한 상황을 겪을 수 있다.둘째, 상대적으로 구현 복잡도가 높다. 현대의 웹앱은 SSR과 CSR을 동시에 사용하는 경우가 많다. 이때 클라이언트 사이드 로직과 서버 사이드의 로직을 구분해가면서 구현해야 하기 때문에 상대적으로 구현 복잡도가 높다.

2026. 01. 03

SSR(Server Side Rendering)이란?
archive

Next.js 폴더 구조 파악하기

Next.js 폴더 구조, '정답'은 없었다. 내가 놓치고 있던 5가지 핵심 원칙Next.js로 프로젝트 처음 시작할 때, 다들 비슷한 고민 한 번쯤은 해봤을 거다. "컴포넌트는 어디다 둬야 하지? lib 폴더는 app 안에 넣나, 밖에 빼나? 대체 어떻게 정리해야 나중에 고생 안 할까?"나도 깔끔하고 확장성 있는 구조를 만들고 싶어서 정답을 찾아 헤맸는데, 생각보다 그 길은 잘 안 보이지 않았다. 그런데 공부하다 보니 문득 이런 생각이 들었다. 만약 Next.js가 의도적으로 '정답'을 정해두지 않은 거라면?사실 Next.js는 특정 구조를 강요하기보다 개발자한테 엄청난 유연성을 주는 프레임워크다. 공식 문서 곳곳에 숨겨져 있지만 의외로 많은 사람들이 놓치는, 강력하고도 반직관적인 5가지 핵심 원칙을 정리해 봤다. 이 글을 다 읽고 나면 폴더 구조에 대한 막막함이 "이렇게 짜면 되겠구나"라는 자신감으로 바뀔 거라고 예상한다.1. Next.js는 원래 '독선적이지 않다' Next.js 폴더 구조를 이해하려면 이 녀석의 근본 철학부터 알아야 하는데 Next.js는 프로젝트 파일을 어떻게 구성하든 크게 간섭하지 않는 '독선적이지 않은' 입장을 취해. 공식 문서에도 작성되어있다.Next.js is unopinionated about how you organize and colocate your project files.이건 그냥 방치하는 게 아니라, 프로젝트가 작은 프로토타입에서 거대한 엔터프라이즈 앱으로 성장할 때 개발자가 상황에 맞춰 최적의 전략을 선택할 수 있게 자율성을 존중해 주는 거야. 이 철학만 이해해도 구조 짜는 게 훨씬 자유로워진다. 내가 생각한 폴더 구조가 맞다고 할 수 있고 사수나 동료가 생각한 폴더구조가 맞을 수 있다는 것이다. 상황에 맞게(자유롭게) 구조를 잡으면 된다 이 말이다.2. 폴더가 곧 라우트는 아니다.예전의 파일 기반 라우팅 시스템은 '폴더 = URL 경로'라는 공식이 강했지. 하지만 Next.js App Router에서는 이 고정관념을 깨야 한다 app 디렉토리 안에 폴더를 만든다고 무조건 URL이 생기는 게 아니란 말이다.라우트는 오직 해당 폴더 안에 page.js나 route.js가 있을 때만 활성화가 된다.이 단순한 규칙 덕분에 '코로케이션(Colocation)'이라는 강력한 패턴이 가능해져. 예전엔 컴포넌트 하나 수정하려면 components 폴더랑 pages 폴더를 왔다 갔다 하느라 정신없었는데 이제는 특정 페이지에서만 쓰는 UI 컴포넌트, 커스텀 훅, 스타일, 테스트 파일을 그냥 그 페이지 폴더 안에 같이 둬도 된다는 말! 관련 코드들이 한곳에 모여 있으니까 응집도도 높아지고 유지보수도 훨씬 편해지는 장점이 생긴거다. 이제 부터 app 라우터 기준 폴더가 주는 의미를 알아보자3. 괄호 ()로 URL 영향 없이 그룹화하기 (Route Groups)프로젝트가 커지면 라우트들을 논리적으로 묶고 싶어질 때가 있다. 예를 들어 마케팅 페이지, 쇼핑몰 페이지, 관리자 페이지를 구분하고 싶을 때 말이야. 이때 ()괄호형태 폴더명이 필요하다.폴더 이름을 (marketing) 처럼 괄호로 감싸면, 이 폴더는 URL 경로에는 전혀 영향을 주지 않으면서 관련된 라우트들을 정리하는 논리적인 그룹 역할만 한다 말 그대로 그룹핑!! 피그마 처럼 그룹으로 감싼다는 의미로 생각하면 이해가 편하다.섹션별 정리: (marketing), (shop), (admin)으로 나눠서 구조를 한눈에 파악.특정 그룹만 레이아웃 적용: (shop) 폴더 안에 layout.js를 두면 장바구니나 결제 페이지 같은 쇼핑몰 관련 페이지들만 특정 레이아웃을 공유하게 할 수 있다.특정 페이지에만 로딩 UI: 예를 들어 app/dashboard/(overview)/ 처럼 만들고 그 안에 loading.js를 넣으면, URL은 /dashboard/overview로 깔끔하게 유지되면서 로딩 스켈레톤은 딱 그 페이지에만 적용할 수 있다.4. 밑줄 _로 라우팅에서 완전히 제외하기 (Private Folders)라우팅이랑 상관없는 파일들을 완벽하게 분리하고 싶다면 '프라이빗 폴더(Private Folders)'를 쓰면 된다. 폴더 이름 앞에 밑줄을 붙여서 _folderName으로 만들면 Next.js 라우팅 시스템이 이 폴더를 아예 무시해버려.역할 분담: 라우팅과 상관없는 공용 컴포넌트나 라이브러리를 _components, _lib에 담아서 역할과 책임을 명확히 분리할 수 있다.충돌 방지: 나중에 Next.js에 새로운 파일 규칙(예: analytics.js)이 생기더라도 _로 시작하는 폴더 안에 있으면 이름이 겹칠 걱정이 없다.여기서 핵심! 코로케이션은 특정 페이지 전용 파일을 위한 거고, 프라이빗 폴더는 여러 라우트에서 공유하지만 특정 라우트 세그먼트는 아닌 공통 자산을 위한 거다.

2025. 12. 28

Next.js 폴더 구조 파악하기
archive

App Router: 서버 컴포넌트, 제약사항과 주의점

개발을 하다 보면 웬만한 건 다 안다고 생각할 때가 있는데, 기술은 정말 끝이 없다. 최근 Next.js의 App Router로 마이그레이션을 진행하면서 수많은 "빨간 줄(에러)"과 싸웠다.단순히 "서버에서 렌더링 된다"를 넘어서, 도대체 뭘 쓸 수 있고 뭘 쓸 수 없는지, 그리고 "실수하기 딱 좋은 함정"들이 무엇인지, 내가 겪은 시행착오를 바탕으로 상세하게 정리해 본다.1. 서버 컴포넌트(RSC), 다시 보자기본 개념은 간단하다. "서버에서 돌고, 결과물(HTML/JSON)만 브라우저로 보낸다." 하지만 이게 가져오는 파급력은 생각보다 크다. 왜 굳이 이걸 쓸까? (장점 심화)Zero Bundle Size: 서버 컴포넌트 내부에서만 쓰이는 라이브러리(예: 마크다운 파서, 날짜 변환기 등)는 브라우저 번들에 포함되지 않는다.보안: API Key나 민감한 토큰이 브라우저로 노출될 일이 없다. 서버에서 다 처리하니까.2. 절대 쓰면 안 되는 것들 (제약 사항)서버 컴포넌트는 리액트 컴포넌트지만, "리액트 훅(Hook)"을 쓸 수 없다. 이 부분이 가장 헷갈렸다. 2-1. State와 Lifecycle 관련 Hooks 사용 불가 서버는 요청을 받으면 컴포넌트를 한 번 딱 실행해서 결과를 보내고 끝이다. "상태(State)"를 유지하거나, "마운트 된 후(Effect)"라는 개념 자체가 없다.useState, useReducer (X)useEffect, useLayoutEffect (X)useRef (X) - 렌더링 결과물에 영향 없는 변수는 쓸 수 있지만, DOM 접근용으론 불가. 2-2. 브라우저 전용 API 사용 불가 서버(Node.js 환경)에서 돌기 때문에 브라우저 객체는 당연히 없다.window, document, navigator (X)localStorage, sessionStorage (X)onClick, onChange 같은 이벤트 핸들러 (X)3. 실수하기 딱 좋은 포인트 (주의점 & 패턴)이론은 알겠는데 막상 코드를 짜다 보면 마주치는 에러들이다.주의점 1: Props 직렬화(Serialization) 문제 서버 컴포넌트에서 클라이언트 컴포넌트로 데이터를(props) 넘길 때, 그 데이터는 반드시 네트워크를 탈 수 있는 형태(직렬화 가능)여야 한다.가능: string, number, array, object (JSON 가능한 것들)

2025. 12. 26

App Router: 서버 컴포넌트, 제약사항과 주의점
archive

Tanstack Query - useMutation!!!

오늘은 내가 직접 삽질하며 깨달은 useQuery와 useMutation 그리고 왜 이게 선택이 아닌 필수인지 아주 상세하게 정리해본다.useMutation 반환 메소드 요약TanStack Query(React Query)의 useMutation이 반환하는 객체에는 실제 동작을 트리거하거나 제어하는 3가지 핵심 메소드가 포함되어있다.1. mutate가장 기본적으로 사용되는 실행 함수특징: 호출 후 아무것도 반환하지 않음 (void).에러 처리: 내부적으로 에러를 잡아두기 때문에 호출부에서 try...catch를 사용할 필요 없음 대신 onError 콜백을 통해 에러 처리용도: 일반적인 UI 이벤트(버튼 클릭 등)에서 가볍게 요청을 보낼 때 사용2. mutateAsyncPromise를 반환하는 비동기 실행 함수특징: 성공 시 데이터, 실패 시 에러를 담은 Promise를 반환에러 처리: 호출부에서 직접 async/await와 try...catch를 사용하여 비동기 흐름을 제어할 수 있음용도: 뮤테이션 실행 후 연쇄적인 비동기 작업이 필요하거나, 여러 개의 뮤테이션을 순차적으로 실행해야 할 때 사용3. reset뮤테이션의 모든 상태를 초기화하는 함수특징: data, error, isPending, isSuccess 등 해당 뮤테이션이 가졌던 상태를 모두 'idle' 상태로 되돌린다용도:4. 라이프사이클 콜백뮤테이션의 각 단계에 개입해서 특정 로직을 실행할 수 있음.onMutate: 뮤테이션이 시작되기 직전에 실행돼. (예: 낙관적 업데이트-Optimistic Update 할 때 미리 UI를 바꿔두는 용도)onSuccess: 성공했을 때 실행. (예: 쿼리 무효화-Invalidation를 통해 목록 새로고침)onError: 실패했을 때 실행. (예: 에러 알림 띄우기)onSettled: 성공하든 실패하든 상관없이 마지막에 무조건 실행. (예: 로딩 상태 해제)5. 코드예시

2025. 12. 22

Tanstack Query - useMutation!!!

© 2023 돌멩이.