<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hi-rachel.log</title>
        <link>https://velog.io/</link>
        <description>기존 블로그: https://hi-rachel.tistory.com, 이주 중 🏡 bitbetter.vercel.app</description>
        <lastBuildDate>Tue, 17 Mar 2026 10:05:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hi-rachel.log</title>
            <url>https://velog.velcdn.com/images/hi-rachel/profile/19ed55d8-cd8e-4985-be56-0185e8ed0be7/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hi-rachel.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hi-rachel" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[AI 인사이트 2]]></title>
            <link>https://velog.io/@hi-rachel/AI-%EC%9D%B8%EC%82%AC%EC%9D%B4%ED%8A%B8-2</link>
            <guid>https://velog.io/@hi-rachel/AI-%EC%9D%B8%EC%82%AC%EC%9D%B4%ED%8A%B8-2</guid>
            <pubDate>Tue, 17 Mar 2026 10:05:32 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hi-rachel/post/7ec0ca6d-e252-40b6-b5ac-023405687a97/image.jpg" alt=""></p>
<h1 id="지식인사이드-내용-정리">지식인사이드 내용 정리</h1>
<ul>
<li><strong>영상</strong>: <a href="https://www.youtube.com/watch?v=512LLypVJfQ">“일해서 돈버는 시대 끝났다.” AI시대 몸값 폭등하는 사람의 특징ㅣ지식인초대석 EP.100 (김대식 X 오건영)</a></li>
</ul>
<blockquote>
<p>단순히 &#39;기본소득 시대가 온다&#39;는 수준이 아니라, 그동안 어떤 구체적인 논의와 아이디어들이 있었는지(UBS, UBE, UBC 등)를 알 수 있어서 흥미로웠습니다. 에이전틱 AI의 확산과 함께 NPU, LPU, HBF 같은 새로운 반도체에 대한 정보도 얻을 수 있었습니다.</p>
</blockquote>
<p>집에서 지식인사이드를 통해 이런 정보를 무료로 들을 수 있는 것도 좋은데, AI를 써서 요약까지 몇 분 안에 끝낼 수 있는 시대가 됐네요. 다만 더 깊이 이해하고 구체적인 정보를 얻고자 한다면 영상을 보는걸 추천드립니다. 저 역시 영상을 본 후 정리와 기억 보조 용도로 AI 요약을 함께 활용합니다.</p>
<h2 id="한-줄-요약">한 줄 요약</h2>
<p>AI가 “도구”를 넘어 “일을 수행하는 주체(에이전트)”로 진화하면서, <strong>개인의 몸값은 ‘내가 직접 일하는 능력’만이 아니라 ‘AI+자본/시스템을 결합해 성과를 내는 능력’</strong>에서 갈린다는 메시지.</p>
<h2 id="핵심-메시지요약">핵심 메시지(요약)</h2>
<ul>
<li><strong>에이전틱 AI의 본질</strong>: “검색/추천”에서 끝나는 게 아니라, 예약·입력·결제 등 <strong>실제 업무 절차를 대신 수행</strong>하는 단계로 간다. 중개/대행/사무형 업무부터 충격이 온다.</li>
<li><strong>고용소득 비중 하락, 자본소득 중요도 상승</strong>: 앞으로는 “일해서 버는 돈”의 비중이 줄고, <strong>자본(투자)에서 오는 소득의 영향이 커지는 구조</strong>를 강조한다.</li>
<li><strong>AI 투자 프레임 전환</strong>: “AI 기업만 사면 되나?”가 아니라, <strong>AI 인프라(예: 데이터센터·HBM·GPU·NPU 등) + 기존 산업(구경제)의 생산성 개선</strong>까지 시야를 넓혀야 한다.</li>
<li><strong>구경제×신경제 결합의 재평가</strong>: 자동차·유통 같은 전통 산업도 AI(특히 물리/피지컬 AI, 자동화)와 결합하면 <strong>가치평가(멀티플) 확장</strong>이 일어날 수 있다는 관점 제시.</li>
<li><strong>‘AI 전문가’도 안전지대가 아님</strong>: 기술 변화 속도가 빨라져, 기존 역할(개발/AI 관련 직무)도 <strong>먼저 대체·재편될 수 있다</strong>는 경고성 문제의식으로 대화를 연다.</li>
</ul>
<h2 id="흐름대로-정리논점">흐름대로 정리(논점)</h2>
<h3 id="에이전틱-ai가-바꾸는-것-정보가-아니라-행동">에이전틱 AI가 바꾸는 것: “정보”가 아니라 “행동”</h3>
<ul>
<li>단순히 “유럽 비행기 알아봐” 같은 요청에 <strong>정보를 나열하는 AI</strong>가 아니라,</li>
<li>실제로 사이트에 들어가 <strong>버튼을 누르고, 빈칸을 채우고, 결제를 완료</strong>하는 AI가 되면</li>
<li>사람/업종이 하던 <strong>대행·중개 기능 자체가 줄어든다</strong>는 설명.</li>
</ul>
<h3 id="돈소득의-구조-변화-노동-→-자본의-비중-확대">돈(소득)의 구조 변화: 노동 → 자본의 비중 확대</h3>
<ul>
<li>고용을 통해 얻는 <strong>노동(고용) 소득의 비중이 낮아질 수 있다</strong>는 전망.</li>
<li>반대로 <strong>자본 소득(투자 소득)의 중요도가 높아진다</strong>는 관점을 반복적으로 강조.</li>
<li>개인 입장에선 “일을 더 열심히”만으로 방어가 어렵고, <strong>자본·기술·레버리지 구조</strong>를 이해해야 한다는 결론으로 이어짐.</li>
</ul>
<h3 id="기본소득ubi-논의-현금-지급만이-답이-아닌-이유--대안들">기본소득(UBI) 논의: “현금 지급”만이 답이 아닌 이유 + 대안들</h3>
<ul>
<li>“노동과 상관없는 소득의 길”이 필요하다는 맥락에서, 흔히 거론되는 해법이 <strong>(1) 투자(주식) (2) 기본소득</strong>이라고 정리한다.</li>
<li>다만 <strong>UBI(현금 지급)</strong>는 사람들의 사용 행태/사회적 부작용(자막 표현상 “돈을 주면… 난리가 난다”) 같은 이유로 <strong>문제가 있을 수 있다</strong>고 지적한다.</li>
<li>그래서 “두 가지(투자/기본소득)”를 넘는 접근으로, <strong>돈을 직접 주기보다 ‘기본 서비스’를 제공하자(UBS)</strong>라는 아이디어를 소개한다.<ul>
<li><strong>UBS(Universal Basic Services)</strong>: 국가가 모든 사람에게 최소한의 서비스를 제공해 <strong>생존/기본 생활을 ‘현금’이 아니라 ‘서비스’로 보장</strong>하자는 방식.</li>
</ul>
</li>
<li>또 다른 대안으로 <strong>UBE/기본 주식</strong> 같은 “기본 자본” 아이디어를 언급한다.<ul>
<li><strong>기본 주식</strong>: 18세가 되면 국가가 <strong>기본으로 주식을 나눠주자</strong>는 발상(자본소득의 출발점(시드)을 넓히는 접근).</li>
<li><strong>컴퓨트 지분 아이디어(자막: UBC)</strong>: 데이터센터의 <strong>GPU(계산능력) 지분을 18세에 일정 비율로 배분</strong>하자는 식의 구상도 언급된다. 개인은 그 컴퓨트를 창작/창업/거래 등 다양한 방식으로 활용할 수 있다는 논리.</li>
</ul>
</li>
</ul>
<h3 id="투자-관점의-핵심-ai-테마가-아니라-체인연쇄으로-보기">투자 관점의 핵심: AI ‘테마’가 아니라 ‘체인(연쇄)’으로 보기</h3>
<ul>
<li>AI 낙관론(생산성 상승 → 모두 행복)만으로는 부족하고,</li>
<li>투자 관점에선 <strong>AI가 필연적으로 요구하는 것(인프라/전력/데이터센터/메모리 등)</strong>,</li>
<li>그리고 <strong>AI가 기존 산업의 생산성을 끌어올리는 구간(유통, 제조, 모빌리티 등)</strong>을 함께 봐야 한다는 프레임.</li>
</ul>
<h3 id="구경제도-ai로-재평가된다">“구경제도 AI로 재평가된다”</h3>
<ul>
<li>“자동차는 구경제” 같은 단순 분류가 아니라,</li>
<li>AI(특히 피지컬 AI)와 접목되면 <strong>기업을 바라보는 관점 자체가 달라지고</strong>,</li>
<li>그 결과 시장에서 <strong>가치평가가 확장(멀티플 확장)</strong>될 수 있다는 논리.</li>
</ul>
<h2 id="내가-가져갈-체크리스트실천">내가 가져갈 체크리스트(실천)</h2>
<ul>
<li><strong>업무 관점</strong>: 내 일이 “정보 제공/정리”에 가까운가, “실행/결정/책임”에 가까운가?</li>
<li><strong>역량 관점</strong>: AI를 ‘툴’로 쓰는 수준을 넘어, <strong>반복 업무를 AI에게 위임해 결과물까지 내는 프로세스</strong>를 만들고 있는가?</li>
<li><strong>소득 관점</strong>: 노동소득만 의존하지 않도록, <strong>저축·투자·현금흐름</strong>을 시스템화하고 있는가?</li>
<li><strong>산업 관점</strong>: AI 기업만 볼 게 아니라, <strong>AI 인프라와 AI로 생산성이 개선되는 기존 산업</strong>을 함께 보고 있는가?</li>
</ul>
<h2 id="10-20대-자산-증식-전략">10-20대 자산 증식 전략</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/2c94c1e9-5e20-4b1e-bf4b-7bddf56f736c/image.png" alt=""></p>
<blockquote>
<p>AI가 일상생활 모든 사람에게 영향을 주려면 5 ~ 10년 정도는 걸릴 것.
지금 시대를 정말 냉철하게 바라보고 인정해라.
앞으로 딱 10 ~ 20년 정도만 골드러시같은 기회가 있을 수 있음. 마지막 기회.
한 사람이 많은 사람이 필요로 하는 서비스를 만들 수 있음 (실패 비용도 점점 줄어듬), 10분의 1의 시간, 비용 투자해 창업 추천 - 김대식 교수님</p>
</blockquote>
<h2 id="키워드">키워드</h2>
<ul>
<li><strong>에이전틱 AI</strong>, <strong>노동소득 vs 자본소득</strong>, <strong>AI 인프라(데이터센터/HBM 등)</strong>, <strong>구경제×AI(피지컬 AI)</strong>, <strong>생산성/가치평가(멀티플)</strong></li>
</ul>
<h2 id="용어-정리">용어 정리</h2>
<ul>
<li><strong>구경제</strong>: 전통 산업/비즈니스(제조, 유통, 자동차 등)처럼 <strong>기존 기술·공정·수요 구조</strong>가 중심인 영역을 가리킬 때 쓰는 표현.</li>
<li><strong>신경제</strong>: 인터넷/소프트웨어/플랫폼처럼 <strong>디지털 기반으로 성장·확장(스케일)</strong>이 빠른 산업을 가리키는 표현(문맥상 AI 산업도 여기에 포함).</li>
<li><strong>멀티플(Multiple)</strong>: 기업가치를 단일 지표로 비교할 때 쓰는 “배수”. 보통 <strong>주가수익비율(P/E), 매출 대비 가치(P/S), EBITDA 대비 가치(EV/EBITDA)</strong> 같은 형태로 말한다.</li>
<li><strong>멀티플 확장(Expansion)</strong>: 시장이 어떤 기업/산업을 더 높은 성장성·수익성으로 평가해 <strong>같은 실적 대비 더 높은 배수(valuation)를 부여</strong>하는 현상.</li>
<li><strong>AI 인프라</strong>: AI를 돌리기 위해 필요한 “기반 시설” 묶음. 예: <strong>데이터센터, 전력/냉각, 네트워크, 반도체(특히 GPU/메모리)</strong>.</li>
<li><strong>데이터센터</strong>: 대규모 서버·스토리지를 모아 운영하는 시설. AI 시대에는 <strong>학습/추론을 위한 GPU 클러스터</strong> 수요가 핵심 이슈로 자주 등장.</li>
<li><strong>HBM(High Bandwidth Memory)</strong>: DRAM을 수직으로 쌓아 GPU 바로 옆에 붙인 <strong>초고속·소용량 메모리</strong>. AI 모델이 커질수록 GPU가 엄청난 양의 데이터를 빠르게 읽고 써야 하는데, 그 역할을 담당한다. 이 영상에서는 “AI 데이터센터 증설 → 메모리 대역폭/용량이 병목”이라는 맥락에서, 지금까지의 핵심 부품으로 언급된다.</li>
<li><strong>HBF(High Bandwidth Flash, 영상/기사 맥락)</strong>: 낸드 플래시(SSD용 저장 칩)를 HBM처럼 수직으로 쌓아, <strong>준고속·대용량 메모리 계층</strong>을 만들려는 차세대 구조를 가리키는 말. HBM이 “초고속·소용량·고비용”이라면, HBF는 “HBM보다 느리지만 충분히 빠른 읽기 속도 + 훨씬 큰 용량 + 낮은 단가”로, 둘 사이의 빈 공간(따뜻한 중간 계층)을 메우는 역할을 한다는 게 핵심 아이디어다. 영상에서는 “HBM 말고 HBF가 필요하다, 그걸 만드는 회사에 투자하는 게 포인트”라는 식으로, <strong>다음 단계 AI 메모리/스토리지 투자 테마</strong>로 언급된다.</li>
<li><strong>GPU(Graphics Processing Unit)</strong>: 원래는 그래픽 처리를 위해 만들어졌지만, 현재는 <strong>대부분의 대규모 AI 모델 학습·추론을 담당하는 기본 가속기</strong>로 쓰인다. 영상에서 말하는 “데이터센터·컴퓨트 인프라 투자”의 중심에 있는 반도체다.</li>
<li><strong>NPU(Neural Processing Unit)</strong>: <strong>신경망 연산에 특화된 전용 칩</strong>. GPU보다 전력 효율·비용에서 유리할 수 있어, 엣지/모바일·온디바이스 AI 확산의 핵심 하드웨어로 거론된다. 즉 “데이터센터 밖의 AI 수요”를 받쳐 줄 반도체라는 맥락이다.</li>
<li><strong>LPU(서로 다른 맥락에서 쓰임)</strong>: 문맥에 따라 다르지만, 최근 AI 맥락에선 <strong>대규모 AI 워크로드에 최적화된 전용 프로세서(예: 특정 기업이 설계한 AI 가속기 브랜드)</strong> 정도를 뜻하는 경우가 많다. 영상에서 강조하는 것은, 이런 전용 가속기들이 등장하면서 “AI 인프라 투자”의 범위가 GPU 한 종류를 넘어 다양한 칩으로 확장되고 있다는 점이다.</li>
<li><strong>에이전틱 AI(Agentic AI)</strong>: 질문에 답만 하는 AI가 아니라, 목표를 주면 <strong>여러 단계를 스스로 실행(클릭/입력/예약/결제 등)</strong>해 결과를 만들어내는 형태의 AI.</li>
<li><strong>UBI(Universal Basic Income, 기본소득)</strong>: 정부가 조건 없이(또는 최소 조건으로) <strong>현금을 정기 지급</strong>하는 정책 아이디어.</li>
<li><strong>UBS(Universal Basic Services, 기본서비스)</strong>: 현금 대신/또는 함께, 국가가 의료·교육·교통·주거 등 <strong>기본 서비스를 보장</strong>하자는 접근.</li>
<li><strong>기본 주식/UBE(문맥상)</strong>: 성인이 될 때 국가가 <strong>기본 자본(예: 주식)을 배분</strong>해 자본소득의 출발점을 넓히자는 아이디어(용어는 논자/맥락에 따라 다르게 쓰일 수 있음).</li>
</ul>
<h3 id="참고">[참고]</h3>
<ul>
<li><p><a href="https://www.youtube.com/watch?v=512LLypVJfQ">https://www.youtube.com/watch?v=512LLypVJfQ</a></p>
</li>
<li><p><a href="https://contents.premium.naver.com/unis/something/contents/260225183905692mz">https://contents.premium.naver.com/unis/something/contents/260225183905692mz</a></p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[개인 기술 블로그 만들기 프로젝트 (BitBetter)]]></title>
            <link>https://velog.io/@hi-rachel/%EA%B0%9C%EC%9D%B8-%EA%B8%B0%EC%88%A0-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-BitBetter</link>
            <guid>https://velog.io/@hi-rachel/%EA%B0%9C%EC%9D%B8-%EA%B8%B0%EC%88%A0-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-BitBetter</guid>
            <pubDate>Thu, 28 Aug 2025 17:06:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hi-rachel/post/5aa3b1a7-779e-4bf2-bbf0-092d1581102d/image.gif" alt=""></p>
<p><a href="https://bitbetter.vercel.app/blog">https://bitbetter.vercel.app/blog</a></p>
<p>티스토리에서 Velog로 2024년 이주했었는데요,
결국 직접 커스텀해서 개발하고 싶은 욕구가 커서 개인 기술 블로그를 만들었습니다.</p>
<p><strong>남과 비교하지 말고 어제의 나보다 1%씩 더 성장하자</strong>는 의미로 <strong>Bitbetter</strong>이라고 이름을 지었습니다.</p>
<p>Playlist 추천이나 Github 커밋 패턴 분석 등 재밌는 기능도 있으니 구경하러 와주시면 감사합니다. 아직 부족한 부분도 많지만 피드백도 환영입니다.</p>
<p>블로그는 간단하게 지식 정리하는 글과, 중요 글, 개인 글 등 좀 분리되어서 표시되게 UI를 개선할 예정이고 앞으로 계속 글을 작성할 예정입니다.</p>
<p>Velog도 가끔 찾아주시는 분들이 있어서 여기에도 같은 글을 쓸까, 특정 주제로만 글을 써볼까 고민입니다.</p>
<p>제가 최종으로 만들고 싶은 블로그는 <a href="https://inpa.tistory.com/">인파님 블로그</a> 같은 넣고 싶은 화려한 애니메이션 및 기능들을 다 넣은 공간이에요.</p>
<p>최적화된 SEO와 깔끔한 블로그도 좋다고 생각하지만, 좀 더 눈에 띄는 화면을 만들고 싶은 생각이 있어요.</p>
<p>개인 기술 블로그 만들기 전 다른 블로그들 많이 구경했는데, 개인적인 블로그 만들어보고 싶으신 분들 있으시면 참고해보면 좋을 것 같아 목록 첨부해봅니다. 티스토리에서 커스텀 적용하시는 분들도 많이 봤습니다.</p>
<h2 id="멋진-블로그들">멋진 블로그들</h2>
<p><a href="https://inpa.tistory.com/">https://inpa.tistory.com/</a></p>
<p><a href="https://parksb.github.io/articles.html">https://parksb.github.io/articles.html</a></p>
<p><a href="https://zerolog.vercel.app/posts">https://zerolog.vercel.app/posts</a></p>
<p><a href="https://rauchg.com/">https://rauchg.com/</a></p>
<p><a href="https://www.daleseo.com/">https://www.daleseo.com/</a></p>
<p><a href="https://petefolio.dev/">https://petefolio.dev/</a></p>
<p><a href="https://heropy.blog/">https://heropy.blog/</a></p>
<p><a href="https://pronist.tistory.com/category">https://pronist.tistory.com/category</a></p>
<p>블로그를 만들어 보니 생각보다 넣을 수 있는 기능이 정말 많고 재밌습니다. 저는 IDE에서 드라큘라 테마를 쓰는걸 좋아하고 눈에 익숙한데 블로그 코드 블록을 드라큘라 테마로 설정한거 하나로도 넘 맘에 드네요.</p>
<p>아직 안해보신 분들은 다음 프로젝트는 블로그 커스텀 해보시는거 어떨까요?
꾸준히 글 쓰시는 모든 분들 응원합니다 💪💪💪</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js import 정렬 설정]]></title>
            <link>https://velog.io/@hi-rachel/Next.js-import-%EC%A0%95%EB%A0%AC-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@hi-rachel/Next.js-import-%EC%A0%95%EB%A0%AC-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Wed, 02 Jul 2025 06:30:42 GMT</pubDate>
            <description><![CDATA[<p><strong>BEFORE</strong>
<img src="https://velog.velcdn.com/images/hi-rachel/post/d6b9b15e-29ef-48ca-9e5d-95aa2fbcc361/image.png" alt=""></p>
<p>프로젝트시 은근히 거슬리는 import
저 react를 맨 위로 올리고 싶다!
그동안 크게 영향을 미치는 부분은 아니라 놔두었는데 정렬을 하지 않으면 프로젝트 진행 기간 동안 계속 저렇게 뒤섞이니 설정을 해보기로 합니다.</p>
<p><strong>AFTER</strong>
<img src="https://velog.velcdn.com/images/hi-rachel/post/cd3d6741-de40-4dd5-91db-604f6935e016/image.png" alt=""></p>
<p>한 줄 띄우기는 개인 취향입니다. 예전에 Python 프로젝트 진행시에도 PEP8에서 권장하는 import 순서로 lint를 활용해 설정했었는데, 언어마다 필요한 lint 도구와 추천 스타일이 다릅니다. </p>
<p>이번 포스팅에서는 Next.js 프로젝트에서 Eslint를 활용해 import 정렬하는 법을 배워보겠습니다.</p>
<blockquote>
<p><strong>사용 버전</strong>
&quot;next&quot;: &quot;15.3.1&quot;,
&quot;react&quot;: &quot;^19.1.0&quot;,
&quot;@eslint/eslintrc&quot;: &quot;^3.3.1&quot;,
&quot;eslint&quot;: &quot;^9.27.0&quot;,
&quot;eslint-config-next&quot;: &quot;15.3.1&quot;,
&quot;eslint-plugin-simple-import-sort&quot;: &quot;^12.1.1&quot;,</p>
</blockquote>
<p>최근에 만들고 있는 블로그라 Next.js 15버전을 사용했습니다.</p>
<hr>
<h2 id="1-패키지-설치">1. 패키지 설치</h2>
<p>정렬에는 <a href="https://github.com/lydell/eslint-plugin-simple-import-sort/">eslint-plugin-simple-import-sort</a>을 사용해줬습니다.</p>
<p><a href="https://github.com/import-js/eslint-plugin-import">eslint-plugin-import</a>를 사용해도 되지만 위에 패키지가 좀 더 간편하게 설정할 수 있어 사용했습니다.</p>
<pre><code>pnpm add -D eslint-plugin-simple-import-sort</code></pre><p>개발 의존성으로 패키지를 설치해줍니다. 각 패키지매니저에 맞는 명령을 사용해 주세요.</p>
<h2 id="2-eslint-설정">2. ESLint 설정</h2>
<p>최신 ESLint (v9+)는 eslint.config.js 또는 .mjs 형식의 Flat Config를 사용합니다. 저는 eslint.config.mjs 파일에서 아래와 같이 설정했습니다.</p>
<pre><code class="language-js">import { FlatCompat } from &quot;@eslint/eslintrc&quot;;
import { dirname } from &quot;path&quot;;
import { fileURLToPath } from &quot;url&quot;;

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const compat = new FlatCompat({
  baseDirectory: __dirname,
});

const simpleImportSort = (await import(&quot;eslint-plugin-simple-import-sort&quot;))
  .default;

const eslintConfig = [
  ...compat.extends(&quot;next/core-web-vitals&quot;, &quot;next/typescript&quot;),
  {
    plugins: {
      &quot;simple-import-sort&quot;: simpleImportSort,
    },
    rules: {
      &quot;simple-import-sort/imports&quot;: [
        &quot;error&quot;,
        {
          groups: [
            // React &amp; Next.js
            [&quot;^react&quot;, &quot;^next&quot;],
            // External packages
            [&quot;^@?\\w&quot;],
            // Absolute imports (like @/components)
            [&quot;^(@|~)/&quot;],
            // Relative imports
            [&quot;^\\.&quot;],
            // Style imports
            [&quot;^.+\\.s?css$&quot;],
          ],
        },
      ],
      &quot;simple-import-sort/exports&quot;: &quot;error&quot;,
    },
  },
];

export default eslintConfig;
</code></pre>
<p>rules는 원하는대로 수정해서 사용하면 됩니다.</p>
<p>설정후, 아래 명령어로 전체 파일을 정리할 수 있습니다.</p>
<pre><code>pnpm exec eslint . --fix</code></pre><p>하지만 매번 명령어를 실행하기는 번거로우니 3번으로 갑니다.</p>
<h2 id="3-vscode-설정">3. VSCODE 설정</h2>
<p>&#39;Cmd + Shift + P&#39; (Ctrl + Shift + P on Windows)를 눌러 <strong>Preference: Open User Settings(JSON)</strong>을 클릭해 settings.json 파일을 엽니다.</p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/45ac9888-61d5-45b1-9549-f5193de04d86/image.png" alt=""></p>
<p>다음 설정 코드를 추가합니다.</p>
<pre><code>  &quot;editor.codeActionsOnSave&quot;: {
    &quot;source.fixAll.eslint&quot;: &quot;true&quot;
  },</code></pre><p>끝!</p>
<p>혼자 개발할 때도 다른 사람과 같이 코드를 짠다면 상대방도 보기 편하게 짜려고 항상 노력합니다. 환경 설정은 번거롭지만 한 번 설정해놓으면 프로젝트 전반에 일관성과 편리함을 제공합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[요즘 하는 생각, AI 인사이트 추천]]></title>
            <link>https://velog.io/@hi-rachel/%EC%9A%94%EC%A6%98-%ED%95%98%EB%8A%94-%EC%83%9D%EA%B0%81-AI-%EC%9D%B8%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%B6%94%EC%B2%9C</link>
            <guid>https://velog.io/@hi-rachel/%EC%9A%94%EC%A6%98-%ED%95%98%EB%8A%94-%EC%83%9D%EA%B0%81-AI-%EC%9D%B8%EC%82%AC%EC%9D%B4%ED%8A%B8-%EC%B6%94%EC%B2%9C</guid>
            <pubDate>Sat, 22 Mar 2025 10:43:06 GMT</pubDate>
            <description><![CDATA[<h2 id="요즘-하는-생각">요즘 하는 생각</h2>
<p>요즘 점심 시간에 &#39;최성운의 사고실험&#39; 유튜브를 보며 밥먹는게 하나의 낙이 되었다. (밑에 추천 영상에는 포함되지 않았지만 그냥 다 추천해서 그렇다.)
보고 싶은 영상이 있으면 &#39;나중에 보기&#39;에 담아놓고 이동 시간, 준비 시간, 밥 먹을 때, 자기 전 꺼내 보는 재미가 있다. 라디오처럼 틀어놓고 다른 일도 하기도 하는데 요즘 재밌는 것들이 너무 많아서 시간날 때 제대로 몰입해서 시청한다. 너무 흥미가 있는 영상을 발견하면 굉장히 신나서 영상을 담아놓는데 시청할 생각에 되게 신나하는 내 모습을 보며 놀랐다. 5차 산업혁명 시대에 새롭고 재밌는게 너무 많이 나와서 그렇다고 생각한다.</p>
<p>굳이 돈을 내고 강의를 듣지 않아도 유튜브에 너무 유익한 지식을 얻을 수 있는 영상들이 너무 많다.
아주 공부 많이 하신 분들이 공짜로 인사이트, 경험을 전달해주는 참 좋은 시대다.</p>
<p>그 중 요즘에 내가 재밌게 본 AI 관련 영상들을 추천하고자 한다.
개발자면 &#39;AI에 대체될거라고 생각하느냐? 요즘 어떠냐?&#39; 이런 질문을 자주 받을 수도 있는데, 실제로 많이 자료를 찾아보고 실제 실무에서 일하다 보면 자신의 생각을 갖게 된다.</p>
<hr>
<h2 id="ai-관련-추천-영상">AI 관련 추천 영상</h2>
<iframe width="560" height="315" src="https://www.youtube.com/embed/HYFslPN7n9o?si=q_fzWM4RVsJXQDZo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

<blockquote>
<p>⭐️ <strong>강추</strong>
나는 겨우 약 2년 전 부트캠프에서 GPT를 활용하기 시작하면서 AI 활용을 하기 시작했는데,
이런 미래를 아주 예전부터 굉장히 구체적으로 예측하고 준비했다는 부분이 놀라웠다.
창업 스토리도 아주 재밌고, 대표님이 말씀하시는 인공지능 시대가 많은 예측들 중 가장 현실에 가깝다고 생각한다. 
검색을 구글 검색창 대신, AI로 하는 시대. 팩트 체크에만 구글링 활용.</p>
</blockquote>
<iframe width="560" height="315" src="https://www.youtube.com/embed/0KDosjF0iYM?si=Sn1TsqyFP8-HrZRU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

<blockquote>
<p><strong>굳이 개발자가 아니라도 보기 좋은 영상</strong></p>
<p><strong>CES(Consumer Electrics Show_세계 최대 규모의 IT·전자 전시회)</strong>
(스마트 안경 나오면 써보고 싶다)
최근 피부과에 갔다가 CES에서 나온 제품들 소개하는 잡지를 봤었는데, 거기 입에 물면 소금맛이 나서 나트륨 섭취를 줄여주는 숟가락, 레이저를 이용한 바늘 없는 주사 등 아주 신기하고 놀라운 제품들이 많았다. 평소 그런 것들을 찾아보진 않았는데 CES는 꼭 챙겨봐야겠다고 생각했다. 그냥 진짜 공상하듯이 상상하는 기술들이 지금 시대에 현실로 구현되고 있다. 이러다 투명 인간도 나올듯?</p>
<p><strong>요즘 핫한 MCP</strong>
AI가 하도 빠르게 발전해서 방송 전 내용을 계속 업데이트해야 됐다고 하는데 그래서인지 비교적 최근 핫한 MCP 얘기도 나온다.
로컬 환경의 프로그램들에 AI가 직접 접근해 일을 해준다.
이런거 당연히 나올 줄 알았는데 생각보다 빨리 나왔다.
활용하면 DB 관리가 굉장히 쉬워질 것 같고, 특정 일들은 정말 자동화되고 인력이 필요없겠다.</p>
<p><strong>할루시네이션</strong>
자꾸 거짓말하는 GPT 짜증날 때도 있는데 &#39;<strong>할루시네이션은 오류가 아니라 특성이다</strong>&#39; &#39;<strong>인간이 창의적인 생각을 하기 위해서 상상력을 가지고 몽상도 하듯 할루시네이션은 AI가 창의적 동작을 하기 위한 동전의 뒷면이다.</strong>&#39;라는 얘기는 처음 듣는 얘기라 새로운 인사이트가 되었다.
엉뚱한 생각도 많이 하는 MBTI N 인간으로서 맞는 얘기 같다. 실제로 내 뇌를 들여다 봐도 이상한 생각 많이 하다가 갑자기 좋은 아이디어가 떠오르기도 하고, 문제 해결에 도움이 된 경험도 있다.
그래도 AI가 많이 발전하면 허언증처럼 거짓말을 사실처럼 막 꾸며서 말하기보다 거짓말은 &#39;거짓말 딱지&#39;를 붙여서 구분할 수 있었으면 좋겠다. (지금은 쓰다보면 거짓말 정말 많이 함)</p>
<p><strong>쓰레기를 넣으면 쓰레기가 나온다(Garbage in, garbage out)</strong>
&#39;<strong>책을 많이 읽고 질문을 잘 하자.</strong>&#39;
수술을 대신해주는 로봇이 현재 실제로 쓰이고 있는데 관리와 명령은 정해진 의사, 의료진들이 하는 것처럼 현재 개발도 비슷하다고 생각한다.
나도 사전 개발 지식이 있어서 그것에 대한 질문과 명령을 하는거지 아무 관심이 없었으면 이만큼 활용하지 못했다.
완전 대체 수준이 언제 올지 모르겠지만? 지금은 일을 대신 해주는 느낌. (돈값 이상 한다)
내가 개발 공부하는 것도 어떻게 제대로 일을 시킬지를 공부한다는 느낌이 많이 든다.
활용하는 사람에 따라 생산성이 천차만별인 AI.</p>
</blockquote>
<iframe width="560" height="315" src="https://www.youtube.com/embed/-YlqL6YwwMs?si=r2mbm-gat5Z5qzan" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

<blockquote>
<p>위 영상을 보니 추천해준 알고리즘</p>
<p><strong>AI는 증폭기다.</strong> 작은 능력차도 크게 차이나게 됨.
신입이 점점 필요없는 시대가 됨.</p>
</blockquote>
<iframe width="560" height="315" src="https://www.youtube.com/embed/w2c1XclG4U0?si=kN1zaPgbXOL_nUus" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

<blockquote>
<p><strong>방산 기업 AI</strong></p>
<p>이전 포스팅에서도 썼지만 나는 TV가 없고 뉴스도 그동안 잘 안봐서 방산 산업에 AI가 이렇게 도입된 사실을 이 영상을 보고 처음 알았는데 충격이었다.
아직까지 &#39;AI 로봇이 전쟁 상황에서 반대편 인간을 죽여도 되냐 안되냐&#39;의 도덕적, 철학적 논의가 이루어지고, 관련 규제들을 만들고 있는 정도인줄 알았는데 오류율이 있는 AI도 그냥 전쟁 승률이 있으면 투입해서 사람을 죽이고 있었다니.. 😵
처음 구글도 직원들의 반대에 방산 사업 참여를 하지 않았지만, 현재는 하고 있는 모습에 이제는 전쟁에 AI 활용을 반드시 할 수 밖에 없는 시대가 왔구나 느낀다.. 피할 수 없다면 정말 많이 발전시켜 피해를 줄이고, 전세계적으로 강력한 법률들이 생겨 적용되면 좋겠다.
전쟁하지 않고 평화가 찾아오길.. 🙏</p>
</blockquote>
<p>+) 3/30일 추가
!youtube[HKFeEnDgBMc?si=e0M5xhbwRNzmIpyl]</p>
<blockquote>
<p><strong>이미지 학습 nono~ 이젠 월드 모델</strong>
월드 모델 개념을 들으니 생각보다 빠른 시간 내에 자율 주행이 실현될 수 있겠다 생각이 들었다.
조용히 엔비디아 주식을 샀다..</p>
</blockquote>
<hr>
<h3 id="내-생각"><strong>내 생각</strong></h3>
<blockquote>
</blockquote>
<p>5차 산업 혁명이 이미 시작되었다고 생각하고, 이제 점점 더 과도기가 올 것이다.
실제 사람과 구분할 수 없는 목소리, 영상, 홀로그램, 대화, 텍스트 등등 많은 부분이 사회의 혼란을 가져올 것이고, 갑자기 직업을 잃어버린 사람들로 인한 문제들이 발생할 것이다.
물론 이때 더 이득을 얻고 성장하는 사람들도 있을 것이다.
달라질 미래에 대비하고 공부하자.</p>
<blockquote>
<p>내가 뉴스를 안보던 이유는 쓸데없는 가짜뉴스, 연예인 가십, 머리 아픈 이슈들 등등 보다 보면 시간 낭비만 되고 내 삶에 도움이 되지 않는 것들이 많아서가 컸다.
그런데 요즘은 내 삶에 영향을 미칠 정도로 큰 이슈들이 있고, 실제로 시대가 변하면서 실시간 뉴스에 나오는 대로 내 삶을 변하게 하는 기술들이 나와서 챙겨보며 배우게 된다. 모든 것을 다 볼 수는 없지만 중요한 것들, 내가 활용할 수 있는 것들은 보려고 노력한다. 물론 유튜브로 유익한 영상만 보려고 하고 중간에 숏폼이나 쓸데없는 컨텐츠로 빠지지 않게 조심해야 한다. 물론 힐링으로 토크쇼나 좋아하는 유튜브도 본다 :)</p>
<p>AI로 대체되다 보면 오히려 &#39;사람이 필요하구나&#39;를 느끼게 되기도 한다.
요즘에는 AI로 쓴 글은 약간 티가 나고 특유의 문체가 있는 것 같이 느껴지는데 사람이 온전히 꾹꾹 눌러서 자기 경험, 생각을 쓴 글은 좀 다르다고 생각한다. 미래에 이것까지 대체할 수 있을지는 모르겠지만 지금은 오히려 AI 컨텐츠가 넘쳐나서 사람이 직접 만들고 쓴 글, 컨텐츠들이 역으로 소중해질 때도 많다고 생각한다.</p>
</blockquote>
<hr>
<h3 id="ai를-잘-활용하는-사례">AI를 잘 활용하는 사례</h3>
<p>번역</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/2Uz0wkfVIpU?si=EqJwm4RomL-xgcjk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

<p>해당 분야의 굉장히 뛰어난 사람이 AI 활용과 함께 살아남고, 나머지는 대체될 수 있는 모습.</p>
<hr>
<h3 id="보통-많이-쓰는-ai">보통 많이 쓰는 AI</h3>
<blockquote>
<p>ChatGPT
Claude
Cursor (AI 탑재 IDE)
Cline (IDE 확장 프로그램)
Gemini
Perplexity</p>
</blockquote>
<p>나는 GPT + Claude 유료 결제해서 쓰는데, 요즘 Cursor도 결제해볼까 생각한다.</p>
<hr>
<h3 id="영상에서-배운-용어-정리">영상에서 배운 용어 정리</h3>
<p>AI 특이점: 인공지능이 인간의 지능을 능가하는 시점
AGI(Artificial General Intelligence)_인공종합지능: 한 분야가 아니라 모든 면에서 인간의 지능을 능가하는 AI</p>
<p>AGI의 5단계
<img src="https://velog.velcdn.com/images/hi-rachel/post/6930dca5-52c5-4c1f-9c2e-3989ba5d2021/image.png" alt=""></p>
<blockquote>
<p>출처: <a href="https://www.youtube.com/embed/0KDosjF0iYM?si=Sn1TsqyFP8-HrZRU">해당 영상</a></p>
</blockquote>
<hr>
<p>여러분의 생각은 어떤가요?
빠르게 변화하는 세상이 무섭기도 하지만, 좋은 변화가 되기 위해 노력합시다! 😃</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AI를 활용해 1시간만에 간단 뉴스 서비스 만들기 (feat. Claude, GPT)]]></title>
            <link>https://velog.io/@hi-rachel/AI%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%B4-1%EC%8B%9C%EA%B0%84%EB%A7%8C%EC%97%90-%EA%B0%84%EB%8B%A8-%EB%89%B4%EC%8A%A4-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0-Caude-GPT</link>
            <guid>https://velog.io/@hi-rachel/AI%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%B4-1%EC%8B%9C%EA%B0%84%EB%A7%8C%EC%97%90-%EA%B0%84%EB%8B%A8-%EB%89%B4%EC%8A%A4-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0-Caude-GPT</guid>
            <pubDate>Sat, 15 Feb 2025 12:05:03 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>안녕하세요 🤓 주니어 개발자 Raina입니다.</strong>
정말 AI 기능이 날이면 날마다 발전하고 5차 산업혁명이 온다고 하는게 저는 개발을 하면서 크게 느껴집니다.
매일 개발을 하며 AI를 활용하는데 대답이 날로 발전한다고 느낍니다.
최근 <a href="https://m.post.naver.com/viewer/postView.naver?volumeNo=45698806&amp;memberNo=34635212">Generative AI 2025 코칭 스터디</a>에 참여 하면서 프롬프트 엔지니어링과 AI 활용을 더 잘할 수 있는 방법도 배우고 있는데 1주차 과제가 AI의 미래에 대해 질문하는 것이었습니다.
저는 개발자의 미래도 궁금해 이에 대해 물어봤는데 2030년쯤이면 중급 개발자 정도는 사라질 수 있다고 대답하더라구여
물론 그 다음 살아남으려면 어떻게 해야할지 물어봤지만, AI를 활용하지 못하고 그 이상의 가치를 제공하지 못하는 개발자는 거의 대체될 것은 명확해 보입니다.</p>
</blockquote>
<h2 id="👀-왜-뉴스-서비스">👀 왜 뉴스 서비스?</h2>
<p>굉장히 간단한 서비스이지만, <strong>저는 집에서 TV를 전혀 보지 않습니다.</strong> 아예 연결을 안합니다.
평소에 유튜브나 넷플릭스를 많이 보는데 이는 제가 보는 알고리즘 정도로 추천해주지 세상의 중요한 뉴스를 전해주지는 않습니다.</p>
<p>최근 정말 큰 일인 계엄이 선포되었을 때도, 국가 재난 문자 등이 오지도 않고 저에게 소식이 닿지 않아 모르고 있었습니다.
밤에 유튜브를 내리다가 제가 구독하는 유명한 변호사님이 &quot;<a href="https://www.youtube.com/watch?v=qrCrFwlFptE&amp;ab_channel=%EC%9D%B4%EB%A9%B4%EC%84%9C%EB%8B%A4">변호사가 설명해주는 계엄령</a>&quot;이라는 영상 썸네일을 봤는데 우리나라에 계엄이 선포되었다는 건 꿈에도 몰랐기 때문에 &quot;왜 갑자기 이런거 설명하지?&quot;라고 생각하고 클릭하지 않고 넘어갔습니다. (이후 회사 동료들에 의해 알게되었습니다.)
어쩄든 정치적인 얘기는 제외하고 제가 아무리 TV를 안봐도 가끔 뉴스를 찾아보며 중요한 뉴스는 알고 있어야 겠다고 느꼈습니다.
하지만 네이버 메인 뉴스는 마음에 안드는 컨텐츠들이 많았고, &quot;<strong>정말 간단하게 중요한 헤드라인만 샥 훑고 가기 + 개발 관련 뉴스를 동시에 보고 싶은 니즈</strong>&quot;가 있었습니다. 그래서 제가 평소에 알고 있던 <strong>Open API인 <a href="https://newsapi.org/">News API</a> + <a href="https://news.ycombinator.com/item?id=32540883">Hacker News API</a></strong>를 이용해 각 주요 뉴스를 20개만 가져오는 간단 PWA 앱을 만들었습니다.</p>
<p>그럼 만드는 과정을 살펴볼까요?
정말 간단해 보이지만, 똑똑하게 질문하는 법이 시간을 많이 줄여줄 수 있습니다.</p>
<hr>
<h2 id="🧠-기획-과정">🧠 기획 과정</h2>
<p><strong>First Things First!</strong> 자, 첫번째로 기획을 해야 서비스를 만들겠죠?
참고로 제가 사용한 AI 환경은 다음과 같습니다.</p>
<blockquote>
<p>환경
저는 현재 개발자로 개발시 AI를 많이 활용하기 때문에 GPT, Claud를 유료 결제해 사용합니다.
(유료 결제가 아니신 분도 이렇게 간단한 프로젝트 정도는 중간에 필요없는 질문으로 낭비하지 않는다면 무료로도 가능할 것 같습니다.)
코드 에디터 -&gt; Cursor 사용 (무료 버전 사용, 해당 플젝에 AI 기능 사용 x)</p>
</blockquote>
<p>GPT를 활용해보겠습니다.</p>
<p><strong>Q. NewsAPI , Hacker News API를 이용해 하루 한 번 들어가 주요 뉴스를 살펴보는 웹페이지 혹은 구글 확장 프로그램을 만들거야
기획, 설계 도와줘</strong></p>
<p><strong>A.</strong></p>
<p>하루 한 번 주요 뉴스를 살펴볼 수 있는 웹페이지 혹은 구글 확장 프로그램을 만들기 위한 기획과 설계를 도와드리겠습니다. 이 프로젝트는 NewsAPI와 Hacker News API를 활용하여 최신 뉴스를 사용자에게 제공하는 웹페이지나 확장 프로그램입니다.</p>
<ol>
<li>기획
주요 기능:</li>
</ol>
<ul>
<li>뉴스 카테고리:<ul>
<li>한국 뉴스<ul>
<li>개발 관련 뉴스 (Hacker News 포함)</li>
<li>기타 주요 글로벌 뉴스</li>
<li>자동화된 뉴스 제공:</li>
</ul>
</li>
<li>하루에 한 번 자동으로 주요 뉴스를 불러옵니다.</li>
<li>사용자가 페이지를 열면 최신 뉴스가 바로 표시됩니다.</li>
</ul>
</li>
<li>검색 기능:<ul>
<li>사용자가 뉴스 카테고리나 키워드를 검색하여 필터링할 수 있습니다.</li>
</ul>
</li>
<li>알림 기능 (옵션):<ul>
<li>새로운 주요 뉴스가 있을 때 알림을 제공하여 사용자가 놓치지 않도록 합니다.</li>
</ul>
</li>
</ul>
<p>페이지/구글 확장 프로그램 구조:</p>
<ul>
<li>헤더:
 사이트 로고, 카테고리 선택 (한국 뉴스, 개발 뉴스 등), 검색창</li>
<li>메인 콘텐츠:<ul>
<li>뉴스 리스트 (각 뉴스에 대한 제목, 요약, 출처 등을 표시)<ul>
<li>뉴스 클릭 시 상세 페이지로 이동 (링크)</li>
</ul>
</li>
</ul>
</li>
<li>푸터:<ul>
<li>페이지 정보 (예: 개발자 정보, 사용법)</li>
</ul>
</li>
<li>구글 확장 프로그램:<ul>
<li>확장 아이콘을 클릭하면 팝업 창에서 최신 뉴스 목록을 확인할 수 있게 함.</li>
<li>설정에서 알림을 켜거나 끌 수 있는 옵션 추가.</li>
</ul>
</li>
</ul>
<ol start="2">
<li>설계
기술 스택:</li>
</ol>
<ul>
<li><p>프론트엔드:</p>
<ul>
<li>HTML/CSS: 기본적인 레이아웃과 스타일링.</li>
<li>JavaScript (React.js/Next.js): 동적 뉴스 로딩 및 상태 관리.</li>
<li>API 연동: NewsAPI, Hacker News API를 통해 데이터를 받아와서 표시.</li>
<li>구글 확장 프로그램:<ul>
<li>Manifest V3를 사용하여 확장 프로그램을 설정합니다.</li>
<li>팝업 UI 구현을 위해 React 또는 Vanilla JS를 사용할 수 있습니다.</li>
<li>background.js와 content.js를 사용해 페이지 내용과 인터랙션 처리.</li>
</ul>
</li>
</ul>
</li>
<li><p>백엔드 (옵션):</p>
<ul>
<li>Node.js/Express로 서버를 설정하여, API 요청을 처리하고 데이터를 클라이언트에 전달할 수 있습니다.</li>
<li>Firebase나 Supabase를 사용하여 사용자 정보 관리 (로그인 및 알림 설정 등).</li>
</ul>
</li>
<li><p>데이터 흐름:</p>
<ol>
<li>API 호출:</li>
</ol>
<ul>
<li>페이지 로드 시, NewsAPI와 Hacker News API에서 데이터를 불러옵니다.</li>
<li>사용자가 카테고리나 검색어를 입력하면 해당 API에서 필터링된 뉴스를 반환합니다.</li>
</ul>
<ol start="2">
<li>UI 표시:</li>
</ol>
<ul>
<li>뉴스 목록을 화면에 출력합니다. 각 뉴스 항목은 제목, 요약, 출처 링크 등을 포함합니다.</li>
<li>사용자가 제목을 클릭하면 해당 뉴스 사이트로 이동할 수 있도록 링크를 제공합니다.</li>
</ul>
<ol start="3">
<li>알림 기능 (구글 확장 프로그램):</li>
</ol>
<ul>
<li>사용자가 설정한 조건에 따라, 예를 들어, 하루 한 번 주요 뉴스가 업데이트되면 알림 API를 통해 팝업 또는 알림을 제공합니다.</li>
</ul>
</li>
</ul>
<p>UI/UX 디자인:</p>
<ul>
<li>주요 화면:<ul>
<li>헤더에 카테고리 선택 (한국 뉴스, 개발 뉴스 등)과 검색창을 두어 사용자가 원하는 뉴스를 쉽게 찾을 수 있도록 합니다.</li>
<li>각 뉴스는 제목과 요약을 보여주고, 클릭하면 전체 기사로 이동할 수 있는 링크를 제공합니다.</li>
<li>리스트 뷰로 구현하여, 사용자가 여러 뉴스 항목을 한 번에 볼 수 있게 합니다.</li>
</ul>
</li>
<li>구글 확장 프로그램 UI:<ul>
<li>확장 프로그램 아이콘을 클릭하면 팝업 창이 나타나며, 주요 뉴스 목록을 간단한 카드 형식으로 보여줍니다.</li>
<li>카드에 뉴스 제목, 간단한 설명, 출처 링크를 포함시켜 사용자가 쉽게 클릭할 수 있도록 합니다.</li>
<li>설정 옵션에서 알림을 켜거나 끌 수 있게 합니다.</li>
</ul>
</li>
</ul>
<ol start="3">
<li><p>구체적인 구현 계획</p>
<ol>
<li>API 연동 및 데이터 처리</li>
</ol>
<ul>
<li>NewsAPI와 Hacker News API를 사용하여 데이터를 받아오는 작업을 먼저 합니다.<ul>
<li>fetch() 또는 axios를 사용하여 API 호출을 수행하고, 받은 데이터를 화면에 출력합니다.</li>
</ul>
</li>
</ul>
<p>예시 코드 (NewsAPI)</p>
<pre><code class="language-javascript">const fetchNews = async () =&gt; {
  const response = await fetch(&#39;https://newsapi.org/v2/top-headlines?country=kr&amp;apiKey=YOUR_API_KEY&#39;);
  const data = await response.json();
  return data.articles;
  };

// 뉴스 목록 출력
const displayNews = async () =&gt; {
const articles = await fetchNews();
 articles.forEach(article =&gt; {
 console.log(article.title); // 기사 제목 출력
 });
};</code></pre>
<ol start="2">
<li><p>구글 확장 프로그램 개발</p>
<ul>
<li>manifest.json 설정 (구글 확장 프로그램 필수 설정)</li>
</ul>
<pre><code class="language-json">{
&quot;manifest_version&quot;: 3,
&quot;name&quot;: &quot;Daily News&quot;,
&quot;description&quot;: &quot;Get daily news updates&quot;,
&quot;version&quot;: &quot;1.0&quot;,
&quot;permissions&quot;: [&quot;activeTab&quot;, &quot;notifications&quot;],
&quot;background&quot;: {
&quot;service_worker&quot;: &quot;background.js&quot;
},
&quot;action&quot;: {
&quot;default_popup&quot;: &quot;popup.html&quot;
},
&quot;icons&quot;: {
&quot;16&quot;: &quot;icons/news-16.png&quot;,
&quot;48&quot;: &quot;icons/news-48.png&quot;,
&quot;128&quot;: &quot;icons/news-128.png&quot;
}
}</code></pre>
</li>
</ol>
</li>
</ol>
<ul>
<li><p>팝업 UI (popup.html):</p>
<pre><code class="language-html">&lt;div&gt;
  &lt;h2&gt;Today&#39;s News&lt;/h2&gt;
  &lt;ul id=&quot;news-list&quot;&gt;&lt;/ul&gt;
&lt;/div&gt;</code></pre>
</li>
<li><p>background.js (매일 아침 자동 업데이트)</p>
<pre><code class="language-javascript">chrome.runtime.onInstalled.addListener(() =&gt; {
  fetchNews().then(news =&gt; {
  chrome.storage.local.set({ dailyNews: news });
  });
});</code></pre>
<ol start="3">
<li>알림 기능 (구글 확장 프로그램)</li>
</ol>
<ul>
<li>알림은 구글 확장 프로그램에서 제공하는 chrome.notifications API를 사용하여, 새로운 뉴스가 있을 때 사용자에게 알림을 표시할 수 있습니다.</li>
</ul>
</li>
</ul>
<pre><code class="language-javascript">  chrome.notifications.create({
    type: &#39;basic&#39;,
    iconUrl: &#39;icons/news-128.png&#39;,
    title: &#39;New Daily News&#39;,
    message: &#39;Check out the latest news!&#39;,
    priority: 2
  });</code></pre>
<ol start="4">
<li>배포 및 테스트<ul>
<li>웹페이지 배포: Netlify, Vercel 등 무료 호스팅 서비스를 사용하여 웹페이지를 배포합니다.</li>
<li>구글 확장 프로그램 배포: 크롬 웹스토어에 확장 프로그램을 업로드하여 배포합니다.</li>
</ul>
</li>
</ol>
<ol start="5">
<li>후속 개발 및 개선</li>
</ol>
<ul>
<li>사용자 로그인 기능 추가: 사용자 맞춤형 뉴스 제공을 위해 로그인 기능을 추가할 수 있습니다.</li>
<li>다양한 뉴스 소스 추가: 다양한 뉴스 API를 추가하여 더 많은 출처에서 뉴스를 가져올 수 있습니다.</li>
<li>다국어 지원: 다국어 기능을 추가하여, 다른 언어 사용자들도 이용할 수 있도록 할 수 있습니다.</li>
</ul>
<p>이러한 기획과 설계를 통해, 주요 뉴스 웹사이트나 구글 확장 프로그램을 효율적으로 구축할 수 있을 것입니다. 각 기능을 구체화하고, 사용자에게 유용한 뉴스 서비스를 제공할 수 있습니다!</p>
<blockquote>
<p>-&gt; GPT가 답변을 잘 해줬습니다. 답변 붙여넣기는 들여쓰기가 자동으로 안되기 때문에 조금 보기 불편할 수도 있습니다ㅜ
모든 답변을 붙여넣기는 어렵기 때문에 중요한 부분만 보여드리겠습니다. (이런 부분은 영상으로 만드는게 편할거 같긴 합니다.)</p>
<p>*<em>My Thoughts💡: *</em>저는 시간이 없습니다. 오늘은 주말 토요일인데 다른 할 일도 많기 때문에 오늘 안에 간단히 끝내고 싶습니다.
또한 다른 프로젝트 했던 경험에서 로그인, DB가 들어가는 순간 시간이 오래 걸립니다.
하지만 간단 뉴스 서비스에서는 로그인할 필요가 없고, 저장할 데이터도 없어보입니다.</p>
</blockquote>
<p><strong>Q. 하루 안에 가능하게 해봐</strong></p>
<p><strong>A.</strong></p>
<pre><code class="language-markdown">하루 안에 뉴스 제공 웹사이트 또는 구글 확장 프로그램을 완성하는 것은 매우 빠듯한 일정이지만,
핵심 기능만 최소화하여 작업할 수 있습니다. 이런 경우에는 기본적인 뉴스 제공 시스템만 구현하고, 후속 개선 작업은 지속적으로 진행하는 방식으로 진행할 수 있습니다.

1. 핵심 목표 (하루 내 완료 가능한 범위)
   뉴스 데이터 제공: NewsAPI와 Hacker News API를 통해 최신 뉴스 가져오기
   웹사이트 또는 구글 확장 프로그램 UI: 간단한 뉴스 목록 표시
   기본적인 알림 시스템: 최신 뉴스 알림
   최소한의 사용자 경험 (UX): 검색 기능 및 카테고리 선택

2. 구현할 핵심 기능
1) 뉴스 데이터 제공
   NewsAPI와 Hacker News API를 통해 한국 뉴스 및 개발 관련 뉴스 제공.
   카테고리별 뉴스 제공 (예: 개발, 글로벌, 한국 뉴스 등).
2) UI 설계 (최소화된 기능)
   - 메인 페이지:
     - 헤더: &quot;오늘의 주요 뉴스&quot;
     - 뉴스 리스트: API로 받아온 뉴스 항목을 간단히 표시 (타이틀, 요약, 출처 링크) 각 뉴스 항목을 클릭하면 원본 뉴스로 이동
     - 검색 기능: 뉴스 검색을 통해 키워드 기반 필터링
     - 알림 기능: 페이지 로드 시 최신 뉴스 표시, 크롬 알림 API를 사용하여 사용자가 최신 뉴스에 대한 알림을 받을 수 있게 하기
3) 구글 확장 프로그램 (선택 사항)
   - 뉴스 목록을 간단히 표시하는 팝업 UI
   - 사용자에게 알림을 제공하여 뉴스 업데이트

3. 개발 시간 분배
   1단계: 환경 설정 (2시간)
   - API 키 확보: NewsAPI, Hacker News API에서 API 키를 받음
   - 개발 환경 준비: React/Next.js 또는 간단한 HTML/CSS/JS 페이지 설정
   create-react-app 또는 Next.js 초기화

   2단계: 데이터 수집 및 표시 (4시간)
   - NewsAPI와 Hacker News API 연동
   - 뉴스 데이터를 가져오는 API 요청 코드 작성
   - 카테고리별 뉴스 필터링
   - 각 뉴스 항목의 제목, 링크, 요약 등의 정보를 표시하는 기본적인 UI 구현
   UI 구성:
   - 뉴스 리스트 페이지 디자인
   - 각 뉴스 항목에 링크 추가 (클릭 시 뉴스 페이지로 이동)

   3단계: 알림 기능 추가 (2시간)
   - 브라우저 알림: 최신 뉴스 알림을 크롬 알림 API를 통해 제공
   - 페이지 로드 시 새 뉴스가 있을 경우 알림 발생

   4단계: 배포 및 테스트 (2시간)
   - 배포 준비: 웹사이트는 Netlify, Vercel 등을 통해 배포
   - 구글 확장 프로그램은 Chrome Web Store에 등록
   - 테스트: 각 기능(뉴스 제공, 검색, 알림 시스템)을 간단히 테스트

   문제 수정 및 최종 확인
   하루 동안 개발할 수 있는 기능

   웹사이트:
   - 뉴스 데이터 제공 (한국 뉴스, 개발 뉴스 등)
   - 뉴스 항목을 간단히 리스트로 출력
   - 뉴스 항목 클릭 시 원본 뉴스 페이지로 이동
   - 기본적인 알림 시스템 구현 (새 뉴스가 있을 때 알림)
   - 기본적인 UI (디자인 없이 리스트만 출력해도 최소화 가능)
   - 구글 확장 프로그램 (선택 사항):
   - 뉴스 목록을 팝업으로 간단히 제공
   - 페이지 방문 시 새 뉴스가 있으면 알림 제공

4. 기능이 최소화된 상태에서 기대되는 결과
   뉴스 제공 웹사이트나 구글 확장 프로그램을 통해 하루에 한 번 주요 뉴스를 쉽게 확인할 수 있는 시스템이 완성됩니다.
   주요 기능을 빠르게 구현한 후, 후속 개선을 통해 사용자 맞춤형 뉴스 제공, UI/UX 개선, 더 많은 뉴스 소스 추가 등을 진행할 수 있습니다.

5. 예상 개발 시간 (최소화된 기능 기준): 8시간 이내
   - 환경 설정: 2시간
   - 뉴스 제공 및 UI 개발: 4시간
   - 알림 기능 및 배포: 2시간

6. 배포 및 배포 후 작업
   - 배포: 웹사이트는 Vercel 또는 Netlify에 배포하여 바로 사용할 수 있게 합니다.
   - 확장 프로그램 배포: Chrome Web Store에 등록하고, 사용자 피드백을 받아 개선 사항을 반영합니다.
   결론:
   하루 안에 뉴스 제공 기능을 갖춘 웹사이트 및 구글 확장 프로그램을 구현하려면 핵심 기능만 집중하여 최소화된 범위 내에서 개발을 완료할 수 있습니다.
   이 프로젝트는 첫날에 기초적인 기능을 제공하고, 후속 작업을 통해 점진적으로 기능을 확장하는 방향으로 진행할 수 있습니다.</code></pre>
<p><strong>Q. 🌟 해당 서비스 개발을 시키기 위한 프롬프트 작성
서비스 컨셉 작성</strong></p>
<p><strong>A.</strong></p>
<p>서비스 컨셉: &quot;뉴스 랩&quot; (News Lab)
서비스 목적
&quot;뉴스 랩&quot;은 사용자가 하루 한 번 주요 뉴스를 손쉽게 확인할 수 있도록 돕는 웹사이트 및 구글 확장 프로그램입니다. 이 서비스는 NewsAPI와 Hacker News API를 활용하여 한국 뉴스와 개발 관련 뉴스를 제공하며, 최신 뉴스를 빠르고 효율적으로 확인할 수 있는 경험을 제공합니다. 사용자는 이 서비스를 통해 원하는 카테고리의 뉴스와 함께 주요 이슈를 파악하고, 하루를 시작하는 데 필요한 정보를 얻을 수 있습니다.</p>
<p>핵심 기능
주요 뉴스 제공:</p>
<p>NewsAPI와 Hacker News API를 통해 주요 뉴스(한국 뉴스, 개발 뉴스, 기타 분야 뉴스 등)를 제공합니다.
카테고리별 뉴스 필터링 기능: 한국 뉴스, 글로벌 뉴스, 개발 뉴스 등.
각 뉴스 항목을 클릭하면 원본 뉴스 페이지로 이동할 수 있도록 링크 제공.
알림 기능:</p>
<p>페이지 로드 시 최신 뉴스가 있을 경우, 브라우저 알림을 통해 사용자가 실시간으로 알림을 받을 수 있습니다.
사용자가 방문하지 않았을 경우, 하루에 한 번 중요한 뉴스를 알리는 알림을 제공하여 놓친 뉴스를 쉽게 확인하도록 도와줍니다.
간단한 UI 디자인:</p>
<p>사용자가 뉴스 목록을 쉽게 탐색할 수 있도록 직관적인 디자인을 제공합니다.
검색 기능을 통해 특정 뉴스나 키워드를 쉽게 검색할 수 있습니다.
뉴스 제목, 간단한 요약, 출처 등의 기본적인 정보만 표시하여 빠르게 정보를 제공할 수 있도록 합니다.
구글 확장 프로그램:</p>
<p>웹사이트와 동일한 기능을 제공하며, 구글 크롬 브라우저에 설치하여 바로 사용할 수 있습니다.
확장 프로그램 팝업에서 최신 뉴스를 간단히 확인하고, 알림을 받을 수 있습니다.
서비스 사용 흐름
웹사이트:</p>
<p>사용자는 웹사이트에 접속하여 최신 뉴스를 확인합니다.
뉴스 항목을 클릭하여 원본 기사를 읽거나, 특정 카테고리를 선택하여 원하는 뉴스만 필터링할 수 있습니다.
사용자가 웹사이트를 방문할 때마다 최신 뉴스에 대한 알림을 받을 수 있습니다.
구글 확장 프로그램:</p>
<p>확장 프로그램을 설치한 후, 브라우저에서 클릭만으로 최신 뉴스 팝업을 확인할 수 있습니다.
뉴스 목록을 보고, 클릭하여 상세 정보를 볼 수 있으며, 알림을 받을 수 있습니다.</p>
<p>타겟 사용자
개발자: 최신 개발 관련 뉴스 및 트렌드를 확인하려는 개발자들
뉴스 애호가: 매일의 주요 뉴스를 빠르게 파악하고자 하는 사용자
업무를 시작하는 사람들: 하루를 시작하면서 중요한 뉴스와 정보를 빠르게 습득하고자 하는 사람들</p>
<p>기술 스택
Frontend: React.js / Next.js
Backend: NewsAPI, Hacker News API
알림 기능: Chrome Notifications API
구글 확장 프로그램: HTML, JavaScript (Chrome Extension API)
배포: Netlify 또는 Vercel (웹사이트), Chrome Web Store (확장 프로그램)</p>
<p>차별화 요소
핵심 뉴스 필터링: 사용자가 원하는 카테고리별로 뉴스를 필터링하여 제공함으로써, 관련된 뉴스를 쉽게 찾아볼 수 있습니다.
간편한 알림 시스템: 웹사이트 및 확장 프로그램 모두 실시간 알림을 통해 사용자가 놓친 뉴스를 알립니다.
일일 업데이트: 사용자가 하루에 한 번 확인할 수 있도록 매일의 주요 뉴스를 제공하여, 지속적으로 최신 정보를 얻을 수 있도록 합니다.</p>
<p>프롬프트 작성:
목표: &quot;뉴스 랩&quot; 웹사이트 및 구글 확장 프로그램 개발을 위한 기본적인 기획과 설계를 구체화하여, 사용자가 하루 한 번 주요 뉴스를 손쉽게 확인할 수 있도록 돕는 서비스를 제공합니다.</p>
<p>🌟 프롬프트 내용:</p>
<pre><code class="language-markdown"># 프로젝트 목표:
&quot;뉴스 랩&quot;은 하루 한 번 주요 뉴스와 개발 관련 뉴스를 손쉽게 확인할 수 있도록 돕는 웹사이트 및 구글 확장 프로그램입니다. NewsAPI와 Hacker News API를 활용하여 한국 뉴스, 개발 뉴스 등을 제공하고, 알림 기능을 통해 최신 뉴스를 빠르게 확인할 수 있게 합니다.

# 주요 기능:
1. 뉴스 제공:
    - 한국 뉴스, 개발 뉴스 등 다양한 카테고리별 뉴스 제공
    - 각 뉴스 항목 클릭 시 원본 뉴스로 이동 가능
    - 뉴스 항목의 제목, 요약, 출처 정보 제공

2. 알림 기능:
    - 웹사이트 방문 시 최신 뉴스 알림 제공
    - 크롬 브라우저 알림 API를 사용하여 실시간 알림 제공

3. UI 디자인:
    - 간단한 뉴스 목록 표시
    - 뉴스 검색 기능 제공
    - 직관적인 뉴스 카테고리 선택 UI

4. 구글 확장 프로그램:
    - 웹사이트와 동일한 뉴스 제공
    - 팝업으로 간단한 뉴스 확인 가능
    - 실시간 알림 기능 제공

# 기술 스택:
- **Frontend**: React.js / Next.js
- **API**: NewsAPI, Hacker News API
- **알림**: Chrome Notifications API
- **구글 확장 프로그램**: HTML, JavaScript
- **배포**: Vercel (웹사이트), Chrome Web Store (확장 프로그램)

# 예상 기간:
- **1일**: 기본적인 웹사이트와 확장 프로그램을 통해 하루 한 번 제공되는 주요 뉴스를 확인할 수 있도록 구현

# 타겟 사용자:
- 개발자, 뉴스 애호가, 업무를 시작하려는 사용자 등

# 차별화 요소:
- 카테고리별 뉴스 제공
- 실시간 알림 시스템
- 직관적인 뉴스 탐색 기능</code></pre>
<p>이 프롬프트를 바탕으로 개발 팀에게 구체적인 개발 지침을 제공할 수 있습니다.</p>
<blockquote>
<p><strong>My Thoughts💡:</strong> 괜찮은 프롬프트가 나왔습니다.
뉴스 랩? 괜찮지만 서비스 이름이 완전히 마음에 들지는 않습니다.
생각해보니 서비스를 만들려면 이름과 로고가 있어야겠죠?</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/b5a741e2-6973-4ea1-85dd-13dd803028f7/image.png" alt=""></p>
<p>이후에도 몇 번 로고 생성 요청했지만 GPT 특유의 이미지 생성 디자인이 마음에 들지 않습니다.
&quot;free logo generator&quot;를 검색해 생성해 좀 맘에 드는 로고를 발견했지만, 막상 다운로드 받으려고 하면 무료가 아닙니다.
로고는 이후에 Claud에게 요청을 했습니다.</p>
<blockquote>
<p>✨ <strong>제가 활용해본 경험으로 GPT는 검색해야 알 수 있는 내용, 글로 정리하는 내용을 잘 만들고 실제 구현, 디자인적인 부분은 Claud가 더 잘한다고 느꼈습니다.</strong></p>
</blockquote>
<h2 id="💻-개발-과정">💻 개발 과정</h2>
<blockquote>
<p>그럼 아까 GPT가 만든 프롬프트를 Claud에게 시켜보겠습니다.
&quot;Headliner&quot;로 벌써 서비스 이름도 정해졌고,
기술 스택은 React로 작성해줬지만 저는 Next.js를 활용할 줄 알고 SEO 설정에도 편하기 때문에 Next.js로 만들어 달라고 합니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/cdefa6d7-0a4b-49a0-a6d0-ff7227b7fa75/image.png" alt=""></p>
<blockquote>
<p><strong>My Thoughts💡:</strong> 하루 안에 핵심 기능을 구현해야 하는 부분을 잘 이해하고 잘 만들어줬습니다. 실제 만들어준 코드들은 깃허브 저장소를 참고해주시기 바랍니다.
<a href="https://github.com/hi-rachel/headliner">https://github.com/hi-rachel/headliner</a></p>
<p>여기서 부족하다고 느낀 다음 부분들에 대해 개선을 요청했습니다.</p>
<ol>
<li>코드가 Next.js Page Router 예시라 Next.js App router 환경으로 요구</li>
<li>코드를 그대로 붙여넣으면 타입 경고가 나기 때문에 타입을 다시 잘 작성해달라고 요구</li>
<li>radix를 설치하라고 했으면서 실제로 shadcn ui를 사용해 나는 import 오류
<img src="https://velog.velcdn.com/images/hi-rachel/post/ac5be60f-8286-4e05-9b6a-10de73b07449/image.png" alt="">
<img src="https://velog.velcdn.com/images/hi-rachel/post/f53eb792-391e-4d78-aa64-dd49614e0915/image.png" alt=""></li>
</ol>
</blockquote>
<p>바로 오류 없는 변경된 코드를 적용시켰고, 결과물은 UI 라이브러리를 활용해 반응형으로 금방 세련된 UI로 구현이 완료되었습니다.</p>
<h3 id="✨-결과물">✨ 결과물</h3>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/10787843-08b0-486c-a950-5240274e7956/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/9d167439-6f19-48a1-a0bf-716da7eb611d/image.png" alt=""></p>
<blockquote>
<p><strong>My Thoughts💡:</strong> 다음 부분들을 발전시켜봤습니다.</p>
<ol>
<li>meta tag 작성</li>
<li>로고, og image, manifest.json 파일 생성</li>
<li>PWA 설정</li>
</ol>
<p>크롬 확장 프로그램으로 만들어 볼까? 했지만 지금 단계에서 굳이 필요가 없을거 같아 진행하지 않고,
간단한 PWA 설정은 있으면 편할거 같아 구현 진행했습니다.
이거 할까? 말까? 필요성이 있을까? 고민이 되는 부분도 AI한테 물어보세요.</p>
</blockquote>
<h3 id="1-meta-tag-작성">1. meta tag 작성</h3>
<p>기본 Next.js layout 파일을 붙여놓고 많은 사람들이 들어왔으면 좋겠으니 SEO를 위해 메타 태그를 작성해달라고 합니다.</p>
<p>layout.tsx</p>
<pre><code class="language-typescript">import type { Metadata } from &quot;next&quot;;
import { Geist, Geist_Mono } from &quot;next/font/google&quot;;
import &quot;./globals.css&quot;;

const geistSans = Geist({
  variable: &quot;--font-geist-sans&quot;,
  subsets: [&quot;latin&quot;],
});

const geistMono = Geist_Mono({
  variable: &quot;--font-geist-mono&quot;,
  subsets: [&quot;latin&quot;],
});

export const metadata: Metadata = {
  title: &quot;Create Next App&quot;,
  description: &quot;Generated by create next app&quot;,
};

export default function RootLayout({
  children,
}: Readonly&lt;{
  children: React.ReactNode;
}&gt;) {
  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body
        className={${geistSans.variable} ${geistMono.variable} antialiased}
      &gt;
        {children}
      &lt;/body&gt;
    &lt;/html&gt;
  );
}</code></pre>
<p><strong>Q. Meta tag 작성해줘</strong></p>
<p><strong>A.</strong>
<img src="https://velog.velcdn.com/images/hi-rachel/post/f76566f9-c6e5-40ea-804c-de9be73d5a0b/image.png" alt=""></p>
<h3 id="2-로고-og-image-manifestjson-파일-생성">2. 로고, og image, manifest.json 파일 생성</h3>
<p>알아서 필요한 부분들을 더 만들어 줄까? 하고 물어봅니다.
응 만들어줘!</p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/20a657fb-95b7-4773-8318-3c391eaf0e13/image.png" alt=""></p>
<p>🤩 꽤 괜찮은 로고를 한 번에 만들어줘서 놀랐습니다... 맘에 드니 바로 활용해줬습니다!</p>
<p>summary_large_image는 카카오톡 공유, 트위터 공유시 뜨는 미리보기 이미지에 필요합니다. (생성해준 metadata를 보면 필요한 이미지들을 알 수 있으니 참고하면 됩니다.)</p>
<p>로고, opengraph image는 만들어줬지만
favicon.ico 파일과 manifest.json에 들어가는 512x512, 192x192 이미지 등 더 필요한 부분들은 검색을 통해 해결합니다.
-&gt; <a href="https://www.favicon-generator.org/">https://www.favicon-generator.org/</a> 추천</p>
<blockquote>
<p>Next.js App router 환경에서는 app 폴더 하위에 favicon.ico 파일을 넣으면 자동 적용됩니다.
나머지 자료들은 public 폴더 경로에 넣어주면 되고 자동 생성된 이미지와 manifest.json에 파일 이름과 경로를 맞춰줍니다.</p>
</blockquote>
<h3 id="3-pwa-설정">3. PWA 설정</h3>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/2597ca31-c764-4fcc-a729-466eb829e013/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/fde6c904-a25d-4aa9-9663-f5842b351ac8/image.png" alt=""></p>
<p>👉 제가 해결한 과정을 보면 알 수 있듯이 모르겠는 부분은 물어보면 됩니다.</p>
<blockquote>
<p>AI도 실수할 수 있고 거짓말 할 수도 있습니다.
이미 아는 내용이면 스스로 검증할 수 있지만 잘 모른다면 다른 AI한테도 물어보고 구글 검색도 하면 됩니다.</p>
</blockquote>
<p>예전에도 개발은 구글링이었지만, 요즘은 정말 검색해서 거의 다 알 수 있고 검색도 AI가 대신해줘~ 코딩도 대신해줘~ 아무리 검색해도 해결이 안되는 문제다? -&gt; 나보다 경험있는 개발자에게 물어보기 (온라인 - stackoverflow, 각종 개발 커뮤니티), 공식 문서 제대로 읽기 공부하기</p>
<h2 id="🦄-배포-오류-고치기">🦄 배포, 오류 고치기</h2>
<p>깃허브에서 저장소를 만들고 바로 연결해줍니다.
연결하는 법도 다 써있죠?</p>
<pre><code class="language-markdown">git remote add origin https://github.com/hi-rachel/test.git
git branch -M main
git push -u origin main</code></pre>
<blockquote>
<p>올릴려면 커밋을 해야겠죠?
커밋 메시지도 AI가 잘 작성해줍니다. 조금 수정해서 원하는 대로 올립니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/8a8b2289-5f20-49fe-895b-1849ead06023/image.png" alt=""></p>
<p>자, 이제 Vercel에 로그인해 깃허브 계정을 연결해 바로 배포해줍니다.
(무료로 활용할 수 있고 제 경험상 가장 쉽고 편리하기 때문에 Vercel로 진행했습니다. Next.js + Vercel 🖤)</p>
<h3 id="🛠️-오류">🛠️ 오류</h3>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/2952c6b2-dabb-4c76-a1b8-83c3442720fd/image.png" alt=""></p>
<p>빌드하면서 나오는 오류도 그대로 추천해주는 링크 읽어보고, 검색해서 고치면 됩니다.</p>
<ol>
<li><a href="https://stackoverflow.com/questions/21636503/use-svg-as-ogimage">Open graph 이미지</a>는 <a href="https://svgtopng.com/">svg에서 png로</a> 바꿔주기</li>
<li>Next.js에서 Viewport 권장사항 따르기</li>
</ol>
<p>끝! -The end-</p>
<blockquote>
<p>🫶 사이트 방문하기: <a href="https://headliner-news.vercel.app/">https://headliner-news.vercel.app/</a>
🌟 Github: <a href="https://github.com/hi-rachel/headliner">https://github.com/hi-rachel/headliner</a></p>
</blockquote>
<hr>
<h2 id="📍-추천">📍 추천</h2>
<p>AI를 활용해 빠르게 서비스를 만드는 것에 관심이 있다면 추천하는 영상입니다.</p>
<p><a href="https://www.youtube.com/watch?v=ai5YcT8Ws80&amp;t=3s&amp;ab_channel=%EB%94%A9%EC%BD%94%EB%94%A9%EC%BD%94">딩코딩코 - AI 를 이용해서 단 3일만에 서비스 만들기. (기획, 디자인, 개발 다해줌)</a></p>
<p><a href="https://www.youtube.com/watch?v=f-0X4O-SuBc&amp;t=153s&amp;ab_channel=%EB%94%A9%EC%BD%94%EB%94%A9%EC%BD%94">딩코딩코 - 48시간 안에 무엇이든지 개발해드립니다 [Ep1]</a></p>
<p>해당 영상을 봤을 때 제가 평소에 쓰는 방식이랑 비슷해서 놀랐습니다.</p>
<p>이런 간단한 서비스를 가지고 포스팅하는게 조금 망설여졌지만, 저는 유튜브를 하지 않기 때문에 글로 설명하는 컨텐츠를 만들어 보고 싶었습니다.
물론 Open API를 활용해서 정말 빠르게 만들 수 있었지만, 직접 백엔드 API까지 구현했다면 훨씬 시간이 걸렸겠죠! (지금은 개발보다 이 글을 쓰는데 시간이 배로 걸렸습니다..)</p>
<p>무조건 빠르게 만드는게 답은 아니지만, 새로운 기술들에 관심을 가지고 있어야 그런 부분들을 활용해 최대한 효율을 뽑아낼 수 있는 부분은 뽑아낼 수 있다고 생각합니다.</p>
<p>정말 하루가 다르게 발전하고, 새로운 기술들이 나와서 저는 유튜브, 개발 커뮤니티  등을 통해 정보를 얻고 있습니다.</p>
<p>사이드 프로젝트를 하다보면 기간이 너무 길어지고 미뤄지다 보면 흐지부지 되는 경우도 굉장히 많은데 핵심 기능들만 빠르게 구현하고 괜찮으면 점점 발전시키는 것도 굉장히 좋은 방법이라고 생각합니다.</p>
<p>저는 개발자라 어느 정도 관련 지식이 있어 AI를 활용할 때 문제 해결력이 좀 더 높다고 생각하지만, 비개발자도 공부를 좀만 한다면 가능할거라 생각합니다. 꼭 엄청 어려운 코딩을 해야 서비스를 만들 수 있는건 아니니까요. NoCode툴을 활용할 수도 있고 Firebase 등과 같은 BaaS도 활용할 수 있습니다.</p>
<p>저는 프론트엔드 개발자였지만 최근에는 AI를 활용해 백엔드 개발, DB 연동, 도커 활용도 문제없이 진행한 경험이 있습니다.
(부족한 부분은 특강, 강의 등을 들었습니다.)</p>
<h2 id="📍-기타-얘기">📍 기타 얘기</h2>
<p><a href="https://www.youtube.com/watch?v=oTyoLq361fI&amp;ab_channel=%EC%B9%A8%EC%B0%A9%EB%A7%A8">침착맨 - AI야 침착맨이 좋아? 김풍이 좋아?</a></p>
<p>이번 개발은 해당 영상을 보면서 했는데요..
진짜 이제는 AI로 정말 정말 많은 걸 할 수 있습니다.
GPT랑 대화도 이제 자연스럽게 가능하니 영어 회화에도 가끔 이용합니다.</p>
<p>스트레스 받으면 괴롭혀도 보십쇼. 
근데 점점 흑화해서 대들까봐 무섭네요..
예전에는 꼬박 존댓말 했는데 요즘 반말도 자주 하더라구여 😅</p>
<hr>
<p>1시간만에 만든 서비스라 물론 부족한 부분이 있습니다. 소프트웨어는 항상 유지보수가 필요하겠죠.</p>
<p>구현 중간 중간 env 환경 변수 관리라던지 vercel 설정 등 이 역시 AI에게 물어봐도 바로 알 수 있는 내용이라 생략했는데 혹시 궁금하시면 댓글 달아주세요.</p>
<p>여기까지 읽어주셔서 감사합니다. 피드백은 환영합니다 🤗</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js PWA 설정법]]></title>
            <link>https://velog.io/@hi-rachel/Next.js-PWA-%EC%84%A4%EC%A0%95%EB%B2%95</link>
            <guid>https://velog.io/@hi-rachel/Next.js-PWA-%EC%84%A4%EC%A0%95%EB%B2%95</guid>
            <pubDate>Sun, 05 Jan 2025 14:10:43 GMT</pubDate>
            <description><![CDATA[<h1 id="pwa-설정법">PWA 설정법</h1>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/ec9afbf9-0ca4-46f6-85ce-4f6771e68ef8/image.png" alt=""></p>
<p>오늘은 Next.js Page Router 환경에서 PWA 설정하는 방법을 설명하겠습니다.</p>
<h2 id="1-next-pwa-패키지-설치">1. next-pwa 패키지 설치</h2>
<p>PWA 설정을 위해 다음 패키지를 설치합니다.</p>
<pre><code class="language-bash">npm i next-pwa</code></pre>
<h2 id="2-nextconfigmjs-파일-설정">2. next.config.mjs 파일 설정</h2>
<pre><code class="language-js">import withPWA from &quot;next-pwa&quot;;

/** @type {import(&#39;next&#39;).NextConfig} */
const nextConfig = {
  reactStrictMode: true, // Re-enable reactStrictMode if needed
};

export default withPWA({
  dest: &quot;public&quot;,
  skipWaiting: true, // PWA-specific options here
})(nextConfig);</code></pre>
<p>위와 같이 withPWA 설정을 넣어줍니다.</p>
<p><strong>전체 코드</strong></p>
<pre><code class="language-js">import withPWA from &#39;next-pwa&#39;;

/** @type {import(&#39;next&#39;).NextConfig} */
const nextConfig = {
    reactStrictMode: true, // Re-enable reactStrictMode if needed
    i18n: {
        locales: [&#39;en&#39;, &#39;ko&#39;],
        defaultLocale: &#39;ko&#39;,
        localeDetection: false,
    },
    images: {
        remotePatterns: [
            {
                protocol: &#39;https&#39;,
                hostname: &#39;*.googleusercontent.com&#39;,
                port: &#39;&#39;,
                pathname: &#39;**&#39;,
            },
            {
                protocol: &#39;https&#39;,
                hostname: &#39;firebasestorage.googleapis.com&#39;,
                port: &#39;&#39;,
                pathname: &#39;**&#39;,
            },
        ],
    },
};

export default withPWA({
    dest: &#39;public&#39;,
    skipWaiting: true, // PWA-specific options here
})(nextConfig);</code></pre>
<p>제가 설정한 next.config.mjs 코드 전체입니다.
저는 i18n 다국화 설정과 이미지 설정이 포함되어 있습니다.</p>
<h2 id="3-manifest-설정">3. manifest 설정</h2>
<p>PWA 설정을 위해서는 앱의 구성 정보를 담고 있는 manifest.json 파일이 필요합니다.</p>
<p>manifest.json을 쉽게 생성하기 위해서는 manifest-generator 검색해서 편한 사이트 이용하면 됩니다.</p>
<p>저는 <a href="https://progressier.com/pwa-manifest-generator">progressier 사이트</a>를 이용했습니다.
name, short_name, icons, display, background_color, theme_color, start_url, scope를 설정해주고 json을 다운받아 줍니다.</p>
<blockquote>
<p>✏️ <strong>설정 옵션</strong>
&quot;display&quot;: &quot;standalone&quot; 설정 (추천)</p>
<ul>
<li>&quot;standalone&quot;은 PWA가 설치 후 실행될 때 브라우저 크롬(주소 표시줄, 뒤로 가기 버튼 등)을 숨기고 독립 실행형 앱처럼 표시되도록 설정합니다. 웹 브라우저 창처럼 보이지 않고 네이티브 앱처럼 보이는 환경을 제공합니다.</li>
</ul>
<p>&quot;orientation&quot;: &quot;any&quot; (default)</p>
<ul>
<li>&quot;any&quot;는 PWA가 실행될 때 화면의 방향을 제한하지 않고, 사용자가 장치의 화면을 회전하면 해당 방향(세로 또는 가로)에 맞게 앱이 실행됩니다.</li>
<li>이 옵션을 사용하면 사용자 경험이 유연해질 수 있지만, 앱이 특정 방향에서만 제대로 동작하도록 설계되었다면, 명시적인 방향 제한(예: &quot;portrait&quot; 또는 &quot;landscape&quot;)을 사용하는 것이 좋습니다.</li>
</ul>
</blockquote>
<h3 id="🎨-icons-만드는-법">🎨 <strong>icons 만드는 법</strong></h3>
<p>manifest를 만들기 위해서는 앱을 대표하는 아이콘이 필요합니다.
icons에 넣을 이미지를 피그마 등을 이용해서 512 x 512 사이즈로 준비합니다.
(권장 사이즈(192x192, 512x512 등) 중 최소 하나는 제공하는 것이 좋습니다.)</p>
<p>그냥 네모로 만든 앱 아이콘을 저장하면 다른 응용 프로그램들과 다르게 보이는 문제가 있어서 <a href="https://progressier.com/maskable-icons-editor">Maskable Icon</a>을 만들어 적용시켜줬습니다.</p>
<p>public 폴더 하위에 생성된 앱 아이콘 이미지 모두 넣어주고 이미지 경로에 유의합니다.
저는 깔끔하게 public 하위에 icons 폴더로 묶어서 넣었습니다.</p>
<p>[참고]
<img src="https://velog.velcdn.com/images/hi-rachel/post/2b6446f4-e921-4904-b915-e4edabf0cef4/image.png" alt=""></p>
<p>maskable 적용 전 - Mac 환경에서 다른 응용 프로그램처럼 rounded 설정 적용이 안되어 어색하다.</p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/7120cb06-98b4-42f5-a7fa-385be16e4f4f/image.png" alt=""></p>
<p>maskable 적용 후 - 다른 응용 프로그램처럼 자연스러운 모습</p>
<p><strong>전체 코드</strong></p>
<pre><code class="language-json">{
  &quot;theme_color&quot;: &quot;#f472b6&quot;,
  &quot;background_color&quot;: &quot;#fce7f3&quot;,
  &quot;icons&quot;: [
    {
      &quot;purpose&quot;: &quot;maskable&quot;,
      &quot;sizes&quot;: &quot;512x512&quot;,
      &quot;src&quot;: &quot;/icons/icon512_maskable.png&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    },
    {
      &quot;purpose&quot;: &quot;any&quot;,
      &quot;sizes&quot;: &quot;512x512&quot;,
      &quot;src&quot;: &quot;/icons/icon512_rounded.png&quot;,
      &quot;type&quot;: &quot;image/png&quot;
    }
  ],
  &quot;orientation&quot;: &quot;any&quot;,
  &quot;display&quot;: &quot;standalone&quot;,
  &quot;dir&quot;: &quot;auto&quot;,
  &quot;lang&quot;: &quot;ko&quot;,
  &quot;name&quot;: &quot;Our Story Ing&quot;,
  &quot;short_name&quot;: &quot;Ing&quot;,
  &quot;start_url&quot;: &quot;/&quot;,
  &quot;scope&quot;: &quot;/&quot;
}</code></pre>
<p>이제 해당 manifest.json 파일 적용을 위해,
src/pages/_document.tsx 파일 Head에 manifest link를 추가해줍니다.</p>
<pre><code class="language-tsx">&lt;link rel=&quot;manifest&quot; href=&quot;/manifest.json&quot; /&gt;</code></pre>
<p><strong>전체 코드</strong></p>
<pre><code class="language-tsx">import { Html, Head, Main, NextScript } from &quot;next/document&quot;;

const Document = () =&gt; {
  return (
    &lt;Html lang=&quot;en&quot;&gt;
      &lt;Head&gt;
        &lt;link rel=&quot;manifest&quot; href=&quot;/manifest.json&quot; /&gt;
        &lt;meta name=&quot;theme-color&quot; content=&quot;#f472b6&quot; /&gt;
        &lt;meta
          name=&quot;description&quot;
          content=&quot;커플들이 자신들의 여정을 공유할 수 있는 특별한 공간&quot;
        /&gt;
      &lt;/Head&gt;
      &lt;body&gt;
        &lt;Main /&gt;
        &lt;NextScript /&gt;
      &lt;/body&gt;
    &lt;/Html&gt;
  );
};

export default Document;</code></pre>
<h2 id="4-테스트-빌드--실행">4. 테스트 (빌드 &amp; 실행)</h2>
<p>먼저 빌드 후 재실행해줍니다.</p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/6a9ef520-5799-42f0-9af2-69183035039d/image.png" alt=""></p>
<blockquote>
<p>여기서 오류 메시지가 뜬다면 설정이 제대로 완료되지 않은 것으로 오류 메시지를 따라 고쳐줍니다.</p>
</blockquote>
<p>자, 이제 설정을 모두 완료했으므로 PWA 앱을 설치해볼까요?</p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/36d12e7b-f3a6-40b0-ac2c-2bb4d2f41dbe/image.png" alt=""></p>
<p>앱이 설치 안된 상태에서 해당 사이트를 접속하면 상단 주소창에 설치 아이콘이 뜨고 누르면 앱을 설치할 수 있습니다. localhost, 배포 환경에서 모두 확인 가능합니다.</p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/35ea765a-2a5b-4d91-a0f3-9dd8525ae3e8/image.png" alt=""></p>
<p>설치를 완료하면 다른 응용 프로그램이 있는 곳에 
잘 설치된 모습을 확인할 수 있고, 상단 주소창 아이콘이 연결 프로그램 아이콘으로 바뀌고 해당 아이콘을 눌러 다운로드한 프로그램을 열 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/e3ca5cec-a79d-43c3-81c4-9747de6a02c8/image.PNG" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/0bb7f3a5-de33-4fd3-a4e7-0657e2abc89c/image.jpg" alt=""></p>
<p>배포후 모바일 환경에서도 똑같이 잘 설치되는 모습을 확인할 수 있습니다.</p>
<p>PWA 앱을 모바일에서 설치하려면 해당 웹사이트에 접속해 &#39;하단 공유 아이콘 클릭-&gt; 홈 화면에 추가&#39;를 누르면 됩니다.</p>
<hr>
<h2 id="🔍-개념-공부">🔍 개념 공부</h2>
<blockquote>
<p>PWA 앱 실행시 작동하는 Service Worker에 대해 알아보았습니다.
<a href="https://developer.mozilla.org/ko/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Offline_Service_workers">참고</a></p>
</blockquote>
<h3 id="service-worker란">Service Worker란?</h3>
<p><strong>Service Worker는 브라우저와 네트워크 사이의 가상 프록시입니다.</strong> 이는 프론트엔드 개발자들이 수년간 어려움을 겪었던 문제들을 결국 해결하였습니다(특히 웹 사이트의 자원을 적절히 캐싱하는 방법과, 사용자의 기기가 오프라인일 때 이를 사용할 수 있도록 하는 것 등).</p>
<p>이는 <strong>페이지의 메인 JavaScript 코드와 독립된 스레드에서 실행되며, DOM 구조에 대한 어떠한 접근도 갖지 않습니다.</strong> 이는 전통적인 웹 프로그래밍과 다른 접근법을 소개합니다. API는 비차단형(non-blocking)이며 여러 컨텍스트 사이에 커뮤니케이션을 주고 받을 수 있습니다. <strong>여러분은 Service Worker에 어떤 작업을 전달할 수 있으며, Promise 기반 접근법을 사용해 결과가 준비될때마다 전달받을 수 있습니다.</strong></p>
<p>Service Worker는 &quot;단지&quot; 오프라인 기능을 제공하는 것 이상으로 알림 처리, 독립된 스레드에서의 복잡한 계산 등 많은 것들을 할 수 있습니다. Service worker는 네트워크 요청을 제어하고 수정하며, 캐시로부터 반환된 커스텀 응답을 제공하거나 응답을 완전히 가공할 수도 있으므로 매우 강력합니다.</p>
<p><strong>보안</strong>
<strong>Service Worker는 매우 강력하기 때문에 안전한 컨텍스트(HTTPS를 의미)에서만 실행됩니다</strong>.
코드를 상용으로 푸시하기전에 먼저 테스트하길 원하신다면, localhost에서 테스트하거나 GitHub Pages를 설정하면 됩니다. 둘 다 HTTPS를 지원합니다.</p>
<hr>
<p>위 글을 통해 Service Worker는 브라우저와 네트워크 사이의 가상의 프록시로, 메인 JS 코드와 독립된 스레드에서 실행되어 오프라인에서 작동할 수 있음을 알 수 있습니다.</p>
<p>이를 이용해 해당 PWA 앱 프로젝트에서 채팅 알림을 브라우저 알림으로 구현했습니다.
기회가 된다면 브라우저 알림에 관해서도 포스팅하겠습니다.</p>
<blockquote>
<p>OKKY 웹사이트에서 처음으로 PWA 앱 설치를 어떻게 하는지 알았었습니다.
웹앱을 구현하고 제일 간단하게 설치할 수 있는 방법이라고 생각합니다.
구현하는 프로젝트에 적합하다면 한 번 시도해보시길!</p>
</blockquote>
<hr>
<p>💗 <strong>현재 진행중인 커플 웹앱 ing 구경가기
<a href="https://our-story-ing.vercel.app/">https://our-story-ing.vercel.app/</a></strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[주니어 개발자를 위한 소프트 스킬 5가지 - 토스 세션 정리]]></title>
            <link>https://velog.io/@hi-rachel/%EC%A3%BC%EB%8B%88%EC%96%B4-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%EC%86%8C%ED%94%84%ED%8A%B8-%EC%8A%A4%ED%82%AC-5%EA%B0%80%EC%A7%80-%ED%86%A0%EC%8A%A4-%EC%84%B8%EC%85%98-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@hi-rachel/%EC%A3%BC%EB%8B%88%EC%96%B4-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%EC%86%8C%ED%94%84%ED%8A%B8-%EC%8A%A4%ED%82%AC-5%EA%B0%80%EC%A7%80-%ED%86%A0%EC%8A%A4-%EC%84%B8%EC%85%98-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 06 Oct 2024 11:45:59 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.youtube.com/watch?v=JyAiWo4ghVg&amp;ab_channel=%ED%86%A0%EC%8A%A4">https://www.youtube.com/watch?v=JyAiWo4ghVg&amp;ab_channel=%ED%86%A0%EC%8A%A4</a></p>
<blockquote>
<p>[토스ㅣSLASH 24 - 빠르게 성장하고 싶은 주니어 개발자를 위한 소프트 스킬 5가지 - 임희진 연사님]
해당 영상을 보고 내용을 정리한 글입니다. 자세한 내용은 해당 영상을 참고해주세요.</p>
<p>최근 입사 후 주니어 개발자로 어떻게 성장해야 할지 막막해 여러 자료를 찾아보던 중 해당 강의를 발견했습니다. 토스 세션을 살펴보면 평소에 궁금했던 점들에 대한 주제도 있고 좋은 내용이 많아 도움을 많이 받고 있습니다.</p>
</blockquote>
<hr>
<h3 id="하드-스킬">하드 스킬</h3>
<ul>
<li>프로그래밍</li>
<li>아키텍처 설계</li>
<li>트러블 슈팅</li>
</ul>
<h3 id="소프트-스킬">소프트 스킬</h3>
<ul>
<li>커뮤니케이션</li>
<li>시간 관리</li>
<li>문제해결 능력</li>
<li>메타인지 능력</li>
</ul>
<h3 id="주니어-본업">주니어 본업</h3>
<pre><code>주니어 때는 성장하는 법을 배우고 성장 곡선의 기울기를 가파르게 만들어야 할 때

하드 스킬이 성장의 더하기라면 소프트 스킬은 곱하기</code></pre><ol>
<li><strong>개발</strong></li>
<li><strong>성장</strong></li>
</ol>
<blockquote>
<p><strong>복리 효과</strong>
The Wisdom of Atomic Habits
하루에 1%씩 성장하면, 1년이면 37.8% 성장</p>
</blockquote>
<h3 id="소프트-스킬-꿀팁-5가지">소프트 스킬 꿀팁 5가지</h3>
<ol>
<li><p><strong>그림으로 소통하기</strong>
 커뮤니케이션 = 상대방과 나의 생각 싱크, 말하는 것 x
 그림으로 소통시 정보 유실이 상대적으로 적음
 다이어그램 툴 하나를 익혀두면 되게 좋다 (노션에 임베딩되는 whimsical 쓰고 있음)</p>
</li>
<li><p><strong>나만의 TODO List 만들기</strong>
 <img src="https://velog.velcdn.com/images/hi-rachel/post/70baa602-2a1a-42eb-b6f5-fa42101d7c59/image.png" alt=""></p>
<ol>
<li><p><strong>내가 중심인 TODO List</strong>를 만들어야 한다
 그 안에 일도 있고, 공부할 것도 있고, 명언, 사적인 일
 =&gt; 내 뇌의 백업처럼 동작해야 한다</p>
</li>
<li><p>어디서든 접근할 수 있어야 하고, 항상 동기화되어 있어야 한다</p>
</li>
<li><p>계속 손이 가는 TODO List를 만들어야 한다
 일, 프로젝트, 공부, 취미, 여행 등 목적별로 만들면 관심 있는 TODO List만 열심히 봄</p>
<p>✍️ <strong>제안</strong>
Google Task 쓴다.</p>
<ul>
<li><strong>Today, Weekly, Monthly, Yearly</strong>로 주기별로 TODO List를 나눈다.</li>
<li>평소엔 Today 위주로 본다</li>
<li>각 주기에 오래 머문 TODO는 다음 주기로 이동(당장 해야할 일 x)</li>
</ul>
</li>
</ol>
</li>
<li><p><strong>코드를 보는 안목 기르기</strong></p>
<pre><code> 기존 코드를 마냥 우수하다고 생각하면 안 됨
 다양한 요구사항, 수많은 히스토리, 빡빡한 일정
 안목이 없으면 현실적인 코드에 익숙해지게 됨
 불편함(Code Smell)을 느낄 수 있는 안목을 길러야 함</code></pre><p>  ✍️ <strong>제안</strong></p>
<pre><code> 평소에 쓰는 오픈소스 코드 열어보기
 유명한 오픈소스 프로젝트 코드 통째로 받아서 공부하기
 **소스코드 가독성, 리팩토링, 디자인 패턴을 다루는 책** 다양하게 읽어보기
 **평소에 코딩 70%, 리팩토링 30%** 시간 쓰기 (나중에 리팩토링으로 코딩 속도가 빨라질 수 있다)
 (취미로) 시간 날 때마다 예전에 본인이 짠, 다른 사람이 짠 소스코드 리팩토링 하기</code></pre></li>
<li><p><strong>왜?라고 묻기</strong></p>
<pre><code> 개발자는 개발을 넘어 문제를 해결하는 사람이어야 합니다.
 최악의 개발: 개발은 실컷하고 문제를 해결 못 함
 최고의 개발: 개발도 안했는데 문제 해결
 **문제의 본질을 파악하기 위한 습관: &quot;왜?&quot;**

 혹시 풀고자 하는 문제가 어떻게 되세요?
 더 나은 해결책이 있을지 같이 고민해보려구여</code></pre></li>
<li><p>나만의 개발 공부법 찾기</p>
<pre><code> 사람마다 본인에게 맞는 개발 공부법이 있습니다
 - 책과 이론을 바탕으로 공부하는 사람
 - 실전을 바탕으로 공부하는 사람</code></pre><p> <img src="https://velog.velcdn.com/images/hi-rachel/post/156514ff-98fe-4f27-b674-709c2b87eb15/image.png" alt=""></p>
</li>
</ol>
<hr>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/2ef038e0-6abd-4580-a72c-6f19a54dd03e/image.png" alt=""></p>
<pre><code>**주니어 첫 3년에 성장 곡선의 기울기를 바꾸면 10년 후 엄청난 실력 차이가 발생한다.**</code></pre><blockquote>
<p>본인 연차에 맞는 일을 하는 건 당연한 것, 3년차가 5년차 10년차의 일을 할 수 있는 것이 정말 잘하는 개발자이다. </p>
</blockquote>
<hr>
<h3 id="✏️-세션-나에게-적용하기">✏️ 세션 나에게 적용하기</h3>
<ol>
<li><p><strong>그림으로 소통하기</strong></p>
<pre><code> 상대방이 말로 설명해주면 나도 까먹는 부분이 많아 노트를 한다.
 그림으로 보여주면 좋은 부분은 나도 먼저 그림으로 그려 보여주자.
 다이어그램 툴
 -&gt; 강연에서 소개해준 whimsical 써보려고 한다. figma, draw.io 등 써보고 제일 좋은 툴 하나로 정착할 것.</code></pre></li>
<li><p><strong>나만의 TODO List 만들기</strong>
 <img src="https://velog.velcdn.com/images/hi-rachel/post/22ef3a69-7655-4f55-b1b2-ebc1007f3134/image.png" alt=""></p>
<p> 강의를 들으면서 Google Task 쓰시는 부분이 너무 깔끔해 나도 바로 적용해 나만의 TODO List를 만들었다.
 종이에 쓰면 어디서든 쓸 수 없고, 노션에 썼을 때도 아쉬운 부분들이 있었는데 새로 만든 이 TODO List로 계속 잘 쓸 것 같다.
 사적인 부분과 일적인 부분의 TODO List를 따로 관리해야 한다고 생각했는데, 내 뇌의 백업처럼 어차피 내가 다 할 일이기 때문에 같이 정리하는 부분이 훨씬 효율적이겠다라고 깨달았다.</p>
</li>
<li><p><strong>코드를 보는 안목 기르기</strong></p>
<pre><code> 기존 코드가 마냥 우수할거라는 생각을 깨부심.
 오픈 소스 하나 전체를 까보는 일은 아직 해보지 않았다. 어려워도 도전해보자.
 불편함(Code Smell)을 느낄 수 있는 안목을 기르자.
 현실에 안주하지 말고 계속 개선할 수 있는 방법을 찾자.</code></pre></li>
<li><p><strong>왜?라고 묻기</strong></p>
<pre><code> 나도 정말 중요하다고 생각하는 부분.
 소통에서도 상대방이 왜 이런 일을 요구하는지 생각해보고 나도 말할때 왜 하려는지 설명하자.
 무지성은 항상 지양</code></pre></li>
<li><p><strong>나만의 개발 공부법 찾기</strong>
 나도 빠르게 만들어보며 배우는 것을 선호하는 편
 -&gt; 이후 더 성장하고 싶은 부분이 있으면 책 공부
 책을 읽다가 멈추는 시기였는데 두껍고 많은 책들 중 어떤 책을 읽고, 어떻게 읽어야 할지 고민이 딱 많은 시기였다. 일단 목차 활용, 여러 책 접함으로 무엇을 모르는지 깨닫고 여러 권의 책을 읽어보며 다양한 관점으로 같은 내용을 접하며 나만의 지식으로 만들자.
 실무에 바로 적용은 못해도 나중에 거름이 된다.
 주말이나 시간이 날 때마다 서점에서 책을 둘러보거나, 온라인으로라도 무슨 개발책이 나왔는지 주기적으로 둘러보는건 정말 좋은 인사이트가 된다고 생각한다.</p>
</li>
</ol>
<blockquote>
<p>개발은 좀 못해도 같이 일할 수 있지만, 아예 커뮤니케이션이 안되는 사람이랑은 같이 일할 수 없다고 생각한다.
소프트 스킬은 직장 외에서도 빛을 발할 수 있는 능력으로 하드 스킬 외에도 소프트 스킬에 대해서도 고민하는 사람이 되자.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프론트엔드 면접 대비] 자료구조]]></title>
            <link>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sun, 11 Aug 2024 14:10:12 GMT</pubDate>
            <description><![CDATA[<h1 id="자료구조">자료구조</h1>
<h3 id="데이터-구조란">데이터 구조란?</h3>
<p>데이터 구조는 데이터를 저장하고 구성하는 데 사용되는 저장소입니다. 이는 컴퓨터에서 데이터를 정리하여 효율적으로 액세스하고 업데이트할 수 있는 방법입니다. 데이터를 처리, 검색 및 저장하는 데에도 사용됩니다.</p>
<h3 id="데이터-구조의-분류">데이터 구조의 분류</h3>
<ol>
<li><p><strong>선형 데이터 구조</strong>: <strong>데이터 요소가 순차적으로 또는 선형적으로 배열</strong>되고, <strong>각 요소가 이전 및 다음 인접 요소에 연결된 데이터 구조를 선형 데이터 구조</strong>라고 합니다. 
예: 배열, 스택, 큐, 연결 리스트 등</p>
<blockquote>
<p>선형적
= 데이터를 일렬로 저장하고 연속적인 방식으로 처리하는 구조</p>
</blockquote>
</li>
<li><p><strong>정적 데이터 구조</strong>: 정적 데이터 구조는 <strong>고정된 메모리 크기</strong>를 갖습니다. 정적 데이터 구조의 요소에 액세스하는 것이 더 쉽습니다. 
예: 배열.</p>
</li>
<li><p><strong>동적 데이터 구조</strong>: 동적 데이터 구조에서는 크기가 고정되지 않습니다. 코드의 메모리(공간) 복잡도와 관련하여 효율적이라고 간주될 수 있는 런타임 중에 무작위로 업데이트될 수 있습니다. 
예: 큐, 스택 등</p>
</li>
<li><p><strong>비선형 데이터 구조</strong>: <strong>데이터 요소가 순차적으로 또는 선형적으로 배치되지 않은 데이터 구조를 비선형 데이터 구조</strong>라고 합니다. <strong>비선형 데이터 구조에서는 단일 실행으로 모든 요소를 순회할 수 없습니다</strong>. 
예: 트리 및 그래프.</p>
</li>
</ol>
<h2 id="1-배열-array">1. 배열 (Array)</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/258542ec-91b4-434c-8256-b22bac15db4c/image.png" alt=""></p>
<p>개념:
<strong>배열은 동일한 타입의 데이터를 순서대로 저장하는 자료구조</strong>입니다. JavaScript에서 배열은 여러 값을 하나의 변수에 저장할 수 있으며, 요소는 인덱스를 통해 접근할 수 있습니다.</p>
<p>시간 복잡도:</p>
<p><strong>접근: O(1)</strong>
배열의 인덱스를 통해 요소에 접근하는 것은 상수 시간에 가능합니다.</p>
<p><strong>삽입/삭제 (맨 뒤): O(1)</strong>
배열의 끝에 요소를 추가하거나 삭제하는 작업은 일반적으로 상수 시간이 걸립니다.</p>
<p><strong>삽입/삭제 (중간/앞): O(n)</strong>
중간이나 앞부분에 요소를 삽입하거나 삭제할 경우, 나머지 요소를 이동해야 하므로 선형 시간이 걸립니다.</p>
<p>활용 사례:
프론트엔드 개발에서 리스트나 컬렉션을 처리할 때 자주 사용됩니다. 예를 들어, 사용자가 입력한 데이터를 배열로 저장하고 이를 화면에 표시하는 작업을 할 때 유용합니다.</p>
<blockquote>
<p>JavaScript와 Python에서 배열(리스트)은 기본적으로 동적 배열입니다.</p>
</blockquote>
<h2 id="2-스택-stack">2. 스택 (Stack)</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/555a9635-1706-411b-a32b-6fd0d3e48698/image.png" alt=""></p>
<p>개념:
<strong>스택은 후입선출(LIFO, Last In First Out) 구조를 가진 자료구조로, 마지막에 삽입된 데이터가 가장 먼저 삭제</strong>됩니다.</p>
<p>시간 복잡도:</p>
<p><strong>삽입 (push) / 삭제 (pop): O(1)</strong>
삽입과 삭제 모두 배열의 끝에서 일어나므로, 항상 일정한 시간이 걸립니다.</p>
<p>활용 사례:
<strong>브라우저의 뒤로 가기 기능</strong>이 스택의 대표적인 예입니다. 사용자가 이전 페이지로 돌아갈 때, 스택에 저장된 이전 페이지를 꺼내어 다시 표시합니다.</p>
<h2 id="3-큐-queue">3. 큐 (Queue)</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/5bd2157b-7ab6-46b0-80ae-4d957b476e96/image.png" alt=""></p>
<p>개념:
<strong>큐는 선입선출(FIFO, First In First Out) 구조를 가진 자료구조로, 가장 먼저 들어간 데이터가 가장 먼저 나옵니다</strong>.</p>
<p>시간 복잡도:</p>
<p><strong>삽입 (enqueue): O(1)</strong></p>
<p><strong>삭제 (dequeue): O(1)</strong></p>
<p>삭제 (shift() 사용 시): O(n) (JavaScript에서 배열의 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift">shift()</a> 메서드를 사용하면, 모든 요소를 앞으로 이동해야 하므로)</p>
<p>활용 사례:
<strong>이벤트 루프나 작업 스케줄링</strong>에서 큐가 유용하게 사용됩니다.</p>
<h2 id="4-링크드-리스트-linked-list">4. 링크드 리스트 (Linked List)</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/5c9a677f-ee56-4d20-926f-8fcf4b916444/image.png" alt=""></p>
<p>개념:
<strong>링크드 리스트는 각 요소가 데이터와 다음 요소를 가리키는 포인터로 구성된 자료구조</strong>입니다. <strong>메모리 상에 요소들이 연속적으로 저장되지 않기 때문에, 삽입과 삭제가 특정 위치에서 매우 효율적</strong>입니다.</p>
<p>시간 복잡도:</p>
<p><strong>접근: O(n)</strong> (특정 요소에 접근하려면 처음부터 순차적으로 탐색해야 하므로)</p>
<p><strong>삽입/삭제 (특정 위치): O(1)</strong> (포인터만 수정하면 되기 때문에 특정 위치에서의 삽입/삭제는 매우 효율적입니다)</p>
<p><strong>삽입/삭제 (임의 위치): O(n)</strong> (특정 위치를 찾기 위해 탐색이 필요할 수 있습니다)</p>
<p>활용 사례:
프론트엔드에서 자주 사용되진 않지만, 삽입과 삭제가 빈번히 일어나는 상황에서 유용할 수 있습니다.</p>
<h2 id="5-트리-tree">5. 트리 (Tree)</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/63d37977-6f3d-453b-83e1-532ce449a957/image.png" alt=""></p>
<p>개념:
<strong>트리는 계층적인 구조를 가진 자료구조로, 각 노드가 자식 노드를 가질 수 있습니다</strong>. 이진 탐색 트리(BST)를 예로 들면, 탐색, 삽입, 삭제 연산이 효율적으로 수행될 수 있습니다.</p>
<p>시간 복잡도:</p>
<p><strong>탐색/삽입/삭제 (평균): O(log n)</strong> (이진 탐색 트리의 경우, 트리가 균형을 이루고 있을 때)</p>
<p><strong>탐색/삽입/삭제 (최악): O(n)</strong> (트리가 불균형한 경우, 즉 한쪽으로 치우친 경우)</p>
<p>활용 사례:
<strong>DOM(Document Object Model)</strong>은 트리 구조의 대표적인 예입니다. HTML 문서를 트리 구조로 나타내어 각 요소를 노드로 표현하며, 이를 통해 DOM을 조작할 때 트리 구조의 개념을 많이 활용합니다.</p>
<h3 id="이진-탐색-트리-binary-search-tree-bst">이진 탐색 트리 (Binary Search Tree, BST)</h3>
<p><strong>이진 탐색 트리는 각 노드가 최대 두 개의 자식 노드를 가지는 트리 구조로, 왼쪽 자식 노드는 항상 부모 노드보다 작은 값을 가지고, 오른쪽 자식 노드는 항상 부모 노드보다 큰 값을 가지는 특성</strong>을 가지고 있습니다. 이 특성 덕분에, 이진 탐색 트리는 빠르게 요소를 검색할 수 있는 자료구조로, 탐색, 삽입, 삭제 연산을 효율적으로 수행할 수 있습니다.</p>
<p>시간 복잡도:</p>
<p><strong>탐색/삽입/삭제 (평균): O(log n)</strong>
이진 탐색 트리는 트리가 균형을 이루고 있을 때, 각 연산이 로그 시간(logarithmic time) 내에 수행될 수 있습니다. 이는 <strong>트리의 높이가 log n</strong>에 비례하기 때문입니다.</p>
<p><strong>탐색/삽입/삭제 (최악): O(n)</strong>
트리가 한쪽으로 치우쳐져서 일직선에 가까운 경우(예: 노드들이 모두 한쪽 자식만 가지는 경우), 이진 탐색 트리는 리스트와 다를 바 없게 되어 각 연산에 선형 시간이 걸릴 수 있습니다. 이 때문에, 최악의 경우 시간 복잡도는 O(n)이 됩니다.</p>
<p>활용 사례:</p>
<ul>
<li>데이터베이스: 이진 탐색 트리는 데이터베이스에서 범위 검색, 삽입, 삭제 등의 작업을 효율적으로 수행하는 데 사용됩니다.</li>
<li>검색 알고리즘: 이진 탐색 트리는 검색 알고리즘의 기초가 되는 자료구조로, 효율적인 데이터 탐색을 위해 많이 사용됩니다.</li>
<li>자동 완성 기능: 트리의 특성을 이용해, 특정 키워드에 대해 자동 완성 기능을 구현할 때 유용합니다. 예를 들어, 검색 창에서 특정 문자를 입력할 때, 해당 문자로 시작하는 단어를 빠르게 찾는 기능을 구현할 수 있습니다.</li>
</ul>
<p>트리의 균형:</p>
<ul>
<li>자체 균형 이진 탐색 트리: AVL 트리, 레드-블랙 트리와 같은 균형 트리들은 자동으로 균형을 유지하여 최악의 시간 복잡도를 줄여줍니다.</li>
<li>트리의 불균형 문제: 일반적인 이진 탐색 트리는 삽입되는 데이터에 따라 쉽게 불균형해질 수 있기 때문에, 균형을 유지하기 위한 특별한 트리 구조를 사용하기도 합니다.</li>
</ul>
<p>이진 탐색 트리는 검색 알고리즘의 기본이 되는 중요한 자료구조로, 다양한 응용 프로그램에서 널리 사용됩니다. 특히 대용량 데이터 세트에서 빠른 검색, 삽입, 삭제 작업이 필요한 경우에 매우 유용합니다.</p>
<h3 id="👉-이진-트리의-종류">👉 이진 트리의 종류</h3>
<ol>
<li><strong>포화 이진 트리 (Full Binary Tree)</strong></li>
</ol>
<pre><code>        1
      /   \
     2     3
    / \   / \
   4   5 6   7</code></pre><ul>
<li><strong>포화 이진 트리는 모든 레벨이 완전히 채워진 이진 트리</strong>입니다. 즉, 모든 노드가 두 개의 자식 노드를 가지거나, 리프 노드(말단 노드)는 자식이 없는 노드로 구성됩니다.</li>
<li>포화 이진 트리는 레벨 h에서 최대 2^h - 1개의 노드를 가집니다.</li>
</ul>
<ol start="2">
<li><strong>완전 이진 트리 (Complete Binary Tree)</strong></li>
</ol>
<pre><code>        1
      /   \
     2     3
    / \   /
   4   5 6</code></pre><ul>
<li><strong>완전 이진 트리는 모든 레벨이 완전히 채워지지 않아도 되지만, 마지막 레벨의 노드들은 왼쪽에서 오른쪽 순서대로 채워져야 합니다</strong>.</li>
</ul>
<p>즉, 완전 이진 트리는 트리의 모든 레벨이 채워져 있지 않아도, 마지막 레벨에서 노드들이 왼쪽부터 차례대로 배치되어야 합니다. 완전 이진 트리는 이진 힙(Heap)과 같은 자료구조의 기반으로 사용됩니다.</p>
<ol start="3">
<li><strong>균형 이진 트리 (Balanced Binary Tree)</strong></li>
</ol>
<pre><code>        3
      /   \
     2     5
    /     / \
   1     4   6</code></pre><ul>
<li><strong>균형 이진 트리는 모든 노드의 왼쪽 서브트리와 오른쪽 서브트리의 높이 차이가 1 이하인 트리</strong>입니다. 즉, 트리가 한쪽으로 치우치지 않고, 최대한 균형을 이루고 있습니다.</li>
<li>균형 트리의 대표적인 종류로는 AVL 트리와 레드-블랙 트리가 있습니다. 이러한 트리들은 자가 균형(self-balancing) 트리로, 삽입이나 삭제 연산 후에도 트리의 균형을 유지하기 위해 <strong>재조정(rebalancing)</strong>을 수행합니다.</li>
</ul>
<ol start="4">
<li><strong>이진 힙 (Binary Heap)</strong></li>
</ol>
<pre><code>        9
      /   \
     7     6
    / \   / \
   5   3 2   4</code></pre><ul>
<li>이진 힙은 이진 트리의 일종으로, <strong>최대 힙(Max Heap)</strong>과 <strong>최소 힙(Min Heap)</strong>으로 구분됩니다.<ul>
<li>최대 힙: 부모 노드가 자식 노드보다 크거나 같은 값을 가집니다. 루트 노드가 가장 큰 값을 가집니다.</li>
<li>최소 힙: 부모 노드가 자식 노드보다 작거나 같은 값을 가집니다. 루트 노드가 가장 작은 값을 가집니다.</li>
</ul>
</li>
<li>이진 힙은 완전 이진 트리의 형태를 가지며, 우선순위 큐의 구현에 주로 사용됩니다.</li>
</ul>
<ol start="5">
<li><strong>AVL 트리 (AVL Tree)</strong></li>
</ol>
<pre><code>    2
   / \
  1   3</code></pre><ul>
<li>AVL 트리는 균형 이진 탐색 트리로, 모든 노드의 왼쪽 서브트리와 오른쪽 서브트리의 높이 차이가 최대 1을 넘지 않도록 유지됩니다.</li>
<li>삽입이나 삭제 연산 후 트리가 불균형해지면, <strong>회전 연산(Rotation)</strong>을 통해 트리를 재조정하여 균형을 유지합니다.</li>
<li>AVL 트리는 검색, 삽입, 삭제 연산이 O(log n) 시간 복잡도를 유지합니다.</li>
</ul>
<ol start="6">
<li><strong>레드-블랙 트리 (Red-Black Tree)</strong></li>
</ol>
<pre><code>       (B) 10
       /    \
   (R) 5    (R) 20
    / \       /  \
(B) 3 (B) 7 (B) 15 (B) 25</code></pre><ul>
<li>레드-블랙 트리는 또 다른 종류의 균형 이진 탐색 트리로, 각 노드가 레드 또는 블랙 색상으로 색칠되어 있습니다. 이 색상을 이용해 트리의 균형을 유지합니다.</li>
<li>레드-블랙 트리는 트리의 균형을 유지하는 데 몇 가지 규칙을 따릅니다(예: 루트와 리프 노드는 항상 블랙, 레드 노드의 자식은 반드시 블랙 등).</li>
<li>레드-블랙 트리는 삽입, 삭제 연산 후에도 O(log n) 시간 복잡도를 유지합니다.</li>
</ul>
<ol start="7">
<li><strong>트라이 (Trie)</strong></li>
</ol>
<pre><code>       (B) 10
       /    \
   (R) 5    (R) 20
    / \       /  \
(B) 3 (B) 7 (B) 15 (B) 25</code></pre><ul>
<li><strong>트라이(Trie)</strong>는 이진 트리의 특수한 형태로, 문자열 또는 시퀀스 데이터를 저장하고 검색하는 데 최적화된 트리 구조입니다.</li>
<li>각 노드는 문자열의 문자 또는 시퀀스의 요소를 저장하며, 루트에서부터 리프까지의 경로가 특정 문자열 또는 시퀀스를 나타냅니다.</li>
<li>주로 사전(dictionary) 데이터 구조나 문자열 검색 기능에 사용됩니다.</li>
</ul>
<p>요약</p>
<ul>
<li>이진 탐색 트리 (BST): 노드의 왼쪽 서브트리는 부모보다 작고, 오른쪽 서브트리는 부모보다 큰 값을 가집니다. 데이터 검색, 삽입, 삭제에 효율적입니다.</li>
<li>완전 이진 트리 (Complete Binary Tree): 모든 레벨이 완전히 채워지며, 마지막 레벨의 노드도 왼쪽에서 오른쪽 순서대로 채워집니다. 힙과 같은 자료구조의 기반으로 사용됩니다.</li>
<li>포화 이진 트리: 모든 레벨이 완전히 채워진 트리입니다.</li>
<li>균형 이진 트리: 노드의 서브트리 높이 차이가 최대 1인 트리입니다. (예: AVL 트리, 레드-블랙 트리)</li>
<li>이진 힙: 완전 이진 트리로, 우선순위 큐 구현에 사용됩니다.</li>
<li>트라이: 문자열이나 시퀀스 데이터를 효율적으로 관리하는 트리 구조입니다.</li>
</ul>
<h3 id="힙heap">힙(Heap)</h3>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/5a04ccd5-bb13-44a6-be2e-47fa8716d096/image.jpg" alt=""></p>
<p>힙(Heap)은 <strong>완전 이진 트리(Complete Binary Tree)</strong>를 기반으로 하는 자료구조로, <strong>부모 노드가 자식 노드보다 항상 큰 값을 가지는 최대 힙(Max Heap)</strong> 또는 <strong>부모 노드가 자식 노드보다 항상 작은 값을 가지는 최소 힙(Min Heap)</strong>의 특성을 가집니다. 힙은 주로 우선순위 큐(Priority Queue)를 구현하는 데 사용되며, 데이터의 최대값 또는 최소값을 빠르게 추출할 수 있는 구조입니다.</p>
<p>시간 복잡도:</p>
<p><strong>삽입 (Insert): O(log n)</strong></p>
<p><strong>새로운 요소가 삽입되면, 트리의 가장 마지막 위치에 임시로 추가한 후, 힙의 속성을 유지하기 위해 부모 노드와 비교하여 자리를 교환합니다(상향 이동)</strong>. 이 작업은 트리의 높이에 비례하는 시간이 걸리므로, <strong>시간 복잡도는 O(log n)</strong>입니다.</p>
<p><strong>삭제 (Extract-Max 또는 Extract-Min): O(log n)</strong>
<strong>힙에서 루트 노드(최대값 또는 최소값)를 삭제한 후, 트리의 가장 마지막 요소를 루트 위치로 옮기고, 자식 노드들과 비교하여 힙의 속성을 유지하기 위해 자리를 교환합니다(하향 이동). 이 작업 역시 트리의 높이에 비례하는 시간</strong>이 걸립니다.</p>
<p><strong>최대값 또는 최소값 접근 (Find-Max 또는 Find-Min): O(1)</strong>
<strong>힙에서 최대값 또는 최소값은 항상 루트 노드에 위치하므로, 접근은 상수 시간에 가능</strong>합니다.</p>
<p>활용 사례:</p>
<ul>
<li><strong>우선순위 큐</strong>: 힙은 우선순위 큐를 구현하는 데 매우 적합한 자료구조입니다. <strong>우선순위 큐는 작업 스케줄링, 네트워크 트래픽 관리, 다익스트라 알고리즘 등 다양한 알고리즘에서 사용</strong>됩니다.</li>
<li><strong>힙 정렬 (Heap Sort)</strong>: 힙을 이용해 정렬 알고리즘을 구현할 수 있습니다. 힙 정렬은 힙에 모든 요소를 삽입한 후, 최대값(또는 최소값)을 하나씩 꺼내어 정렬된 배열에 삽입하는 방식으로 동작합니다. 힙 정렬의 시간 복잡도는 O(n log n)이며, 불안정 정렬에 속합니다.</li>
<li><strong>최대값 또는 최소값 추출</strong>: 힙을 사용하면 최대값 또는 최소값을 효율적으로 추출할 수 있기 때문에, 이러한 작업이 빈번히 요구되는 시스템에서 유용합니다.</li>
</ul>
<p>힙의 특징:</p>
<ul>
<li><strong>완전 이진 트리 형태 유지</strong>: <strong>힙은 항상 완전 이진 트리의 형태를 유지</strong>합니다. <strong>이는 힙이 완벽하게 채워지지 않은 마지막 레벨을 제외하고, 모든 레벨이 완전히 채워져 있는 트리라는 것을 의미</strong>합니다.</li>
<li><strong>힙의 속성 유지</strong>: 삽입과 삭제 시 힙의 구조적 속성과 정렬 속성을 유지하기 위한 작업이 수행됩니다. 이를 통해 힙의 특성을 항상 만족하게 됩니다.</li>
<li><strong>Heapify 과정</strong>: 힙이 아닌 배열을 힙으로 변환하는 과정을 “Heapify”라고 합니다. 이는 트리의 특정 노드에서 시작하여 아래로 내려가며 힙의 특성을 유지하도록 하는 작업입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/fb9c2c0a-3f3f-4f48-980e-35b801fbe9cc/image.png" alt="">
힙의 종류:</p>
<ul>
<li>최대 힙 (Max Heap): 부모 노드의 값이 자식 노드의 값보다 크거나 같도록 유지하는 힙. 최댓값을 빠르게 추출할 수 있습니다.</li>
<li>최소 힙 (Min Heap): 부모 노드의 값이 자식 노드의 값보다 작거나 같도록 유지하는 힙. 최솟값을 빠르게 추출할 수 있습니다.</li>
</ul>
<p>힙은 이진 트리 기반의 효율적인 자료구조로, 우선순위 큐와 같은 시스템에서 매우 유용하게 사용됩니다. 삽입과 삭제의 시간 복잡도가 O(log n)으로 유지되기 때문에, 큰 규모의 데이터를 다루는 알고리즘에서도 중요한 역할을 합니다.</p>
<h3 id="우선순위-큐">우선순위 큐</h3>
<p><strong>우선순위 큐(Priority Queue)</strong>는 <strong>각 요소가 우선순위(priority)</strong>를 가지며, 우선순위에 따라 요소를 관리하고 처리하는 자료구조입니다. 일반적인 큐(Queue)에서는 FIFO(First In, First Out) 원칙에 따라 요소가 삽입된 순서대로 처리되지만, <strong>우선순위 큐에서는 가장 높은 우선순위를 가진 요소가 먼저 처리</strong>됩니다.</p>
<p><strong>우선순위 큐의 특징</strong></p>
<ol>
<li><p><strong>우선순위 기반 처리</strong>:
각 요소는 데이터와 함께 우선순위 값을 가지며, 이 우선순위 값에 따라 큐에서의 순서가 결정됩니다.
예를 들어, 응급실에서 환자를 처리하는 시나리오를 생각해 볼 수 있습니다. 환자가 병원에 도착한 순서대로가 아니라, 환자의 상태(우선순위)에 따라 먼저 치료가 필요하거나, 덜 긴급한 환자가 나중에 처리됩니다.</p>
</li>
<li><p>삽입(Insertion):
새로운 요소가 우선순위 큐에 삽입될 때, 해당 요소는 기존의 요소들과 비교되어 적절한 위치에 삽입됩니다. <strong>우선순위가 높을수록 큐의 앞쪽에 배치</strong>됩니다.</p>
</li>
<li><p>삭제(Deletion):
<strong>우선순위 큐에서 삭제 연산은 일반적으로 가장 높은 우선순위를 가진 요소를 제거하는 연산</strong>입니다. 이로 인해 우선순위 큐는 우선순위가 높은 요소가 항상 가장 먼저 제거되도록 보장합니다.</p>
</li>
<li><p><strong>최대 우선순위 큐와 최소 우선순위 큐</strong>:</p>
</li>
</ol>
<ul>
<li>최대 우선순위 큐(Max-Priority Queue): 가장 높은 우선순위를 가진 요소가 가장 먼저 제거되는 큐.</li>
<li>최소 우선순위 큐(Min-Priority Queue): 가장 낮은 우선순위를 가진 요소가 가장 먼저 제거되는 큐.</li>
</ul>
<p><strong>우선순위 큐의 구현</strong></p>
<p>우선순위 큐는 여러 가지 방법으로 구현될 수 있으며, 대표적인 구현 방법은 다음과 같습니다:</p>
<ol>
<li><p>배열(Array):
배열을 사용하여 우선순위 큐를 구현할 수 있습니다. <strong>요소를 배열에 삽입할 때, 우선순위에 따라 배열을 정렬한 후, 가장 앞쪽에 위치한 요소를 제거</strong>합니다. 삽입과 삭제 시 정렬이 필요하므로 시간 복잡도는 비효율적일 수 있습니다.</p>
</li>
<li><p>정렬된 연결 리스트(Sorted Linked List):
연결 리스트를 우선순위 순으로 정렬된 상태로 유지하면서 요소를 삽입하는 방법입니다. <strong>삽입 시 정렬된 위치를 찾아 삽입하므로, 삽입 연산이 O(n)</strong>의 시간 복잡도를 가집니다.</p>
</li>
<li><p>힙(Heap):
<strong>힙(Heap)은 우선순위 큐를 효율적으로 구현하기 위한 자료구조</strong>입니다. 힙은 <strong>이진 트리 형태</strong>로 구현되며, <strong>최대 힙(Max-Heap)이나 최소 힙(Min-Heap)을 사용해 우선순위 큐의 삽입과 삭제 연산을 O(log n) 시간 복잡도로 수행</strong>할 수 있습니다.
예를 들어, 최대 힙에서는 부모 노드가 항상 자식 노드보다 크거나 같으며, 루트 노드가 큐에서 가장 높은 우선순위를 가진 요소가 됩니다.</p>
</li>
</ol>
<p>⭐ <strong>우선순위 큐의 활용 사례</strong></p>
<ol>
<li><p><strong>스케줄링</strong>:
<strong>운영 체제의 작업 스케줄러는 작업의 우선순위에 따라 CPU 자원을 할당하는 데 우선순위 큐를 사용</strong>합니다. 중요한 작업이 먼저 처리될 수 있도록 보장합니다.</p>
</li>
<li><p><strong>다익스트라 알고리즘(Dijkstra’s Algorithm)</strong>:
<strong>그래프에서 최단 경로를 찾는 다익스트라 알고리즘은 우선순위 큐를 사용하여 가장 짧은 경로를 먼저 탐색</strong>합니다.</p>
</li>
<li><p><strong>이벤트 관리 시스템</strong>:
<strong>이벤트 처리 시스템에서 긴급한 이벤트를 먼저 처리해야 할 때, 우선순위 큐가 사용</strong>될 수 있습니다.</p>
</li>
<li><p><strong>데이터 흐름 관리</strong>:
<strong>네트워크 패킷 처리에서 우선순위 큐는 중요한 패킷이 먼저 전송되도록 관리하는 데 사용</strong>됩니다.</p>
</li>
</ol>
<h3 id="mst최소-신장-트리란">MST(최소 신장 트리)란?</h3>
<p>MST(Minimum spannig Tree)는 그래프속성을 갖고 사이클이 없는 정점을 통해 연결된 간선의 합이 최소인 것을 의미합니다.</p>
<h2 id="6-그래프-graph">6. 그래프 (Graph)</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/2083a4bb-9f30-4c83-a2e3-83a1f5b5b44f/image.jpg" alt=""></p>
<p>개념:
<strong>그래프는 노드와 그 노드들을 연결하는 간선으로 이루어진 자료구조</strong>입니다. 다양한 관계를 표현할 수 있으며, 이를 통해 복잡한 문제를 해결할 수 있습니다.</p>
<p>시간 복잡도:</p>
<p><strong>탐색 (DFS/BFS): O(V + E) (여기서 V는 노드의 수, E는 간선의 수입니다)</strong></p>
<p>활용 사례:
소셜 네트워크에서 친구 관계를 표현하거나, 지도와 같은 네트워크 데이터를 처리할 때 그래프 구조가 사용될 수 있습니다.</p>
<h2 id="7-딕셔너리-dictionary와-해시-테이블hash-table">7. 딕셔너리 (Dictionary)와 해시 테이블(Hash Table)</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/2f8df1d3-5496-4734-9570-f85d9c2a6e09/image.png" alt=""></p>
<h3 id="해시-테이블">해시 테이블</h3>
<p>해시 테이블은 자료구조의 일종으로, 키-값 쌍을 저장하고 빠르게 데이터를 검색할 수 있도록 설계되었습니다. <strong>해시 함수(Hash Function)를 사용하여 키를 해시값으로 변환</strong>하고, 이 해시값을 기반으로 데이터를 저장할 위치를 결정합니다. 해시 테이블은 많은 프로그래밍 언어에서 딕셔너리나 맵과 같은 자료구조의 기반이 됩니다.</p>
<h3 id="딕셔너리">딕셔너리</h3>
<p><strong>딕셔너리는 키와 값의 쌍으로 이루어진 자료구조</strong>입니다. <strong>각 키는 고유하며, 해당 키를 통해 연결된 값을 빠르게 찾고 수정할 수 있습니다</strong>. 딕셔너리는 파이썬과 같은 언어에서 사용되며, 내부적으로 해시 테이블을 사용하여 키-값 쌍을 저장합니다. 따라서 딕셔너리는 해시 테이블의 구체적인 구현 중 하나입니다.</p>
<p>시간 복잡도:</p>
<p><strong>삽입/삭제/탐색: O(1) (평균적인 경우, 해시 충돌이 없는 경우)</strong></p>
<p><strong>삽입/삭제/탐색: O(n) (최악의 경우, 해시 충돌이 많이 발생할 때)</strong></p>
<p>활용 사례:
딕셔너리는 데이터를 효율적으로 저장하고 조회해야 하는 상황에서 자주 사용됩니다. 예를 들어, 사용자 정보를 키로 저장하고, 해당 키를 통해 빠르게 사용자 데이터를 검색하는 상황에 유용합니다.</p>
<h3 id="javascript의-object와-map">JavaScript의 Object와 Map</h3>
<blockquote>
<p>JavaScript의 Object와 Map은 내부적으로 해시 테이블 자료구조 기반으로 구현되어 있습니다. 각각의 동작 원리와 차이점을 알아보겠습니다.</p>
</blockquote>
<ol>
<li><p>객체(Object)</p>
<p><strong>객체(Object)</strong>는 JavaScript에서 가장 기본적인 데이터 구조 중 하나로, 키-값 쌍을 저장하는 비순차적 데이터 구조입니다.</p>
<p><strong>동작 원리</strong></p>
<ol>
<li>키의 해싱: <strong>객체에 새로운 키-값 쌍을 추가할 때, JavaScript 엔진은 키(대부분 문자열)를 해시 함수에 넣어 해시 값을 계산</strong>합니다. 이 <strong>해시 값은 키를 고유하게 식별할 수 있는 숫자 또는 문자열로 변환</strong>됩니다.</li>
<li>해시 버킷에 저장: 계산된 해시 값은 해시 테이블의 특정 인덱스(해시 버킷)를 가리키게 됩니다. 이 인덱스에 해당하는 위치에 키-값 쌍이 저장됩니다. 만약 해당 위치에 이미 다른 키-값 쌍이 있다면, JavaScript는 체이닝(Chaining)이나 오픈 어드레싱(Open Addressing) 같은 방법으로 충돌을 해결합니다.</li>
<li>검색: 객체에서 값을 검색할 때, JavaScript는 키를 해시 함수에 넣어 해시 값을 계산하고, 그 값을 사용해 해시 테이블에서 해당 키-값 쌍을 빠르게 찾습니다.</li>
<li>충돌 처리: 만약 두 개 이상의 키가 동일한 해시 값을 가지는 경우(해시 충돌), JavaScript는 그 위치에서 해당 키에 대해 추가적인 비교를 수행하여 정확한 값을 반환합니다.</li>
</ol>
</li>
<li><p>Map</p>
<p>Map은 객체와 유사하게 키-값 쌍을 저장하는 자료구조지만, 몇 가지 중요한 차이점이 있습니다. Map은 객체보다 더 복잡한 자료구조로, 특히 <strong>다양한 타입의 키(예: 객체, 함수 등)를 지원</strong>합니다. Map 또한 해시 테이블을 사용하여 구현되며, 동작 원리는 다음과 같습니다:</p>
<p><strong>동작 원리</strong></p>
<ol>
<li>다양한 타입의 키: <strong>Map은 키로 문자열뿐만 아니라 객체, 함수 등 모든 데이터 타입을 허용</strong>합니다. 이 점에서 객체와 차별화됩니다.</li>
<li>해시 함수의 유연성: Map은 키가 어떤 타입이든 간에 해시 값을 계산할 수 있도록 보다 복잡한 해시 함수를 사용합니다. 객체나 함수와 같은 복잡한 타입의 키를 사용할 때는, 이러한 키의 메모리 주소나 특정 속성을 이용하여 해시 값을 생성할 수 있습니다.</li>
<li>빠른 접근: Map도 객체처럼 평균 O(1)의 시간 복잡도로 데이터를 검색할 수 있습니다. 이는 해시 테이블이 해시 값을 사용해 키-값 쌍을 저장하고 검색하기 때문입니다.</li>
<li>순서 보장: 객체와 달리, Map은 삽입된 순서를 유지합니다. 즉, Map에 삽입된 순서대로 데이터가 반환됩니다.</li>
<li>메서드 지원: Map은 객체보다 더 풍부한 메서드를 제공합니다. 예를 들어, map.size로 크기를 알 수 있고, map.has()로 키의 존재 여부를 확인할 수 있으며, map.forEach()로 순회할 수 있습니다.</li>
</ol>
</li>
</ol>
<blockquote>
<p>스택, 큐, 그래프, 트리, 해시 테이블 각 주요 자료구조의 기본적인 개념 설명, 예시 1개 정도 말할 수 있도록 숙지하는 것을 추천합니다.
이후 추가적인 개념, 차이점 위주 꼬리 질문을 준비하면 됩니다.</p>
</blockquote>
<hr>
<h1 id="자료구조-관련-면접-질문">자료구조 관련 면접 질문</h1>
<h2 id="1-배열-array-1">1. 배열 (Array)</h2>
<h3 id="⭐-배열과-링크드-리스트의-차이점은-무엇인가요">⭐ 배열과 링크드 리스트의 차이점은 무엇인가요?</h3>
<p><strong>배열은 인덱스를 통해 요소에 직접 접근할 수 있는 반면, 링크드 리스트는 요소 접근에 순차 탐색이 필요</strong>합니다. 따라서 배열 요소에 접근할 때는 O(1)의 시간 복잡도를 가지고, 링크드 리스트는 O(n)을 가집니다. 삽입/삭제는 배열의 중간이나 앞 부분에서 이루어질 경우 O(n), 링크드 리스트는 O(1)의 시간 복잡도를 가집니다. 하지만 특정 위치를 찾기 위한 탐색이 필요한 경우 O(n)입니다. 또한, 배열은 고정된 크기나 동적 배열로 메모리 할당이 이루어지지만, 링크드 리스트는 필요할 때마다 동적으로 메모리를 할당합니다.</p>
<h3 id="javascript에서-배열의-길이를-변경하는-방법은-무엇인가요">JavaScript에서 배열의 길이를 변경하는 방법은 무엇인가요?</h3>
<p>JavaScript에서 배열의 길이는 length 속성을 수정하거나, push, pop, shift, unshift 같은 메서드를 사용해서 조절할 수 있습니다.</p>
<p>length 속성 변경: 배열의 length 속성을 직접 변경하여 배열의 크기를 조절할 수 있습니다. 이 방법은 배열을 축소하거나 확장할 때 유용합니다.</p>
<pre><code class="language-javascript">let arr = [1, 2, 3, 4, 5];
arr.length = 3; // 배열의 길이가 3으로 축소, arr은 [1, 2, 3]
arr.length = 5; // 배열의 길이가 5로 확장, arr은 [1, 2, 3, &lt;2 empty items&gt;]</code></pre>
<p>push, pop, shift, unshift 메서드 사용:</p>
<ul>
<li>push(): 배열의 끝에 요소를 추가합니다.</li>
<li>pop(): 배열의 끝에서 요소를 제거합니다.</li>
<li>shift(): 배열의 앞에서 요소를 제거합니다.</li>
<li>unshift(): 배열의 앞에 요소를 추가합니다.
이 메서드들은 배열의 크기를 동적으로 조절합니다.</li>
</ul>
<pre><code class="language-javascript">arr.push(6); // [1, 2, 3, 4, 5, 6]
arr.pop(); // [1, 2, 3, 4, 5]
arr.shift(); // [2, 3, 4, 5]
arr.unshift(1); // [1, 2, 3, 4, 5]</code></pre>
<h3 id="javascript의-배열과-다른-언어의-배열예-c-java과의-차이점은-무엇인가요">JavaScript의 배열과 다른 언어의 배열(예: C, Java)과의 차이점은 무엇인가요?</h3>
<p><strong>JavaScript 배열은 동적이고, 다양한 타입을 저장</strong>할 수 있으며, 해시 테이블처럼 동작할 수도 있습니다. 반면, C와 Java 배열은 고정 크기고, 타입이 정해져 있어요. 또한, C/Java에서는 배열 선언 시 메모리가 고정됩니다.</p>
<h2 id="2-스택-stack-1">2. 스택 (Stack)</h2>
<h3 id="스택을-사용한-실제-예를-들어-보세요">스택을 사용한 실제 예를 들어 보세요.</h3>
<p>예를 들어 스택은 브라우저의 뒤로 가기/앞으로 가기 기능에서 사용됩니다. 가장 최근 페이지를 스택에 쌓아두고, 뒤로 가기를 하면 스택에서 그 페이지를 꺼내와 표시합니다.</p>
<h3 id="재귀와-스택의-관계에-대해-설명해보세요">재귀와 스택의 관계에 대해 설명해보세요.</h3>
<p><strong>재귀 함수가 호출될 때마다 호출 스택에 함수가 쌓이고, 함수가 종료되면 스택에서 제거</strong>됩니다. 그래서 재귀 호출의 순서가 스택에 의해 관리됩니다.</p>
<h2 id="3-큐-queue-1">3. 큐 (Queue)</h2>
<h3 id="큐를-사용하여-이벤트-루프를-구현할-수-있는-방법을-설명해보세요">큐를 사용하여 이벤트 루프를 구현할 수 있는 방법을 설명해보세요.</h3>
<p>JavaScript의 이벤트 루프는 큐를 이용해 비동기 작업을 관리합니다. 작업이 완료되면 큐에 콜백이 추가되고, 콜 스택이 비면 이벤트 루프가 이 콜백을 실행합니다.</p>
<h3 id="fifo-구조의-큐와-lifo-구조의-스택의-차이점은-무엇인가요">FIFO 구조의 큐와 LIFO 구조의 스택의 차이점은 무엇인가요?</h3>
<p>큐는 먼저 들어온 데이터가 먼저 처리되고, 스택은 나중에 들어온 데이터가 먼저 처리됩니다. 그래서 큐는 순차적으로 처리할 때, 스택은 뒤에서부터 처리할 때 사용됩니다.</p>
<h2 id="4-링크드-리스트-linked-list-1">4. 링크드 리스트 (Linked List)</h2>
<h3 id="단일-연결-리스트와-이중-연결-리스트의-차이점은-무엇인가요">단일 연결 리스트와 이중 연결 리스트의 차이점은 무엇인가요?</h3>
<p>단일 연결 리스트는 각 노드가 다음 노드만 가리키지만(포인터), 이중 연결 리스트는 이전 노드도 가리킵니다. 그래서 이중 연결 리스트는 양방향으로 탐색할 수 있습니다.</p>
<h3 id="javascript에서-링크드-리스트를-직접-구현해본-경험이-있나요-또는-설명해보세요">JavaScript에서 링크드 리스트를 직접 구현해본 경험이 있나요? (또는 설명해보세요)</h3>
<p>JavaScript에서 노드를 객체로 만들고, next 속성을 사용해 다음 노드를 가리키는 방식으로 링크드 리스트를 구현할 수 있습니다. 이로써 순차적으로 요소를 탐색할 수 있습니다.</p>
<h2 id="5-트리-tree-1">5. 트리 (Tree)</h2>
<h3 id="트리와-그래프의-차이점은-무엇인가요">트리와 그래프의 차이점은 무엇인가요?</h3>
<p>트리는 사이클이 없는 계층적 구조이며, 각 노드가 자식 노드를 가질 수 있지만 부모는 하나만 가질 수 있습니다. 반면, 그래프는 노드 간에 여러 개의 연결이 있을 수 있으며, 사이클이 존재할 수 있습니다.</p>
<h3 id="이진-탐색-트리의-특징과-장점은-무엇인가요">이진 탐색 트리의 특징과 장점은 무엇인가요?</h3>
<p>이진 탐색 트리는 왼쪽 자식은 부모보다 작고, 오른쪽 자식은 부모보다 큽니다. 이를 통해 검색, 삽입, 삭제가 평균적으로 O(log n)으로 효율적인 시간 복잡도를 가집니다.</p>
<h2 id="6-힙-heap">6. 힙 (Heap)</h2>
<h3 id="우선순위-큐와-힙의-관계를-설명해보세요">우선순위 큐와 힙의 관계를 설명해보세요.</h3>
<p>우선순위 큐는 각 요소에 우선순위를 부여하는 큐입니다. 힙은 이 우선순위 큐를 효율적으로 구현하기 위한 자료구조로, 최대값이나 최소값을 빠르게 추출할 수 있습니다.</p>
<h3 id="힙-정렬에-대해-설명해보세요">힙 정렬에 대해 설명해보세요.</h3>
<p>힙 정렬은 힙을 이용해 데이터를 정렬하는 방법입니다. 힙에 요소를 추가하고, 최대값이나 최소값을 반복적으로 꺼내면서 정렬된 배열을 만듭니다.</p>
<h2 id="7-그래프-graph">7. 그래프 (Graph)</h2>
<h3 id="dfs와-bfs의-차이점은-무엇인가요">DFS와 BFS의 차이점은 무엇인가요?</h3>
<p>DFS는 깊이 우선 탐색으로, 한 노드의 자식 노드를 모두 탐색한 후 다음 노드로 이동하며, BFS는 너비 우선 탐색으로, 현재 노드의 모든 인접 노드를 탐색한 후 다음 단계로 이동합니다.</p>
<h3 id="그래프를-활용한-프론트엔드-애플리케이션의-예를-들어보세요">그래프를 활용한 프론트엔드 애플리케이션의 예를 들어보세요.</h3>
<p>소셜 네트워크에서 친구 추천 알고리즘이나, 지도 앱에서 최단 경로 탐색 등이 그래프를 활용한 예가 있습니다.</p>
<h2 id="8-딕셔너리-dictionary">8. 딕셔너리 (Dictionary)</h2>
<h3 id="해시맵에서-충돌이-발생할-때-해결-방법은-무엇인가요">해시맵에서 충돌이 발생할 때 해결 방법은 무엇인가요?</h3>
<blockquote>
<p><strong>해시 충돌이란?</strong>
<strong>서로 다른 두 입력(예: apple과 orange)이 같은 해시 값을 생성하여, 같은 해시 버킷에 저장되어야 하는 상황</strong>을 말합니다. 해시 함수가 이상적이라도, 무한한 수의 입력을 고정된 크기의 해시 값으로 매핑하기 때문에 충돌은 필연적으로 발생할 수 있습니다.</p>
</blockquote>
<p>해시맵에서 충돌이 발생하면, 체이닝이나 오픈 어드레싱 같은 방법으로 해결할 수 있습니다. <strong>체이닝은 동일한 해시 값을 가진 요소들을 리스트로 저장</strong>하고, <strong>오픈 어드레싱은 다른 빈 슬롯을 찾아 저장</strong>합니다.</p>
<h3 id="체이닝-오픈-어드레싱이란">체이닝, 오픈 어드레싱이란?</h3>
<ol>
<li><p><strong>체이닝 (Chaining)</strong></p>
<p><strong>체이닝은 해시 충돌이 발생할 때, 동일한 해시 값을 가진 키-값 쌍들을 리스트(또는 링크드 리스트)</strong>에 저장하는 방법입니다. 해시 테이블의 각 슬롯(해시 버킷)이 이 리스트를 가리키게 됩니다.</p>
<p>새로운 요소가 동일한 해시 값을 가질 경우, 해당 리스트의 끝에 추가됩니다. 검색 시, 해당 해시 값을 가진 리스트를 탐색하여 올바른 키를 찾아 값을 반환합니다.</p>
<pre><code>해시 테이블 예시 (체이닝):
해시 버킷 1: [ (&quot;apple&quot;, 2), (&quot;orange&quot;, 5) ]
해시 버킷 2: [ (&quot;banana&quot;, 3) ]
해시 버킷 3: [ (&quot;grape&quot;, 7) ]</code></pre><p>여기서 apple과 orange가 동일한 해시 값을 가져서 동일한 해시 버킷 1에 리스트 형태로 저장됩니다.</p>
</li>
<li><p><strong>오픈 어드레싱 (Open Addressing)</strong></p>
<p><strong>오픈 어드레싱은 충돌이 발생했을 때, 해시 테이블 내에서 다른 빈 슬롯을 찾아 그 자리에 키-값 쌍을 저장하는 방법</strong>입니다. 따라서 해시 테이블 자체가 키-값 쌍을 모두 저장하는 구조가 됩니다.</p>
<p>오픈 어드레싱에는 여러 가지 전략이 있습니다:</p>
<ul>
<li>선형 탐사(Linear Probing): 충돌이 발생하면, 그 다음 연속적인 슬롯을 탐색하여 빈 슬롯을 찾습니다.</li>
<li>제곱 탐사(Quadratic Probing): 충돌이 발생하면, 일정한 간격(예: 1, 4, 9, …)을 두고 슬롯을 탐색합니다.</li>
<li>이중 해싱(Double Hashing): 두 번째 해시 함수를 사용하여 새로운 슬롯을 결정합니다.</li>
</ul>
<pre><code>해시 테이블 예시 (오픈 어드레싱):
해시 버킷 1: (&quot;apple&quot;, 2)
해시 버킷 2: (&quot;banana&quot;, 3)
해시 버킷 3: (&quot;orange&quot;, 5)  // &quot;orange&quot;는 원래 해시 버킷 1에 들어가야 했지만, 충돌로 인해 해시 버킷 3으로 이동.
해시 버킷 4: (&quot;grape&quot;, 7)</code></pre></li>
</ol>
<h3 id="딕셔너리와-배열의-차이점은-무엇인가요">딕셔너리와 배열의 차이점은 무엇인가요?</h3>
<p>딕셔너리는 키-값 쌍으로 데이터를 저장하며, 각 키는 고유합니다. 배열은 인덱스를 통해 데이터를 순서대로 저장하고, 값이 중복될 수 있습니다.</p>
<hr>
<blockquote>
<p>각 자료 구조 사진의 출처는 <a href="https://www.geeksforgeeks.org/data-structures/">geeksforgeeks</a>입니다.</p>
</blockquote>
<hr>
<blockquote>
<p>추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Web Vitals 최적화의 중요성과 방법, 주요 지표, Lighthouse 측정 항목]]></title>
            <link>https://velog.io/@hi-rachel/Web-Vitals-%EC%B5%9C%EC%A0%81%ED%99%94%EC%9D%98-%EC%A4%91%EC%9A%94%EC%84%B1%EA%B3%BC-%EB%B0%A9%EB%B2%95-%EC%A3%BC%EC%9A%94-%EC%A7%80%ED%91%9C-feat.-Lighthouse-%EC%B8%A1%EC%A0%95-%ED%95%AD%EB%AA%A9</link>
            <guid>https://velog.io/@hi-rachel/Web-Vitals-%EC%B5%9C%EC%A0%81%ED%99%94%EC%9D%98-%EC%A4%91%EC%9A%94%EC%84%B1%EA%B3%BC-%EB%B0%A9%EB%B2%95-%EC%A3%BC%EC%9A%94-%EC%A7%80%ED%91%9C-feat.-Lighthouse-%EC%B8%A1%EC%A0%95-%ED%95%AD%EB%AA%A9</guid>
            <pubDate>Sun, 11 Aug 2024 12:17:48 GMT</pubDate>
            <description><![CDATA[<h1 id="web-vitals-최적화">Web Vitals 최적화</h1>
<p>Web Vitals 최적화는 웹 페이지의 사용자 경험을 개선하기 위해 Google이 정의한 주요 웹 성능 지표(Web Vitals)를 측정하고 최적화하는 과정을 말합니다. Web Vitals는 웹사이트의 속도, 응답성, 안정성을 측정하는 중요한 지표이며, 이를 최적화함으로써 사용자 경험(UX)을 크게 향상시킬 수 있습니다.</p>
<h2 id="주요-web-vitals-지표-core-web-vitals">주요 Web Vitals 지표 (Core Web Vitals)</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/b330dc73-74cf-4ed3-af16-aa66a15f9f57/image.png" alt=""></p>
<h3 id="largest-contentful-paint-lcp"><strong>Largest Contentful Paint (LCP)</strong>:</h3>
<p>정의: <strong>페이지의 메인 콘텐츠가 로드되는 데 걸리는 시간</strong>입니다. 사용자 관점에서 페이지가 얼마나 빨리 표시되는지를 측정합니다.
최적화 목표: <strong>LCP는 2.5초 이하</strong>가 이상적입니다.
최적화 방법:</p>
<ul>
<li><strong>서버 응답 시간 단축</strong>: 서버의 응답 시간을 줄여 페이지 로드 시간을 단축합니다.</li>
<li><strong>리소스 최적화</strong>: CSS, 자바스크립트, 이미지 등의 로딩을 최적화합니다.</li>
<li><strong>Critical Rendering Path 최적화</strong>: 핵심 콘텐츠가 빠르게 로드되도록 렌더링 경로를 최적화합니다.</li>
</ul>
<h3 id="first-input-delay-fid"><strong>First Input Delay (FID)</strong>:</h3>
<p>정의: <strong>사용자가 처음으로 페이지와 상호작용할 때(예: 링크 클릭, 버튼 누르기) 발생하는 지연 시간</strong>입니다. 페이지가 얼마나 빠르게 반응하는지를 측정합니다.
최적화 목표: <strong>FID는 100밀리초 이하</strong>가 이상적입니다.
최적화 방법:</p>
<ul>
<li><strong>메인 스레드 작업 최소화</strong>: 긴 자바스크립트 실행을 피하고, 작업을 분리하여 메인 스레드가 차단되지 않도록 합니다.</li>
<li><strong>Third-party 코드 최적화</strong>: 외부 스크립트의 영향을 최소화합니다.</li>
<li><strong>Lazy loading 사용</strong>: 필요한 자바스크립트와 CSS만을 로드하여 초기 페이지 로드 시간을 단축합니다.</li>
</ul>
<h3 id="cumulative-layout-shift-cls"><strong>Cumulative Layout Shift (CLS)</strong>:</h3>
<p>정의: <strong>페이지가 로드되는 동안 시각적 콘텐츠가 얼마나 예기치 않게 이동하는지를 측정</strong>합니다. 이는 사용자가 페이지를 스크롤하거나 클릭할 때 불편함을 초래할 수 있습니다.
최적화 목표: <strong>CLS는 0.1 이하</strong>가 이상적입니다.
최적화 방법:</p>
<ul>
<li><strong>이미지 크기 명시</strong>: 이미지 및 동영상의 크기를 명시하여 레이아웃 이동을 방지합니다.</li>
<li><strong>글꼴 로딩 최적화</strong>: 글꼴 로딩 시 플래시 텍스트(FOUT, Flash of Unstyled Text)를 피하기 위해 적절한 폴백 글꼴을 사용합니다.</li>
<li><strong>애니메이션 사용 최소화</strong>: 레이아웃 이동을 유발할 수 있는 애니메이션을 피하거나 최적화합니다.</li>
</ul>
<h2 id="web-vitals-최적화의-중요성">Web Vitals 최적화의 중요성</h2>
<p>  Web Vitals는 단순히 사용자 경험을 개선하는 것뿐만 아니라, Google의 검색 순위에도 직접적인 영향을 미칩니다. Google은 2021년 6월부터 Web Vitals를 포함한 페이지 경험(Page Experience)을 검색 순위 알고리즘에 반영하기 시작했습니다. 따라서 Web Vitals 지표를 최적화하면, 다음과 같은 이점이 있습니다:</p>
<ul>
<li><p><strong>사용자 경험 향상</strong>: Web Vitals 지표는 실제 사용자가 웹사이트를 사용할 때 느끼는 성능을 반영합니다. 이를 최적화하면 사용자 경험이 크게 향상됩니다.</p>
</li>
<li><p><strong>SEO 향상</strong>: Google은 Web Vitals를 검색 순위 알고리즘의 중요한 요소로 사용하고 있습니다. 따라서 이 지표를 최적화하면 SEO 성능도 개선됩니다.</p>
</li>
<li><p><strong>전환율 증가</strong>: 더 빠르고 반응성이 좋은 웹사이트는 사용자 만족도를 높이며, 이는 곧 전환율(Conversion Rate)의 증가로 이어질 수 있습니다.</p>
<blockquote>
<p>전환율: 마케팅 및 웹사이트 분석에서 중요한 지표로, 특정 목표를 달성한 방문자 수의 비율을 의미</p>
</blockquote>
</li>
</ul>
<h2 id="⭐-web-vitals-최적화-방법">⭐ Web Vitals 최적화 방법</h2>
<ol>
<li><p><strong>페이지 로드 속도 개선</strong>: 특정 목표를 달성한 방문자 수의 비율</p>
<ul>
<li><strong>이미지 최적화</strong>: <strong>이미지 크기를 줄이고, 최신 이미지 포맷(WebP 등)을 사용</strong>합니다.</li>
<li><strong>자바스크립트 최적화</strong>: <strong>불필요한 자바스크립트 제거, 코드 스플리팅(Code Splitting) 적용 등을 통해 자바스크립트의 영향을 최소화</strong>합니다.</li>
<li><strong>캐싱 사용</strong>: <strong>브라우저 캐싱을 적절히 설정하여 반복 방문 시 로드 속도를 개선</strong>합니다.</li>
</ul>
</li>
<li><p><strong>서버 성능 최적화</strong>:</p>
<ul>
<li><strong>CDN 사용</strong>: 콘텐츠 배포 네트워크(CDN)를 사용하여 전 세계적으로 리소스를 빠르게 제공합니다.</li>
<li><strong>서버 응답 시간 개선</strong>: 서버 사이드 렌더링(SSR), 프리렌더링, HTTP/2 등 최신 기술을 사용하여 서버 응답 시간을 개선합니다.</li>
</ul>
</li>
<li><p><strong>사용자 인터랙션 최적화</strong>:</p>
<ul>
<li><strong>입력 지연 최소화</strong>: 자바스크립트가 사용자 입력 이벤트(클릭, 터치 등)에 신속하게 반응할 수 있도록 합니다.</li>
<li><strong>프리로드 및 프리페치</strong>: 중요한 리소스를 미리 로드하거나 프리페치하여 사용자가 필요한 순간에 빠르게 제공할 수 있도록 합니다.</li>
</ul>
</li>
<li><p><strong>개발 도구 활용</strong>:</p>
</li>
</ol>
<ul>
<li><a href="https://chromewebstore.google.com/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=ko">Lighthouse</a>: Google의 웹 성능 분석 도구로, Web Vitals를 측정하고 최적화할 부분을 제안합니다.</li>
<li><a href="https://pagespeed.web.dev/">PageSpeed Insights</a>: 웹사이트의 성능을 분석하고, 개선해야 할 요소를 제시합니다.</li>
<li><a href="https://developer.chrome.com/docs/devtools/lighthouse?hl=ko">Chrome DevTools</a>: 웹페이지의 성능을 분석하고, 성능 문제를 해결하기 위한 다양한 도구를 제공합니다.</li>
</ul>
<h3 id="👉-lighthouse로-측정할-수-있는-항목">👉 Lighthouse로 측정할 수 있는 항목</h3>
<ol>
<li>성능 (Performance):</li>
</ol>
<ul>
<li>Web Vitals: Lighthouse는 Web Vitals 지표(LCP, FID, CLS 등)를 포함한 다양한 성능 측정 지표를 제공합니다. 이를 통해 웹 페이지의 로드 속도, 인터랙션 응답성, 레이아웃 안정성 등을 평가할 수 있습니다.</li>
<li>기타 성능 지표: 첫 번째 콘텐츠가 표시되는 시간(FCP), 상호작용 가능 시간(TTI) 등도 평가됩니다.</li>
</ul>
<ol start="2">
<li>접근성 (Accessibility):</li>
</ol>
<ul>
<li>웹 접근성 검사: Lighthouse는 웹 페이지의 접근성을 자동으로 평가하고, WCAG(Web Content Accessibility Guidelines) 기준에 따라 접근성 문제를 감지합니다. 예를 들어, 적절한 색 대비, 이미지에 대한 대체 텍스트, 키보드 내비게이션, 폼 라벨링 등을 검사합니다.</li>
<li>수동 검토 권장: 일부 접근성 문제는 수동으로 검토해야 할 수 있으며, Lighthouse는 이러한 경우에 대해 별도의 권장 사항을 제공합니다.</li>
</ul>
<ol start="3">
<li>최적화 (Best Practices):</li>
</ol>
<ul>
<li>코드 품질 및 보안: Lighthouse는 HTTPS 사용, 안전하지 않은 자바스크립트 라이브러리, 잠재적인 보안 문제 등을 검사하여 웹사이트의 보안과 코드 품질을 평가합니다.</li>
</ul>
<ol start="4">
<li>SEO:</li>
</ol>
<ul>
<li>검색 엔진 최적화(SEO) 검사: Lighthouse는 페이지가 검색 엔진에 얼마나 잘 최적화되어 있는지를 평가합니다. 메타 태그, 타이틀, 설명, 구조화된 데이터 등 다양한 SEO 요소를 분석합니다.</li>
</ul>
<ol start="5">
<li>PWA (Progressive Web App):</li>
</ol>
<ul>
<li>PWA 성능: Lighthouse는 웹 애플리케이션이 Progressive Web App(PWA)으로서 얼마나 잘 작동하는지 평가합니다. 오프라인 지원, 설치 가능성, 서비스 워커 설정 등을 검사합니다.</li>
</ul>
<blockquote>
<p>실제 성능 최적화를 위해 Lighthouse를 이용해보니 고쳐야할 부분, 권장사항을 자세히 알려주고 관련 문서를 제공하여 편하게 개선해보며 최적화 방법을 익힐 수 있었습니다. 몰랐던 웹 접근성 항목도 알 수 있었습니다.
어떤 지표가 측정되고, 어떤 부분이 사용자 경험에 영향을 주는지 안다면 좀 더 개선된 성능, UX를 제공하는 웹 사이트를 제작하는데 많은 도움이 될 것 입니다.</p>
</blockquote>
<hr>
<p>Web Vitals 최적화는 현대 웹 개발에서 필수적인 과정입니다. 웹 페이지의 주요 성능 지표를 개선함으로써 사용자 경험을 향상시키고, SEO 성능을 높이며, 궁극적으로 비즈니스 목표를 달성할 수 있습니다. 이를 위해 다양한 최적화 기법과 도구를 활용하여 지속적으로 성능을 모니터링하고 개선해 나가는 것이 중요합니다.</p>
<hr>
<h2 id="📌-참고-자료">📌 참고 자료</h2>
<p><a href="https://developers-kr.googleblog.com/2020/05/Introducing-Web-Vitals.html">Web Vitals 소개: 건강한 사이트를 위한 필수적인 측정항목</a></p>
<hr>
<blockquote>
<p>추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] useState의 동작 원리]]></title>
            <link>https://velog.io/@hi-rachel/React-useState%EC%9D%98-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC-1eqhpjy7</link>
            <guid>https://velog.io/@hi-rachel/React-useState%EC%9D%98-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC-1eqhpjy7</guid>
            <pubDate>Sun, 11 Aug 2024 08:38:28 GMT</pubDate>
            <description><![CDATA[<h1 id="usestate">useState</h1>
<p><code>useState</code>는 React에서 함수형 컴포넌트에서 상태(state)를 관리하기 위해 제공되는 훅(Hook)입니다. 이 훅은 함수형 컴포넌트 내에서 상태를 정의하고, 그 상태를 업데이트하는 방법을 제공합니다. 아래에서 <code>useState</code>의 동작 원리, 개념, 클로저, 비동기 호출 등과 관련된 내용을 설명하겠습니다.</p>
<h2 id="1-usestate의-개념과-사용-이유">1. useState의 개념과 사용 이유</h2>
<h3 id="개념">개념</h3>
<ul>
<li><strong><code>useState</code>는 상태를 관리하는 Hook</strong>: 함수형 컴포넌트에서 상태를 추가할 수 있도록 하는 React의 Hook입니다. 상태는 컴포넌트가 렌더링될 때 유지되는 값으로, 컴포넌트 내에서 동적인 데이터를 다룰 때 사용됩니다.</li>
<li><strong>상태의 정의 및 초기화</strong>: <code>useState</code>는 초기 상태 값을 인자로 받아, 현재 상태 값과 그 상태를 업데이트하는 함수를 반환합니다. <code>const [state, setState] = useState(initialValue);</code> 형태로 사용됩니다.</li>
<li><strong>상태의 유지</strong>: 컴포넌트가 렌더링될 때마다 <code>useState</code>가 반환하는 상태 값은 매번 새롭게 정의되지 않고, 이전 렌더링에서 설정된 상태가 유지됩니다.</li>
</ul>
<h3 id="사용-이유">사용 이유</h3>
<ul>
<li><strong>UI 업데이트 관리</strong>: 상태가 변경되면 컴포넌트는 해당 상태를 기반으로 UI를 다시 렌더링합니다. <code>useState</code>를 사용해 상태를 관리함으로써, UI와 데이터의 일관성을 유지할 수 있습니다.</li>
<li><strong>함수형 컴포넌트에서 상태 관리</strong>: 함수형 컴포넌트는 기존 클래스형 컴포넌트와 달리 <code>this.state</code>를 사용할 수 없습니다. <code>useState</code>를 통해 함수형 컴포넌트에서도 상태를 관리할 수 있게 됩니다.</li>
</ul>
<h2 id="2-클로저와-usestate">2. 클로저와 useState</h2>
<p><strong>클로저</strong>는 <strong>함수와 그 함수가 선언될 때의 렉시컬 환경(Lexical Environment)을 기억하는 메커니즘</strong>입니다. <code>useState</code>와 클로저는 밀접하게 관련되어 있습니다.</p>
<ul>
<li><p><strong>클로저와 상태 유지</strong>: <code>useState</code>로 생성된 상태와 이를 변경하는 함수는 클로저에 의해 상태값을 기억합니다. 함수형 컴포넌트가 여러 번 렌더링 되더라도, 클로저를 통해 <code>useState</code>의 상태는 항상 최신 상태를 유지합니다. 이는 상태 관리가 컴포넌트 내에서 안정적으로 이루어질 수 있게 해줍니다.</p>
</li>
<li><p><strong>업데이트 함수와 클로저</strong>: <code>setState</code>와 같은 상태 업데이트 함수는 클로저를 통해 이전 상태 값을 참조하여 새로운 상태를 계산하거나, 업데이트된 상태를 렌더링 주기에 전달합니다. 이 때문에 <code>setState</code>에 상태를 업데이트하는 콜백 함수를 넘길 수 있습니다. 예를 들어:</p>
<pre><code class="language-jsx">const [count, setCount] = useState(0);

const increment = () =&gt; {
  setCount((prevCount) =&gt; prevCount + 1);
};

</code></pre>
</li>
</ul>
<p>이 경우, setCount의 인자로 넘겨지는 함수는 prevCount라는 이름으로 이전 상태값을 가지고 있으며, 이 값은 클로저에 의해 유지됩니다.</p>
<h2 id="3-비동기-호출과-usestate">3. 비동기 호출과 useState</h2>
<p>useState에서의 상태 업데이트는 비동기적으로 처리됩니다.</p>
<ul>
<li><p>상태 업데이트의 비동기성: <strong>setState는 즉각적으로 상태를 변경하지 않습니다. React는 여러 상태 업데이트를 하나의 렌더링 주기(batch)에서 처리하여 성능을 최적화</strong>합니다. 따라서 setState를 호출한 직후에 상태 값을 참조하면 업데이트되기 전의 값이 반환될 수 있습니다.</p>
</li>
<li><p>비동기 로직에서의 상태 관리: 비동기 작업(예: API 호출)에서 useState를 사용해 상태를 관리할 때, 비동기 작업이 완료된 후 상태를 업데이트할 수 있습니다. 이러한 경우 useEffect와 같은 훅을 함께 사용하여 비동기 로직을 처리할 수 있습니다.</p>
</li>
</ul>
<pre><code class="language-jsx">useEffect(() =&gt; {
  async function fetchData() {
    const data = await fetchSomeData();
    setState(data);
  }
  fetchData();
}, []);</code></pre>
<h2 id="자세히-정리">자세히 정리</h2>
<p><strong>useState의 비동기적 특성</strong></p>
<ul>
<li><strong>비동기적 상태 업데이트</strong>: React에서 useState를 통해 상태를 업데이트할 때, 상태 업데이트는 즉각적으로 반영되지 않습니다. 대신, <strong>React는 상태 변경 요청을 큐에 넣어두고, 컴포넌트가 다시 렌더링될 때 이 큐에 담긴 상태 업데이트를 한꺼번에 처리</strong>합니다.</li>
<li><strong>동기화 문제 방지</strong>: useState가 비동기적으로 동작하는 이유 중 하나는 여러 상태 변경이 일어날 때마다 컴포넌트를 여러 번 재렌더링하지 않기 위해서입니다. 즉, 여러 상태 변경이 발생해도 React는 성능을 최적화하기 위해 이러한 변경 사항을 한꺼번에 처리합니다.</li>
<li><strong>렌더링 이후 상태 반영</strong>: setState를 호출한 후 바로 그 다음 줄에서 상태를 확인하면, 여전히 이전 상태 값이 반환됩니다. 이는 상태가 바로 업데이트되지 않기 때문입니다. 상태가 업데이트된 후에야 그 값이 변경되며, 이 변경은 다음 렌더링 사이클에서 반영됩니다.</li>
</ul>
<p><strong>React의 배치 업데이트(batch update) 메커니즘</strong></p>
<ul>
<li><strong>배치 업데이트</strong>: React는 상태 업데이트가 발생할 때마다 즉각적으로 컴포넌트를 다시 렌더링하지 않습니다. 대신 여러 개의 상태 업데이트가 발생하면, 이를 배치(batch)로 묶어서 한 번의 렌더링 사이클에서 모두 처리합니다. 이렇게 하면 불필요한 재렌더링을 줄여 성능을 최적화할 수 있습니다.</li>
<li><strong>동시성 모드와 배치 업데이트</strong>: <strong>React 18부터 도입된 동시성 모드(Concurrent Mode)에서는 배치 업데이트가 기본적으로 활성화</strong>됩니다. 이 모드에서는 여러 개의 상태 업데이트가 자동으로 배치되어 처리됩니다. 예를 들어, 여러 개의 setState 호출이 있을 때 이들은 모두 배치로 묶여서 처리되고, 그 결과 컴포넌트는 한 번만 렌더링됩니다.</li>
</ul>
<p><strong>useState의 비동기성 + 배치 업데이트의 결합</strong></p>
<ul>
<li><p>발생할 수 있는 문제</p>
<ul>
<li>실시간 상태 확인 어려움: useState가 비동기적으로 동작하면서 배치 업데이트가 적용되면, 상태 업데이트가 일어난 직후에 상태를 확인할 때, 이는 아직 최신 값으로 반영되지 않았을 수 있습니다. 이는 상태 업데이트가 배치로 처리되면서, 그 사이에 발생하는 여러 상태 변경이 함께 묶여 다음 렌더링에서 처리되기 때문입니다.</li>
<li>최적화와 예측 가능성: React는 이 배치 업데이트 메커니즘을 통해 최적화를 이루지만, 이로 인해 개발자가 상태 업데이트의 타이밍을 정확하게 예측하기 어려운 경우가 생깁니다. 특히 상태 값에 의존하는 로직을 바로 상태 업데이트 이후에 실행하려고 할 때, 비동기적 특성으로 인해 예상치 못한 동작이 발생할 수 있습니다.</li>
</ul>
</li>
<li><p>해결 방법</p>
<ul>
<li>상태 값 의존 로직의 분리: 상태 업데이트 후 상태 값을 직접 참조하지 않고, 상태 변경에 의존하는 로직을 가능한 한 분리하거나, 업데이트 함수의 콜백 기능을 사용해 안전하게 처리하는 방법도 있습니다.</li>
<li>useEffect 활용: 상태 값이 변경된 이후에 특정 작업을 수행하려면 useEffect를 사용하여 상태 값의 변경을 감지하고, 그에 따라 로직을 실행할 수 있습니다. 이는 상태 값이 업데이트된 이후에 원하는 동작을 보장할 수 있는 방법입니다.</li>
</ul>
</li>
</ul>
<h2 id="실제-트러블슈팅-경험">실제 트러블슈팅 경험</h2>
<blockquote>
<p>프로젝트시 useState의 비동기적 특성과 배치 업데이트에 대한 이해가 부족해 setState()로 상태를 설정하고 그 상태를 다음 줄에서 바로 확인하려고 해 문제가 발생한 경험이 있었습니다. <a href="https://github.com/SlamTalk/slam-talk-frontend/pull/308">참고</a></p>
<p>당시에는 useState의 비동기적 특성을 이해하고 문제를 해결하였습니다. 이후 공부를 더 하며 배치 업데이트와 연관된 점을 파악했고, useState의 동작원리를 더 깊이 공부하며 클로저를 이용해 이전 상태를 참조할 수 있음을 알게되었습니다.</p>
<p>처음 React를 공부할 때는 함수형 컴포넌트에서 간단하게 상태 관리할 수 있는 Hook으로만 이해했지만 해당 경험을 통해 동작원리를 잘 알지 못하면 버그를 발생시킬 수 있다는 점을 배웠습니다.</p>
</blockquote>
<hr>
<p><strong>정리</strong>
useState는 React에서 함수형 컴포넌트의 상태를 관리하기 위한 핵심적인 도구입니다. 클로저와의 결합을 통해 상태를 안전하게 관리할 수 있으며, 비동기 작업과 함께 사용할 때 상태 관리의 복잡성을 처리할 수 있습니다. 이러한 특징들은 React 컴포넌트가 복잡한 UI를 효율적으로 관리할 수 있도록 돕습니다.</p>
<p><a href="https://react.dev/reference/react/useState">React 공식 문서 - useSTate</a></p>
<hr>
<blockquote>
<p>추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Github Actions 동작 원리에 대한 이해]]></title>
            <link>https://velog.io/@hi-rachel/Github-Actions-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@hi-rachel/Github-Actions-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Fri, 09 Aug 2024 13:34:26 GMT</pubDate>
            <description><![CDATA[<h2 id="1-github-actions이란">1. Github Actions이란</h2>
<p>GitHub Actions는 GitHub에서 제공하는 CI/CD(Continuous Integration/Continuous Delivery) 도구로, 코드의 빌드, 테스트, 배포와 같은 자동화된 작업을 수행할 수 있습니다. 프론트엔드 개발자에게 GitHub Actions는 프로젝트의 지속적인 통합 및 배포 파이프라인을 구성하는 데 매우 유용한 도구입니다. 아래는 GitHub Actions의 동작 원리, 과정, 그리고 프론트엔드 개발자가 알아야 할 주요 개념을 정리한 내용입니다.</p>
<h2 id="2-github-actions의-주요-개념">2. GitHub Actions의 주요 개념</h2>
<p><strong>GitHub Actions</strong>는 <strong>리포지토리에서 코드 변경이 발생할 때, 특정 작업을 자동으로 수행할 수 있도록 하는 자동화 도구</strong>입니다. 워크플로우(Workflow)라고 불리는 일련의 작업들을 정의하고, 이를 트리거(Trigger)에 따라 실행합니다. GitHub Actions는 YAML 파일을 사용해 설정을 정의하며, 이 파일은 .github/workflows/ 디렉터리에 위치합니다.</p>
<ul>
<li><p><strong>워크플로우(Workflow)</strong>: <strong>워크플로우는 자동화된 프로세스</strong>의 정의로, 하나 이상의 작업(Job)으로 구성됩니다. 워크플로우는 특정 이벤트에 의해 트리거됩니다. 예를 들어, 코드가 푸시될 때 테스트를 실행하는 워크플로우를 정의할 수 있습니다.</p>
</li>
<li><p><strong>잡(Job)</strong>: <strong>잡은 여러 스텝(Step)으로 구성된 작업 단위</strong>입니다. 각 잡은 독립적으로 실행되며, 병렬 또는 순차적으로 실행할 수 있습니다. 예를 들어, 테스트 잡과 빌드 잡을 병렬로 실행하거나, 빌드가 완료된 후에만 배포 잡이 실행되도록 설정할 수 있습니다.</p>
</li>
<li><p><strong>스텝(Step)</strong>: <strong>스텝은 잡 내에서 실행되는 개별 명령어 또는 작업</strong>입니다. 각 스텝은 스크립트나 액션(Action)으로 정의됩니다.</p>
</li>
<li><p><strong>액션(Action)</strong>: <strong>액션은 스텝에서 실행되는 재사용 가능한 코드 조각</strong>입니다. GitHub 마켓플레이스에서 제공되는 다양한 액션을 사용해 쉽게 작업을 자동화할 수 있습니다. 예를 들어, 코드 스타일 검사를 위한 ESLint 액션을 추가하거나, Docker 이미지를 빌드하는 액션을 추가할 수 있습니다.</p>
</li>
<li><p><strong>런너(Runner)</strong>: <strong>런너는 워크플로우를 실행하는 환경</strong>입니다. GitHub에서 제공하는 호스티드 런너를 사용할 수도 있고, 자체 호스티드 런너를 설정할 수도 있습니다.</p>
</li>
<li><p><strong>이벤트(Event)</strong>: <strong>이벤트는 워크플로우를 트리거하는 조건</strong>입니다. 대표적인 이벤트로는 push, pull_request, issue, schedule 등이 있으며, 특정 브랜치에 코드가 푸시되었을 때, 혹은 특정 시간에 주기적으로 워크플로우를 실행하는 것이 가능합니다.</p>
</li>
</ul>
<h2 id="3-github-actions의-동작-원리">3. GitHub Actions의 동작 원리</h2>
<ol>
<li><p><strong>트리거(Event) 감지</strong>: 리포지토리에 정의된 특정 이벤트(예: 코드 푸시, PR 생성 등)가 발생하면, GitHub Actions가 워크플로우를 트리거합니다.</p>
</li>
<li><p><strong>워크플로우 실행</strong>: 트리거된 워크플로우가 정의된 순서대로 잡(Job)을 실행합니다. 각 잡은 지정된 런너 환경에서 실행됩니다.</p>
</li>
<li><p><strong>잡(Job) 실행</strong>: 각 잡은 독립적으로 실행되며, 여러 스텝(Step)으로 구성됩니다. 잡은 병렬로 실행될 수도 있고, 순차적으로 실행될 수도 있습니다.</p>
</li>
<li><p><strong>스텝(Step) 실행</strong>: 각 스텝은 명령어 또는 액션을 수행하며, 성공 또는 실패로 완료됩니다. 실패가 발생하면 워크플로우가 중단될 수 있습니다.</p>
</li>
<li><p><strong>결과 보고</strong>: 모든 스텝이 실행되면, GitHub Actions는 워크플로우 실행 결과를 요약하여 GitHub의 웹 인터페이스에 표시합니다. 여기서 로그를 확인하거나, 실패한 이유를 분석할 수 있습니다.</p>
</li>
</ol>
<h2 id="4-github-actions의-설정-파일-yaml">4. GitHub Actions의 설정 파일 (YAML)</h2>
<p>GitHub Actions는 .github/workflows/ 디렉터리에 위치한 .yaml 파일(혹은 .yml 파일)로 설정됩니다. 다음은 프론트엔드 프로젝트에서 자주 사용하는 GitHub Actions 설정 파일 예시입니다.</p>
<pre><code class="language-yaml">name: CI/CD Pipeline

on:
  push:
    branches:
      - main
      - develop
  pull_request:
    branches:
      - main
      - develop

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16.x, 18.x] # 테스트하고자 하는 Node.js 버전들

    steps:
      - name: Check out the code
        uses: actions/checkout@v4

      - name: Set up Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: &quot;npm&quot; # 캐시 사용

      - name: Install dependencies
        run: npm ci # 의존성 설치

      - name: Run Lint
        run: npm run lint # 린트 작업 수행

      - name: Run Tests
        run: npm test # 유닛 테스트 수행

      - name: Build Project
        run: npm run build # 빌드 수행

#   deploy:
#     runs-on: ubuntu-latest
#     needs: build-and-test  # 빌드 및 테스트가 성공한 경우에만 배포

#     steps:
#       - name: Deploy to Vercel
#         uses: amondnet/vercel-action@v20
#         with:
#           vercel-token: ${{ secrets.VERCEL_TOKEN }}
#           vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
#           vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
#           working-directory: ./</code></pre>
<p>📄 실제 프로젝트시 사용했던 main.yml 파일</p>
<pre><code class="language-yml">name: Slam Talk CI

on:
  workflow_dispatch:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [20.x]

    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm run lint</code></pre>
<ul>
<li><p>브랜치 트리거 설정:</p>
<ul>
<li>main, develop 브랜치를 별도로 운영하여 개발과 배포를 관리하기 때문에, 이 두 브랜치에서의 커밋과 PR(Pull Request) 이벤트가 발생할 때마다 자동으로 워크플로우가 실행되도록 설정했습니다.</li>
<li>push 및 pull_request 트리거를 설정하여, 새로운 코드가 푸시되거나 PR이 생성될 때 자동으로 린트 작업이 수행됩니다. 이를 통해 코드의 품질을 지속적으로 검증할 수 있습니다.</li>
</ul>
</li>
<li><p>노드 버전 설정:</p>
<ul>
<li>실제 프로젝트에서 사용 중인 Node.js 20.x 버전을 명시하여, 이 버전에서 코드가 정상적으로 동작하는지 확인합니다.</li>
<li>matrix 전략을 사용하면, 필요에 따라 여러 Node.js 버전에서 코드를 테스트할 수 있습니다. 이 설정에서는 현재 프로젝트에서 사용 중인 Node.js 20.x 버전만 명시되어 있지만, 다른 Node.js 버전(예: 14.x, 16.x 등)에서도 테스트하고 싶은 경우, 해당 버전들을 추가로 명시할 수 있습니다.</li>
</ul>
</li>
<li><p>CI 작업:</p>
<ul>
<li>npm ci 명령어를 사용하여 의존성을 설치합니다. 이 명령어는 package-lock.json 파일에 명시된 정확한 버전의 패키지들을 설치하기 때문에, 개발 환경과 CI 환경 간의 일관성을 유지하는 데 매우 중요합니다.</li>
<li>npm run lint 명령어를 통해 린트 작업을 수행합니다. 이를 통해 코드가 정해진 스타일 가이드와 규칙을 준수하는지 확인할 수 있습니다. 린트 작업에서 문제가 발견되면, 이를 사전에 수정함으로써 코드 품질을 유지할 수 있습니다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>Github을 통해 Vercel을 연결하면 자동으로 CI/CD 파이프라인을 구성할 수 있습니다.
👉 Vercel에서 자동으로 CI/CD가 되기 때문에 자동 Lint 검사 용도 정도로 Github Actions CI를 활용했습니다.
Jest 테스트 등이 추가되면 좋을 것 같습니다.</p>
</blockquote>
<h2 id="5-프론트엔드-개발에서-github-actions의-활용">5. 프론트엔드 개발에서 GitHub Actions의 활용</h2>
<p>프론트엔드 개발에서 GitHub Actions는 다음과 같은 작업을 자동화하는 데 유용합니다:</p>
<ol>
<li>코드 검증:</li>
</ol>
<ul>
<li>ESLint 및 Prettier: 코드 스타일을 일정하게 유지하기 위해, GitHub Actions를 통해 ESLint와 Prettier를 자동으로 실행할 수 있습니다. 이를 통해 코드 스타일 위반 사항을 PR(Pull Request)에서 경고로 표시할 수 있습니다.</li>
</ul>
<ol start="2">
<li>테스트 자동화:</li>
</ol>
<ul>
<li>Jest를 이용한 유닛 테스트: GitHub Actions를 Jest와 통합하여, 코드 푸시 시 자동으로 유닛 테스트를 실행합니다. 테스트가 실패할 경우 배포를 중단하여, 버그가 포함된 코드가 배포되지 않도록 방지할 수 있습니다.</li>
</ul>
<ol start="3">
<li>빌드 작업:</li>
</ol>
<ul>
<li>Webpack 및 Vite: 프론트엔드 프로젝트의 코드는 배포 전에 빌드 과정이 필요합니다. GitHub Actions에서 Webpack이나 Vite와 같은 번들러를 사용하여 코드를 빌드하고, 그 결과를 검토한 후 배포할 수 있습니다.</li>
</ul>
<ol start="4">
<li>배포 자동화:</li>
</ol>
<ul>
<li>Vercel 및 Netlify: GitHub Actions에서 빌드가 성공적으로 완료되면, Vercel이나 Netlify와 같은 배포 플랫폼에 자동으로 배포할 수 있습니다. 이 과정에서 GitHub Actions와 배포 플랫폼 간의 인증은 API 키 또는 토큰을 통해 처리됩니다.</li>
</ul>
<ol start="5">
<li>동적 환경 변수 설정:</li>
</ol>
<ul>
<li>환경 변수 관리: 프론트엔드 프로젝트에서 환경 변수는 중요한 설정 요소입니다. GitHub Actions를 활용하여, 특정 환경에 맞는 환경 변수 파일을 생성하거나 자동으로 환경 변수 설정 파일을 작성할 수 있습니다.</li>
</ul>
<p>이러한 활용 방법을 통해, 프론트엔드 개발자는 GitHub Actions를 사용하여 코드를 자동으로 검사, 테스트, 빌드, 배포할 수 있으며, 이를 통해 개발 속도와 코드 품질을 크게 향상시킬 수 있습니다.</p>
<h2 id="6-github-actions의-장점">6. GitHub Actions의 장점</h2>
<ul>
<li>통합된 환경: GitHub 리포지토리와 통합되어 있어, 별도의 CI/CD 도구를 사용하지 않아도 됩니다.</li>
<li>유연성: 다양한 액션과 커스텀 설정을 통해 프로젝트에 맞는 CI/CD 파이프라인을 구성할 수 있습니다.</li>
<li>확장성: 커뮤니티와 GitHub 마켓플레이스에서 제공하는 수많은 액션을 활용해 다양한 작업을 자동화할 수 있습니다.</li>
</ul>
<p><strong>GitHub Actions를 사용하면 코드가 푸시될 때마다 자동으로 테스트, 빌드, 배포가 이루어지며, 이를 통해 안정적인 배포 파이프라인을 구축</strong>할 수 있습니다. YAML 파일을 통해 간단하게 설정할 수 있고, GitHub의 방대한 생태계와 액션을 활용하여 다양한 자동화를 실현할 수 있습니다.</p>
<h2 id="7-vercel과-github-actions를-활용한-cicd-흐름">7. Vercel과 GitHub Actions를 활용한 CI/CD 흐름</h2>
<ol>
<li><strong>코드 푸시(Push)</strong>: 개발자가 코드의 변경 사항을 GitHub 리포지토리에 푸시합니다.</li>
<li><strong>GitHub Actions 트리거</strong>: 코드가 푸시되면 GitHub Actions가 트리거되어 워크플로우가 시작됩니다. 이 단계에서는 코드 빌드, 테스트, 코드 스타일 검사 등의 작업이 이루어집니다.</li>
<li><strong>테스트 및 빌드</strong>: GitHub Actions는 설정된 워크플로우에 따라 코드를 빌드하고 테스트합니다. 만약 테스트가 실패하거나 빌드에 문제가 발생하면, 개발자에게 알림이 가며 배포는 중단됩니다.</li>
<li><strong>Vercel 빌드 및 배포 트리거</strong>: GitHub Actions의 빌드와 테스트가 성공적으로 완료되면, Vercel이 자동으로 배포를 트리거합니다. Vercel은 다음과 같은 빌드 과정을 통해 프로젝트의 최신 코드를 프로덕션 또는 프리뷰 환경에 배포합니다:
• 빌드 명령어 실행: package.json 파일에 지정된 빌드 명령어(예: npm run build)가 실행되어 프로젝트가 빌드됩니다.
• 코드 최적화: 코드 스플리팅, 트리 쉐이킹, 압축 등의 최적화 작업이 수행됩니다.
• 정적 자산 생성: 빌드된 정적 파일들이 Vercel의 배포 시스템에 의해 준비됩니다.
• 서버리스 함수 배포: 서버리스 함수가 포함된 경우, 개별적으로 배포됩니다.
• 글로벌 CDN 배포: 빌드된 결과물은 Vercel의 글로벌 CDN을 통해 전 세계에 배포됩니다. 이를 통해 사용자들은 가까운 서버에서 콘텐츠를 빠르게 제공받습니다.</li>
<li><strong>프리뷰 환경 제공</strong>: Vercel은 모든 PR(Pull Request)에 대해 별도의 프리뷰 환경을 제공합니다. 이를 통해 팀원들은 코드가 실제로 배포되기 전에 변경 사항을 미리 확인할 수 있습니다. 각 PR은 고유한 URL이 부여되며, 이 URL에서 변경 사항을 테스트할 수 있습니다.</li>
<li><strong>프로덕션 배포</strong>: 코드 변경 사항이 main 또는 지정된 배포 브랜치에 머지(Merge)되면, Vercel은 자동으로 프로덕션 배포를 진행합니다. 이 과정은 무중단 배포로 이루어져, 사용자는 새로운 버전을 즉시 사용할 수 있게 됩니다.</li>
<li><strong>결과 확인 및 알림</strong>: 배포가 완료되면 Vercel 대시보드 또는 GitHub에서 배포 상태를 확인할 수 있습니다. 성공 여부와 배포된 URL을 확인할 수 있으며, 문제가 발생한 경우 빠르게 대응할 수 있습니다.</li>
</ol>
<blockquote>
<p>Vercel은 무중단 배포를 기본으로 하며, 이전 버전의 애플리케이션을 유지하면서 새로운 버전을 배포합니다. 이를 통해 배포 중에도 사용자가 끊김 없이 애플리케이션을 사용할 수 있습니다.</p>
</blockquote>
<hr>
<h2 id="✏️-용어-정리-연관된-개념-정리">✏️ 용어 정리, 연관된 개념 정리</h2>
<h3 id="cicontinuous-integration란">CI(Continuous Integration)란?</h3>
<p><strong>Continuous Integration(CI)</strong>은 소프트웨어 개발에서 팀원들이 <strong>각자 작업한 코드를 자주 병합(Integration)</strong>하여, <strong>자동으로 빌드(Build)와 테스트(Test)</strong>를 수행하는 과정을 말합니다. CI의 주요 목표는 <strong>코드 병합 시 발생할 수 있는 충돌과 버그를 조기에 발견하고 해결하는 것</strong>입니다.</p>
<ul>
<li>자동화된 빌드 및 테스트: 코드가 리포지토리에 푸시될 때마다 자동으로 빌드와 테스트가 실행됩니다. 이를 통해 새로운 코드가 기존 코드와 잘 통합되는지, 테스트를 통과하는지 확인할 수 있습니다.</li>
<li>지속적인 코드 품질 보장: CI는 코드를 자주 통합하고 테스트함으로써 코드 품질을 지속적으로 유지하고 개선하는 데 도움을 줍니다.</li>
<li>신속한 피드백: 코드에 문제가 있으면 바로 피드백을 제공하여, 개발자들이 신속하게 수정할 수 있도록 합니다.</li>
</ul>
<h3 id="cdcontinuous-deliverycontinuous-deployment란">CD(Continuous Delivery/Continuous Deployment)란</h3>
<p><strong>Continuous Delivery(CD)</strong>와 <strong>Continuous Deployment(CD)</strong>는 CI의 다음 단계로, <strong>빌드된 코드가 자동으로 배포(Deployment)되는 과정을 포함</strong>합니다.</p>
<ul>
<li>Continuous Delivery(CD): CI 후, 빌드된 코드를 프로덕션 환경에 배포하기 전에, 수동 승인이 필요한 경우를 말합니다. 개발자나 관리자에게 배포 승인 요청이 가며, 승인이 완료되면 코드가 프로덕션 환경에 배포됩니다.</li>
<li>Continuous Deployment(CD): CI 후, 빌드된 코드가 자동으로 프로덕션 환경에 배포되는 것을 말합니다. 수동 승인 없이 자동으로 배포되며, 이로 인해 신속하게 새로운 기능이나 수정사항이 배포됩니다.</li>
</ul>
<p>두 개념은 “CD”로 불리지만, Continuous Delivery와 Continuous Deployment의 차이점은 수동 승인이 있는지 여부입니다.</p>
<h3 id="cicd-파이프라인-정리">CI/CD 파이프라인 정리</h3>
<ol>
<li>CI 파이프라인</li>
</ol>
<ul>
<li>코드를 푸시하거나 Pull Request가 생성될 때, 자동으로 빌드하고 테스트를 수행합니다.</li>
<li>코드 품질을 보장하기 위해 테스트가 실패할 경우 알림을 보내고 배포를 중단합니다.</li>
</ul>
<ol start="2">
<li>CD 파이프라인</li>
</ol>
<ul>
<li>CI가 성공적으로 완료되면, 코드 변경 사항을 스테이징 환경이나 프로덕션 환경에 자동으로 배포할 수 있습니다.</li>
<li>GitHub Actions 내에서 배포 스크립트를 작성하여, AWS, Azure, Vercel, Netlify 등 다양한 배포 플랫폼에 배포할 수 있습니다.</li>
</ul>
<h3 id="파이프라인이란">파이프라인이란?</h3>
<p>파이프라인(Pipeline)은 소프트웨어 개발 및 배포 과정에서 <strong>일련의 작업이 자동으로 순차적으로 또는 병렬로 수행되는 흐름</strong>을 말합니다. 이 개념은 특히 CI/CD(Continuous Integration/Continuous Deployment)에서 많이 사용됩니다. 파이프라인은 코드의 변경 사항이 소스 코드 저장소에 반영된 후, 빌드, 테스트, 배포와 같은 단계들이 자동으로 실행되도록 구성합니다.</p>
<p><strong>파이프라인의 주요 단계</strong></p>
<ol>
<li><strong>코드 통합 (Integration)</strong>:<ul>
<li>개발자가 작성한 코드가 저장소에 커밋되면 파이프라인이 시작됩니다.</li>
<li>이 단계에서는 여러 개발자가 작업한 코드가 함께 통합됩니다.</li>
</ul>
</li>
<li><strong>빌드 (Build)</strong>:<ul>
<li>코드가 컴파일되거나 패키징됩니다.</li>
<li>의존성 관리, 코드를 바이너리 형태로 변환 등의 작업이 이루어집니다.</li>
<li>빌드 과정에서 오류가 발생하면 파이프라인이 중단되고, 문제가 보고됩니다.</li>
</ul>
</li>
<li><strong>테스트 (Test)</strong>:<ul>
<li>빌드된 코드가 사전 정의된 테스트 케이스를 통해 검증됩니다.</li>
<li>유닛 테스트, 통합 테스트, E2E 테스트 등 다양한 테스트가 이 단계에서 수행됩니다.</li>
<li>테스트에 실패하면 파이프라인이 중단되고, 문제가 보고됩니다.</li>
</ul>
</li>
<li><strong>배포 (Deploy)</strong>:<ul>
<li>테스트가 성공적으로 완료되면, 코드가 스테이징 또는 프로덕션 환경에 배포됩니다.</li>
<li>이 단계에서 애플리케이션이 사용자에게 제공될 준비를 마칩니다.</li>
<li>무중단 배포(Zero-downtime deployment)도 가능하며, 새로운 버전이 배포되면서도 이전 버전이 사용자의 서비스에 영향을 미치지 않도록 할 수 있습니다.</li>
</ul>
</li>
<li><strong>모니터링 및 피드백</strong> (Monitoring and Feedback):<ul>
<li>배포된 애플리케이션의 상태를 모니터링하고, 문제가 발생하면 피드백을 제공하는 단계입니다.</li>
<li>성능 모니터링, 오류 추적, 사용자 피드백 수집 등이 포함될 수 있습니다.</li>
</ul>
</li>
</ol>
<p><strong>파이프라인의 장점</strong></p>
<ul>
<li>자동화: 사람이 개입하지 않고, 코드 변경부터 배포까지의 과정을 자동으로 수행할 수 있어 효율적이고 오류를 줄일 수 있습니다.</li>
<li>일관성: 동일한 작업을 항상 동일한 방법으로 수행하여 결과의 일관성을 보장합니다.</li>
<li>빠른 피드백: 코드 변경 사항이 문제를 일으킬 경우, 즉시 피드백을 제공하여 빠르게 수정할 수 있습니다.</li>
<li>개발 속도 향상: 개발자들은 코드 변경 후 수동으로 빌드나 배포를 할 필요 없이, 빠르게 다음 작업에 집중할 수 있습니다.</li>
</ul>
<p>예를 들어, GitHub Actions에서 파이프라인을 설정하면 다음과 같은 흐름으로 작업이 진행될 수 있습니다:</p>
<ol>
<li>코드가 푸시되면 파이프라인이 시작됩니다.</li>
<li>npm ci 명령어로 의존성을 설치하고, 빌드가 시작됩니다.</li>
<li>빌드된 코드에 대해 테스트를 수행합니다.</li>
<li>테스트가 성공하면 코드가 배포됩니다.</li>
<li>배포된 애플리케이션의 상태를 모니터링합니다.</li>
</ol>
<p>이와 같은 파이프라인을 통해 개발부터 배포까지의 과정을 자동화하여 더 빠르고 안정적인 소프트웨어 제공이 가능합니다.</p>
<h3 id="⭐️-빌드-결과물이-뭘까요">⭐️ 빌드 결과물이 뭘까요?</h3>
<p><strong>빌드 결과물(Build Artifacts)</strong>은 CI/CD 파이프라인에서 코드가 빌드된 후 생성되는 산출물입니다. 빌드 결과물은 일반적으로 <strong>애플리케이션의 배포 가능한 형태</strong>로, 다음과 같은 형태일 수 있습니다:</p>
<ul>
<li>압축 파일 (ZIP, TAR): 여러 파일이 하나의 패키지로 압축된 형태. 이 파일은 배포될 서버로 전송된 후, 압축이 풀려 실행됩니다.</li>
<li><strong>번들 파일 (JavaScript, CSS 등): Webpack, Vite와 같은 번들러에 의해 생성된 최적화된 자바스크립트와 CSS 파일들이 번들로 묶여 배포</strong>됩니다.</li>
<li>Docker 이미지: 애플리케이션과 필요한 모든 종속성을 포함한 컨테이너 이미지. 이 이미지는 Docker Registry에 푸시되고, 이후 배포 시 사용됩니다.</li>
<li>애플리케이션 바이너리: 빌드된 실행 파일이나 라이브러리 파일들이 배포에 사용됩니다. 예를 들어, Java 애플리케이션의 경우 JAR 파일이 될 수 있습니다.</li>
</ul>
<p>이러한 빌드 결과물은 CI/CD 파이프라인에서 생성된 후, 다음 단계로 배포되거나, 저장소에 보관되어 배포 시 사용됩니다.</p>
<h3 id="cdn이란">CDN이란?</h3>
<p><strong>CDN(Content Delivery Network)</strong>은 <strong>인터넷 사용자들에게 콘텐츠를 빠르고 효율적으로 전달하기 위해 사용되는 분산된 서버 시스템</strong>입니다. CDN은 다음과 같은 주요 기능을 수행합니다:</p>
<ol>
<li><strong>콘텐츠 캐싱</strong>: <strong>CDN은 웹사이트의 정적 콘텐츠(이미지, HTML, CSS, JavaScript 파일 등)를 캐싱하여 저장</strong>합니다. 이를 통해 동일한 콘텐츠 요청이 있을 때마다 원본 서버에 접근할 필요 없이, 가장 가까운 CDN 서버에서 콘텐츠를 제공할 수 있습니다.</li>
<li><strong>글로벌 분산</strong>: CDN은 전 세계에 분산된 서버 네트워크를 통해 콘텐츠를 전달합니다. 사용자는 자신의 위치에서 가장 가까운 CDN 서버에 접속하여 빠르게 콘텐츠를 받을 수 있습니다.</li>
<li><strong>로드 밸런싱</strong>: CDN은 트래픽 부하를 여러 서버에 분산시켜 서버 과부하를 방지하고, 웹사이트의 가용성과 성능을 향상시킵니다.</li>
<li><strong>보안 강화</strong>: CDN은 DDoS 공격 방어, SSL 인증서 관리, 방화벽 설정 등을 통해 웹사이트의 보안을 강화합니다.</li>
</ol>
<p>정리</p>
<ul>
<li>Vercel은 프로젝트의 코드가 변경될 때마다 자동으로 빌드 과정을 수행하고, 이를 최적화된 형태로 준비하여 글로벌 CDN에 배포합니다.</li>
<li>글로벌 CDN은 Vercel의 기본 기능으로, 전 세계 사용자에게 빠르고 안정적으로 콘텐츠를 제공하는 역할을 합니다.</li>
<li>CDN(Content Delivery Network)은 콘텐츠를 효율적으로 제공하기 위해 전 세계에 분산된 서버 네트워크로, 사용자 경험을 개선하고 웹사이트 성능을 향상시킵니다.</li>
</ul>
<h3 id="서버리스-함수란">서버리스 함수란?</h3>
<p><strong>서버리스 함수는 서버 관리에 신경 쓰지 않고, 코드 작성에만 집중할 수 있는 클라우드 컴퓨팅 모델</strong>입니다. 개발자는 특정 이벤트가 발생했을 때 실행되는 개별 함수로 코드를 작성하고, 클라우드 제공자(AWS Lambda, Google Cloud Functions, Vercel Serverless Functions 등)가 이 함수를 자동으로 실행하며, 인프라 관리와 확장성을 처리합니다.</p>
<ul>
<li>자동 확장: 요청이 증가하면 클라우드 제공자가 자동으로 더 많은 인스턴스를 생성하여 트래픽을 처리합니다.</li>
<li>과금 모델: 실행된 함수에 대해서만 과금되며, 함수가 실행되지 않으면 비용이 발생하지 않습니다.</li>
<li>실행 환경: 서버리스 함수는 특정 이벤트(HTTP 요청, 데이터베이스 트리거 등)에 의해 호출되며, 짧은 시간 동안 실행됩니다.</li>
</ul>
<p>서버리스 모델을 사용하면 인프라 관리 없이도 코드의 배포와 실행을 효율적으로 처리할 수 있습니다.</p>
<blockquote>
<p>Next.js 환경에서는 API Routes를 사용하여 app/api 또는 pages/api 디렉토리에 서버리스 함수를 정의할 수 있습니다.</p>
</blockquote>
<h3 id="로드-밸런싱이란">로드 밸런싱이란?</h3>
<p><strong>로드 밸런싱</strong>은 <strong>네트워크나 애플리케이션 트래픽을 여러 서버(또는 인스턴스)로 분산시켜, 서버의 부하를 고르게 분배하는 기술</strong>입니다. 이를 통해 <strong>하나의 서버에 과도한 요청이 몰리는 것을 방지하고, 시스템의 성능과 안정성을 높일 수 있습니다</strong>.</p>
<ul>
<li>트래픽 분산: 로드 밸런서는 클라이언트 요청을 여러 서버로 분배하여, 특정 서버에 과부하가 걸리지 않도록 합니다.</li>
<li>가용성 향상: 서버 중 하나가 장애를 일으키더라도, 로드 밸런서는 다른 서버로 트래픽을 전환해 서비스를 지속적으로 제공할 수 있습니다.</li>
<li>확장성: 로드 밸런싱을 통해 시스템이 수평적으로 확장될 수 있으며, 트래픽 증가에 대응하기 위해 서버를 쉽게 추가할 수 있습니다.</li>
</ul>
<p>로드 밸런싱은 웹 애플리케이션의 성능 최적화와 가용성을 높이기 위해 중요한 역할을 합니다.</p>
<h3 id="ddos-공격이란">DDos 공격이란?</h3>
<p>DDoS(Distracted Denial of Service) 공격은 <strong>대규모의 트래픽을 특정 서버나 네트워크에 집중적으로 전송하여, 정상적인 서비스가 불가능하게 만드는 사이버 공격</strong>입니다. DDoS 공격은 일반적으로 분산된 여러 컴퓨터(봇넷)가 동시에 공격을 수행해, 타겟 서버의 자원을 고갈시킵니다.</p>
<ul>
<li>목적: 서비스 방해 또는 중단을 목적으로, 서버의 CPU, 메모리, 네트워크 대역폭 등을 과부하 상태로 만들어 서비스를 제공하지 못하게 합니다.</li>
<li>공격 방법: 공격자는 악성 소프트웨어를 통해 수천, 수만 대의 컴퓨터를 감염시켜 하나의 거대한 봇넷을 형성한 후, 특정 서버에 대량의 요청을 보내 DDoS 공격을 수행합니다.</li>
<li>대응 방법: 로드 밸런싱, 웹 애플리케이션 방화벽(WAF), DDoS 보호 서비스(AWS Shield, Cloudflare 등)를 통해 DDoS 공격을 완화하거나 방어할 수 있습니다.</li>
</ul>
<p>DDoS 공격은 서비스 가용성을 저해하고, 비즈니스에 심각한 영향을 미칠 수 있기 때문에 적절한 보안 대책이 필요합니다.</p>
<hr>
<blockquote>
<p>추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Webpack이란? CRA 없이 직접 설정하기, 다른 모듈 번들러와의 비교 (feat. vite, turbopack, rollup, parcel)]]></title>
            <link>https://velog.io/@hi-rachel/Webpack%EC%9D%B4%EB%9E%80-CRA-%EC%97%86%EC%9D%B4-%EC%A7%81%EC%A0%91-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0-%EB%8B%A4%EB%A5%B8-%EB%AA%A8%EB%93%88-%EB%B2%88%EB%93%A4%EB%9F%AC%EC%99%80%EC%9D%98-%EB%B9%84%EA%B5%90-feat.-vite-turbopack-rollup-parcel</link>
            <guid>https://velog.io/@hi-rachel/Webpack%EC%9D%B4%EB%9E%80-CRA-%EC%97%86%EC%9D%B4-%EC%A7%81%EC%A0%91-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0-%EB%8B%A4%EB%A5%B8-%EB%AA%A8%EB%93%88-%EB%B2%88%EB%93%A4%EB%9F%AC%EC%99%80%EC%9D%98-%EB%B9%84%EA%B5%90-feat.-vite-turbopack-rollup-parcel</guid>
            <pubDate>Fri, 09 Aug 2024 09:48:52 GMT</pubDate>
            <description><![CDATA[<p>웹팩(Webpack)은 현대 웹 개발에서 매우 중요한 역할을 하는 모듈 번들러(module bundler)입니다. 웹팩을 이해하고 효과적으로 사용하는 것은 프론트엔드 개발자에게 필수적인 기술 중 하나입니다. 웹팩은 코드의 구조를 최적화하고, 개발 효율성을 높이며, 성능 향상을 도모할 수 있는 강력한 도구입니다.</p>
<h2 id="1-웹팩webpack이란">1. 웹팩(Webpack)이란?</h2>
<p><strong>웹팩은 자바스크립트, CSS, 이미지, 폰트 등 다양한 자산(assets)을 하나의 파일 또는 여러 파일로 번들링하여 웹 애플리케이션의 로딩 속도와 성능을 최적화하는 도구</strong>입니다. 웹팩은 모듈을 관리하고 의존성을 해결하여 최종적으로 하나의 번들로 묶어줍니다. 이를 통해 코드의 복잡성을 줄이고, 성능을 개선할 수 있습니다.</p>
<h2 id="2-웹팩의-주요-개념">2. 웹팩의 주요 개념</h2>
<h3 id="21-entry-엔트리">2.1. Entry (엔트리)</h3>
<ul>
<li><p><strong>엔트리는 웹팩이 번들링을 시작하는 지점</strong>을 의미합니다. 일반적으로 엔트리는 자바스크립트 파일이며, 이 파일을 시작으로 모든 의존성을 추적하여 번들을 생성합니다.</p>
</li>
<li><p>기본적인 웹팩 설정에서 entry 속성은 필수입니다.</p>
<pre><code class="language-javascript">module.exports = {
  entry: &quot;./src/index.js&quot;, // 웹팩이 번들링을 시작할 파일
};</code></pre>
</li>
</ul>
<h3 id="22-output-아웃풋">2.2. Output (아웃풋)</h3>
<ul>
<li><p><strong>아웃풋은 웹팩이 생성한 번들을 저장할 위치와 파일 이름을 지정하는 속성입니다. 번들링된 파일이 output에 정의된 경로에 저장</strong>됩니다.</p>
<pre><code class="language-javascript">module.exports = {
  entry: &quot;./src/index.js&quot;,
  output: {
    path: path.resolve(__dirname, &quot;dist&quot;), // 번들된 파일의 저장 경로, path.resolve를 사용해 절대 경로 생성
    filename: &quot;bundle.js&quot;, // 번들된 파일 이름
  },
};</code></pre>
</li>
</ul>
<h3 id="23-loaders-로더">2.3. Loaders (로더)</h3>
<ul>
<li><p><strong>로더는 웹팩이 자바스크립트 외의 파일을 처리할 수 있게 해주는 도구</strong>입니다. 예를 들어, CSS, 이미지, 폰트 파일 등을 모듈로 취급하고, 이를 자바스크립트 파일에서 사용할 수 있게 변환해줍니다.</p>
</li>
<li><p>로더는 <strong>파일의 전처리</strong>를 담당하기도 합니다. 즉, 특정 파일을 변환하거나 처리하여 웹팩이 번들에 포함할 수 있는 형태로 만드는 역할을 합니다.</p>
</li>
<li><p>로더는 module.rules 속성에서 정의하며, 특정 파일 유형에 대해 어떤 로더를 사용할지 지정합니다.</p>
<pre><code class="language-javascript">module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/, // .css 확장자를 가진 파일에 대해
        use: [&quot;style-loader&quot;, &quot;css-loader&quot;], // style-loader와 css-loader를 적용
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i, // 이미지 파일에 대해
        type: &quot;asset/resource&quot;, // 자산 리소스로 처리
      },
    ],
  },
};</code></pre>
</li>
</ul>
<h3 id="24-plugins-플러그인">2.4. Plugins (플러그인)</h3>
<ul>
<li><p>플러그인은 웹팩의 기능을 확장하거나, 번들링 과정에서 발생하는 다양한 작업을 수행하기 위해 사용됩니다. 예를 들어, HTML 파일을 자동으로 생성하거나, 코드 압축, 환경 변수 설정 등을 할 수 있습니다.</p>
</li>
<li><p>대표적인 플러그인으로는 HtmlWebpackPlugin, CleanWebpackPlugin, MiniCssExtractPlugin 등이 있습니다.</p>
<pre><code class="language-javascript">const HtmlWebpackPlugin = require(&quot;html-webpack-plugin&quot;);

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: &quot;./src/index.html&quot;, // 번들링된 JS 파일을 포함할 HTML 파일 템플릿
    }),
  ],
};</code></pre>
</li>
</ul>
<h3 id="25-mode-모드">2.5. Mode (모드)</h3>
<ul>
<li><p>웹팩은 mode 설정을 통해 개발(development) 모드와 프로덕션(production) 모드를 구분합니다.</p>
</li>
<li><p>개발 모드에서는 디버깅을 용이하게 하고, 프로덕션 모드에서는 코드 최적화(압축, 난독화 등)를 수행합니다.</p>
<pre><code class="language-javascript">module.exports = {
  mode: &quot;development&quot;, // &#39;development&#39; 또는 &#39;production&#39;
};</code></pre>
</li>
</ul>
<h2 id="3-웹팩의-동작-과정">3. 웹팩의 동작 과정</h2>
<ol>
<li>엔트리 포인트에서 시작: 웹팩은 설정된 엔트리 파일을 기준으로 모든 의존성을 추적합니다.</li>
<li>모듈 및 의존성 분석: 웹팩은 로더를 사용해 다양한 파일 유형을 처리하고, 모듈 간의 의존성을 분석합니다.</li>
<li>번들 생성: 웹팩은 분석된 모듈을 기반으로 하나 또는 여러 개의 번들을 생성합니다.</li>
<li>출력: 생성된 번들은 output에 정의된 경로에 저장됩니다.</li>
</ol>
<h2 id="4-웹팩의-실사용-예시">4. 웹팩의 실사용 예시</h2>
<h3 id="41-개발-환경에서의-사용">4.1. 개발 환경에서의 사용</h3>
<ul>
<li>개발 환경에서는 webpack-dev-server를 사용해 실시간으로 변경사항을 반영하며 개발할 수 있습니다.</li>
<li>소스 맵(source map)을 사용해 디버깅을 쉽게 할 수 있습니다.</li>
</ul>
<pre><code class="language-javascript">module.exports = {
  mode: &quot;development&quot;,
  devtool: &quot;inline-source-map&quot;, // 소스 맵을 활성화
  devServer: {
    contentBase: &quot;./dist&quot;, // 개발 서버의 파일 제공 경로
  },
};</code></pre>
<h3 id="42-프로덕션-환경에서의-사용">4.2. 프로덕션 환경에서의 사용</h3>
<ul>
<li>프로덕션 모드에서는 번들 파일을 최적화하여 배포할 수 있습니다.</li>
<li>코드 압축, 환경 변수 설정, 코드 스플리팅 등을 통해 성능을 극대화합니다.</li>
</ul>
<pre><code class="language-javascript">const MiniCssExtractPlugin = require(&quot;mini-css-extract-plugin&quot;);

module.exports = {
  mode: &quot;production&quot;,
  output: {
    filename: &quot;[name].[contenthash].js&quot;, // 캐싱을 위한 해시 추가
    path: __dirname + &quot;/dist&quot;,
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: &quot;[name].[contenthash].css&quot;,
    }),
  ],
};</code></pre>
<h2 id="5-웹팩의-고급-기능">5. 웹팩의 고급 기능</h2>
<h3 id="51-코드-스플리팅-code-splitting">5.1. 코드 스플리팅 (Code Splitting)</h3>
<p>코드 스플리팅은 번들을 여러 개로 나누어 성능을 최적화하는 기법입니다. 이를 통해 초기 로딩 시간을 줄이고, 필요할 때만 코드가 로드되도록 할 수 있습니다.</p>
<pre><code class="language-javascript">module.exports = {
  optimization: {
    splitChunks: {
      chunks: &quot;all&quot;, // 중복된 모듈을 별도의 청크로 분리
    },
  },
};</code></pre>
<h3 id="52-트리-쉐이킹-tree-shaking">5.2. 트리 쉐이킹 (Tree Shaking)</h3>
<p>트리 쉐이킹은 사용하지 않는 코드를 제거하여 번들 크기를 줄이는 기법입니다. ES6 모듈 시스템을 사용하는 경우 웹팩은 자동으로 트리 쉐이킹을 수행합니다.</p>
<pre><code class="language-javascript">module.exports = {
  mode: &quot;production&quot;, // 프로덕션 모드에서 트리 쉐이킹 활성화
};</code></pre>
<h2 id="6-웹팩-설정-파일-webpackconfigjs">6. 웹팩 설정 파일 (webpack.config.js)</h2>
<ul>
<li><p>웹팩 설정 파일은 일반적으로 프로젝트 루트에 webpack.config.js라는 이름으로 작성됩니다.</p>
</li>
<li><p>이 파일을 통해 웹팩의 엔트리, 아웃풋, 로더, 플러그인 등을 구성할 수 있습니다.</p>
<pre><code class="language-javascript">const path = require(&quot;path&quot;);
const HtmlWebpackPlugin = require(&quot;html-webpack-plugin&quot;);
const { CleanWebpackPlugin } = require(&quot;clean-webpack-plugin&quot;);

module.exports = {
  entry: &quot;./src/index.js&quot;,
  output: {
    filename: &quot;bundle.js&quot;,
    path: path.resolve(__dirname, &quot;dist&quot;),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [&quot;style-loader&quot;, &quot;css-loader&quot;],
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(), // dist 폴더 정리
    new HtmlWebpackPlugin({
      template: &quot;./src/index.html&quot;,
    }),
  ],
  mode: &quot;development&quot;, // 또는 &#39;production&#39;
};</code></pre>
</li>
</ul>
<h2 id="✏️-정리---웹팩을-왜-쓰나요">✏️ 정리 - 웹팩을 왜 쓰나요?</h2>
<p>웹팩은 프론트엔드 개발자의 생산성을 크게 향상시킬 수 있는 도구입니다. 웹팩을 사용하면 <strong>코드의 모듈화를 유지하면서도 최적화된 번들을 생성</strong>할 수 있으며, <strong>다양한 로더와 플러그인을 통해 다양한 파일 형식을 처리</strong>하고, 최신 웹 기술을 손쉽게 도입할 수 있습니다. 프론트엔드 개발자는 웹팩을 사용하여 보다 효율적이고 관리하기 쉬운 애플리케이션을 구축할 수 있습니다.</p>
<hr>
<h2 id="✏️-용어-정리">✏️ <strong>용어 정리</strong></h2>
<h3 id="모듈-번들러란">모듈 번들러란?</h3>
<p><strong>모듈 번들러(Module Bundler)는 여러 개의 파일로 나누어진 모듈(예: 자바스크립트 파일, CSS 파일, 이미지 등)을 하나 또는 여러 개의 번들(bundle) 파일로 묶어주는 도구</strong>입니다. 모듈 번들러는 애플리케이션을 구성하는 모든 자산(assets)을 하나의 모듈로 취급하고, 이러한 모듈 간의 의존성을 분석하여 최종적으로 효율적인 배포를 위해 번들 파일을 생성합니다.</p>
<h3 id="모듈-번들러의-필요성">모듈 번들러의 필요성</h3>
<p>모던 웹 애플리케이션은 일반적으로 복잡한 구조를 가지며, 여러 개의 자바스크립트 파일, CSS 파일, 이미지 파일 등이 서로 의존관계를 맺고 있습니다. 이러한 구조에서는 다음과 같은 문제들이 발생할 수 있습니다:</p>
<ol>
<li><p><strong>의존성 관리</strong>: 여러 파일 간의 의존성을 관리하기 어렵습니다. 어떤 파일이 어떤 파일에 의존하는지, 어떤 순서로 로드해야 하는지 등을 수동으로 관리하는 것은 매우 번거롭습니다.
👉 모듈 번들러는 애플리케이션의 엔트리 포인트에서 시작하여 모든 모듈의 의존성을 분석합니다. 이를 통해 각 모듈이 필요한 순서에 따라 번들에 포함되도록 합니다.</p>
</li>
<li><p><strong>네트워크 요청 과다</strong>: 파일이 많아질수록 웹 페이지를 로드하는 데 필요한 네트워크 요청이 증가하게 됩니다. 이는 페이지 로딩 속도를 저하시키고 사용자 경험을 악화시킬 수 있습니다.
👉 분석된 모듈을 하나의 파일 또는 여러 개의 파일로 번들링합니다. 이를 통해 애플리케이션에서 필요한 자산을 최소한의 네트워크 요청으로 로드할 수 있습니다.</p>
</li>
<li><p><strong>코드 최적화</strong>: 각 파일에 포함된 중복된 코드나 사용하지 않는 코드(dead code)를 관리하고 제거하는 것이 어렵습니다.
👉 모듈 번들러는 코드 최적화 작업도 수행합니다. 예를 들어, 중복된 코드를 제거하거나 사용되지 않는 코드를 제거하여 번들 크기를 줄이고, 로딩 속도를 향상시킵니다. 코드 스플리팅, 트리 쉐이킹 등과 같은 고급 최적화 기법을 지원합니다.</p>
</li>
<li><p><strong>브라우저 호환성</strong>: 번들러는 최신 자바스크립트 문법을 구 버전의 브라우저에서도 동작할 수 있도록 트랜스파일링(transpiling)해줍니다.
👉 모듈 번들러는 자바스크립트 파일뿐만 아니라 CSS, 이미지, 폰트 등의 파일도 처리할 수 있습니다. 이를 위해 로더(Loaders)와 플러그인(Plugins)을 사용하여 다양한 파일 형식을 지원합니다. 예를 들어, SCSS 파일을 CSS 파일로 변환하거나, 최신 자바스크립트 문법을 오래된 브라우저에서도 동작하도록 변환할 수 있습니다.</p>
</li>
</ol>
<p>모듈 번들러는 이러한 문제를 해결하기 위해 등장한 도구입니다.</p>
<h3 id="대표적인-모듈-번들러">대표적인 모듈 번들러</h3>
<ol>
<li><p><strong>웹팩(Webpack)</strong>: 가장 널리 사용되는 모듈 번들러로, 강력한 기능과 유연한 설정을 자랑합니다. 다양한 플러그인과 로더를 통해 거의 모든 파일 형식을 처리할 수 있으며, 코드 스플리팅, 트리 쉐이킹 등의 고급 최적화 기법을 지원합니다.</p>
</li>
<li><p><strong>롤업(Rollup)</strong>: 주로 라이브러리 번들링에 특화된 모듈 번들러로, 웹팩보다 간단한 설정과 더 작은 번들 크기를 제공합니다. 트리 쉐이킹에 강점을 가지고 있어, 불필요한 코드를 제거하는 데 효과적입니다. ESM을 중심으로 설계된 모듈 번들러.</p>
<ul>
<li>롤업은 오픈 소스 라이브러리(예: lodash, d3.js)나 작은 패키지를 개발할 때 많이 사용됩니다. 롤업의 플러그인 시스템을 통해 다양한 형식으로 라이브러리를 번들링할 수 있습니다.</li>
<li>ESM(ECMAScript Module) 지원: 롤업은 ESM을 기본적으로 지원하여, 현대적인 모듈 시스템을 사용하는 프로젝트에서 유용합니다. 예를 들어, 라이브러리를 개발할 때, ESM 형식으로 배포하기 위해 롤업을 사용할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>파셀(Parcel)</strong>: 설정이 거의 필요 없는 “제로 설정” 모듈 번들러로, 개발자가 번들링 설정에 시간을 들이지 않고도 빠르게 개발을 시작할 수 있도록 도와줍니다. 또한, 멀티 코어를 활용하여 번들링 속도가 빠릅니다.</p>
<ul>
<li>신속한 프로토타이핑: 빠르게 프로토타입을 만들고 싶을 때, 파셀을 사용하면 설정 파일 없이 프로젝트를 빠르게 시작할 수 있습니다. 예를 들어, 개발 초기 단계에서 빠르게 기능을 구현하고 테스트하기에 적합합니다.</li>
<li>소규모 프로젝트: 소규모 웹 애플리케이션이나 개인 프로젝트에서 파셀은 뛰어난 선택입니다. 복잡한 빌드 설정 없이 다양한 기능을 지원하여, 빠른 개발이 가능합니다.</li>
</ul>
</li>
</ol>
<h3 id="실무에서의-사용-예">실무에서의 사용 예</h3>
<p>프론트엔드 개발자는 모듈 번들러를 사용하여 여러 개의 파일을 효율적으로 관리하고, 애플리케이션을 최적화할 수 있습니다. 예를 들어, <strong>웹팩을 사용하여 자바스크립트 파일을 번들링</strong>하고, <strong>SCSS 파일을 CSS 파일로 변환</strong>하며, <strong>이미지 파일을 최적화</strong>하는 과정을 설정할 수 있습니다. 이를 통해 개발자는 코드의 구조를 유지하면서도 성능 최적화를 달성할 수 있습니다.</p>
<h3 id="esm이란">ESM이란?</h3>
<p><strong>ESM(ECMAScript Module)</strong>은 자바스크립트에서 모듈 시스템을 표준화한 사양입니다. ESM은 ES6(ECMAScript 2015)에서 도입된 모듈 시스템으로, 자바스크립트 코드를 모듈화하여 재사용성과 유지보수성을 높이기 위해 설계되었습니다. 이전의 모듈 시스템들(예: CommonJS, AMD)과는 달리, <strong>ESM은 자바스크립트 언어 자체의 표준</strong>으로 자리 잡았습니다.</p>
<p><strong>주요 특징</strong></p>
<ol>
<li><strong>파일 단위의 모듈</strong>: ESM에서는 각 파일이 독립적인 모듈로 취급됩니다. 모듈은 다른 모듈에서 내보낸(export) 변수나 함수를 가져오기(import)하여 사용할 수 있습니다.</li>
<li><strong>정적 분석 가능</strong>: ESM은 정적 분석이 가능하도록 설계되었습니다. <strong>모듈의 의존성이 코드 실행 전에 결정</strong>되므로, 트리 쉐이킹과 같은 최적화 기법을 적용하기 쉽습니다.</li>
<li><strong>엄격한 모드</strong>: ESM은 자동으로 엄격 모드(“use strict”)가 적용됩니다. 이는 실수나 버그를 줄이고, 더 나은 성능을 보장합니다.</li>
<li><strong>비동기 로드 지원</strong>: ESM은 비동기적으로 모듈을 로드할 수 있어, 특히 브라우저 환경에서 성능 최적화에 유리합니다.</li>
</ol>
<hr>
<h2 id="🔥-터보팩turbopack이란">🔥 터보팩(Turbopack)이란?</h2>
<p><strong>터보팩(Turbopack)</strong>은 Vercel에서 개발한 초고속 웹 애플리케이션 번들러로, 기존의 웹팩(Webpack)을 대체할 수 있는 새로운 도구로 자리매김하고 있습니다. 터보팩은 특히 성능과 빌드 속도에 중점을 두고 설계되었으며, 대규모 프로젝트에서도 빠른 빌드 타임을 제공하는 것을 목표로 합니다.</p>
<p><strong>터보팩의 주요 특징</strong></p>
<ol>
<li><p><strong>속도</strong>: 터보팩의 가장 큰 장점은 빌드 속도입니다. Rust로 작성된 터보팩은 고성능을 자랑하며, 웹팩과 비교하여 빌드 속도가 최대 수십 배 빠르다고 알려져 있습니다. 이로 인해 대규모 애플리케이션에서의 빌드 시간을 크게 단축할 수 있습니다.</p>
</li>
<li><p><strong>점진적 번들링(Incremental Bundling)</strong>: 터보팩은 변화가 발생한 파일만 재번들링하는 점진적 번들링 방식을 채택하여, 불필요한 빌드 시간을 줄이고 빠른 피드백을 제공합니다. 이를 통해 개발자는 더 빠르게 코드를 작성하고 테스트할 수 있습니다.</p>
</li>
<li><p><strong>Rust 기반</strong>: Rust로 작성되어 높은 성능과 메모리 안전성을 보장합니다. 이는 JavaScript로 작성된 기존의 번들러들보다 더 나은 성능을 제공합니다.</p>
</li>
<li><p><strong>완전한 웹팩 대체는 아님</strong>: 현재 터보팩은 일부 기능에서 웹팩을 완전히 대체하지는 않습니다. 특히 플러그인 생태계나 일부 고급 기능에서는 웹팩이 여전히 더 강력한 선택일 수 있습니다. 그러나 터보팩은 빠른 성능을 요구하는 프로젝트에서 웹팩의 대안으로 유망한 선택지가 되고 있습니다.</p>
</li>
</ol>
<p><strong>터보팩의 사용 사례</strong></p>
<p>터보팩은 특히 Next.js 프로젝트에서 잘 통합되어 사용됩니다. Vercel은 Next.js의 개발사로, Next.js 프로젝트에 최적화된 번들러를 제공하기 위해 터보팩을 개발했습니다. Next.js 13 버전부터 터보팩이 웹팩의 대체제로 제공되며, 개발 환경에서 빠른 빌드 속도를 제공합니다.</p>
<p>터보팩은 고성능을 요구하는 대규모 프로젝트나 빌드 시간이 중요한 프로젝트에서 주로 사용됩니다. 특히 대규모 코드베이스를 다루는 기업형 애플리케이션에서 터보팩의 속도 향상 효과를 극대화할 수 있습니다.</p>
<p><strong>웹팩과의 비교</strong></p>
<ul>
<li>성능: 터보팩은 웹팩보다 훨씬 빠른 빌드 속도를 제공합니다. 특히 대규모 프로젝트에서 그 성능 차이가 더 크게 나타납니다.</li>
<li>생태계: 웹팩은 수년간 개발되어 온 방대한 플러그인과 설정 옵션을 가지고 있습니다. 터보팩은 아직 초기 단계에 있으며, 일부 고급 기능에서는 웹팩이 더 유리할 수 있습니다.</li>
<li>사용성: 웹팩은 다양한 플러그인과 설정을 지원하는 유연한 도구이지만, 설정이 복잡할 수 있습니다. 터보팩은 더 간단한 설정을 목표로 하고 있으며, 기본 설정만으로도 빠른 번들링이 가능합니다.</li>
</ul>
<p><strong>결론</strong></p>
<p>터보팩은 웹팩의 대체제로서 강력한 번들링 성능을 제공하지만, 현재로서는 웹팩과 상호 보완적인 관계로 사용할 수 있습니다. 특히 빠른 빌드 속도가 중요한 프로젝트에서 터보팩은 매력적인 선택이 될 수 있습니다.</p>
<hr>
<h2 id="nextjs에서의-모듈-번들링">Next.js에서의 모듈 번들링</h2>
<p>Next.js는 웹팩을 내부적으로 사용하여 번들링 작업을 수행합니다. 그러나 Next.js는 개발자가 웹팩 설정을 직접 다루지 않도록 대부분의 설정을 자동화해둔 상태로 제공됩니다. 이는 개발자가 설정보다는 개발 자체에 집중할 수 있도록 돕습니다.</p>
<p>Next.js에서 기본 웹팩 설정을 커스터마이징해야 할 경우, next.config.js 파일을 사용합니다.</p>
<pre><code class="language-javascript">// next.config.js
module.exports = {
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) =&gt; {
    // 웹팩 설정 수정
    config.plugins.push(new webpack.IgnorePlugin(/\/__tests__\//));

    // 커스텀 설정을 반환
    return config;
  },
};</code></pre>
<h3 id="nextjs와-웹팩-터보팩의-관계">Next.js와 웹팩, 터보팩의 관계</h3>
<p>Next.js는 초기에는 웹팩(Webpack)을 내부적으로 사용해 왔으나, Next.js 13부터는 터보팩(Turbopack)을 도입하여 성능을 개선하고 있습니다. 그러나 웹팩과 터보팩을 동시에 사용하는 것은 아닙니다. 개발자가 선택할 수 있는 옵션으로, 기본적으로는 웹팩을 사용하되, 터보팩을 사용하고자 할 때는 터보팩을 활성화할 수 있습니다.</p>
<p>비교</p>
<ul>
<li><p>웹팩(Webpack): 전통적으로 Next.js는 웹팩을 사용하여 모듈 번들링과 개발 환경을 지원해 왔습니다. 웹팩은 강력한 플러그인 생태계를 가지고 있으며, Next.js는 기본적으로 웹팩을 사용해 개발 모드에서 HMR(Hot Module Replacement) 등 다양한 기능을 제공합니다.</p>
</li>
<li><p>터보팩(Turbopack): Next.js 13에서 소개된 새로운 모듈 번들러로, 성능을 극대화하기 위해 설계되었습니다. 터보팩은 웹팩보다 훨씬 빠르게 번들링 작업을 수행할 수 있도록 설계되었으며, 특히 대규모 프로젝트에서 빌드 속도를 크게 개선합니다. 터보팩은 Rust로 구현되어 있어 높은 성능을 자랑합니다.</p>
</li>
</ul>
<p>웹팩과 터보팩의 선택</p>
<ul>
<li><strong>Next.js 13 이전: 기본적으로 웹팩이 사용</strong>됩니다.</li>
<li><strong>Next.js 13 이후: 기본적으로 웹팩이 사용되지만, next.config.js에서 옵션을 설정하여 터보팩을 활성화</strong>할 수 있습니다. 개발자는 프로젝트 요구에 따라 웹팩을 계속 사용할 수도 있고, 터보팩으로 전환할 수도 있습니다.</li>
</ul>
<hr>
<h2 id="⭐️-react-nextjs에서의-모듈-번들링-핵심-포인트-정리">⭐️ React, Next.js에서의 모듈 번들링 핵심 포인트 정리</h2>
<ul>
<li><p><strong>트리 쉐이킹</strong>: 사용하지 않는 코드를 제거하여 최종 번들의 크기를 줄이는 기능. Next.js는 기본적으로 트리 쉐이킹을 지원합니다.</p>
</li>
<li><p><strong>코드 스플리팅</strong>: 번들 파일을 여러 개로 나누어 필요한 부분만 로드하게 함으로써 초기 로드 시간을 단축. React와 Next.js 모두 코드 스플리팅을 쉽게 구현할 수 있습니다.</p>
</li>
<li><p><strong>핫 모듈 리플레이스먼트(HMR)</strong>: 코드 변경 시 전체 페이지를 새로고침하지 않고도 변경된 부분만 업데이트하는 기능. Next.js는 개발 모드에서 HMR을 기본으로 지원합니다. React에서는 CRA으로 생성된 프로젝트에 HMR이 자동으로 설정되어 있습니다.</p>
<ul>
<li>webpack-dev-server 또는 webpack-hot-middleware를 설정하여 HMR을 활성화할 수 있습니다.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="🤔-react에서-cra-없이-webpack을-직접-설정하려면">🤔 React에서 CRA 없이 webpack을 직접 설정하려면?</h2>
<p>npx create-react-app을 사용할 수도 있지만, 웹팩을 수동으로 설정하는 예시</p>
<ol>
<li>React 프로젝트 설정</li>
</ol>
<pre><code class="language-bash">mkdir react-webpack-example
cd react-webpack-example
npm init -y // or yarn init -y</code></pre>
<ol start="2">
<li>필요한 패키지 설치</li>
</ol>
<pre><code class="language-bash">npm install react react-dom
npm install --save-dev webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env @babel/preset-react html-webpack-plugin</code></pre>
<ol start="3">
<li><p>폴더 구조</p>
<p>react-webpack-example/
├── node_modules/
├── public/
│ └── index.html
├── src/
│ ├── index.js
│ └── App.js
├── package.json
├── webpack.config.js
└── .babelrc</p>
</li>
</ol>
<blockquote>
<p>폴더 구조는 프로젝트에 따라 변경될 수 있음.</p>
</blockquote>
<ol start="4">
<li>Webpack 설정 (webpack.config.js)</li>
</ol>
<blockquote>
<p>TypeScript, tailwindCSS, babel을 사용하는 Webpack 설정 예시</p>
</blockquote>
<pre><code class="language-javascript">const path = require(&quot;path&quot;);
const HtmlWebpackPlugin = require(&quot;html-webpack-plugin&quot;);
const MiniCssExtractPlugin = require(&quot;mini-css-extract-plugin&quot;);

module.exports = {
  entry: &quot;./src/index.tsx&quot;, // TypeScript 엔트리 파일
  output: {
    filename: &quot;bundle.[contenthash].js&quot;, // 해시를 사용해 캐싱 문제를 해결
    path: path.resolve(__dirname, &quot;dist&quot;),
  },
  resolve: {
    extensions: [&quot;.ts&quot;, &quot;.tsx&quot;, &quot;.js&quot;, &quot;.jsx&quot;], // TypeScript와 JavaScript 파일의 확장자 처리
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/, // .ts, .tsx 파일을 처리
        use: &quot;babel-loader&quot;, // Babel을 사용해 TypeScript를 컴파일
        exclude: /node_modules/,
      },
      {
        test: /\.css$/, // .css 파일을 처리
        use: [
          MiniCssExtractPlugin.loader, // CSS 파일을 별도로 추출
          &quot;css-loader&quot;, // CSS를 JS로 변환
          &quot;postcss-loader&quot;, // Tailwind CSS를 처리하기 위해 postcss-loader 사용
        ],
      },
      {
        test: /\.(png|jpg|gif|svg)$/, // 이미지 파일을 처리
        type: &quot;asset/resource&quot;, // 파일을 별도로 관리
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: &quot;./public/index.html&quot;, // HTML 템플릿 파일
    }),
    new MiniCssExtractPlugin({
      filename: &quot;[name].[contenthash].css&quot;, // CSS 파일의 이름 패턴
    }),
  ],
  devServer: {
    static: path.join(__dirname, &quot;dist&quot;), // 개발 서버에서 제공할 정적 파일 경로
    compress: true,
    port: 3000,
    hot: true, // HMR 활성화
    open: true, // 개발 서버가 시작될 때 브라우저 자동 열기
  },
};</code></pre>
<blockquote>
<p>tailwindCSS는 post.config.js 설정, 설치 후 tailwind.config.js 파일이 추가로 필요합니다.
TypeScript는 tsconfig.json 파일 설정이 필요합니다.</p>
</blockquote>
<ol start="5">
<li>Babel 설정 (.babelrc)</li>
</ol>
<pre><code class="language-json">{
  &quot;presets&quot;: [
    &quot;@babel/preset-env&quot;, // 최신 JavaScript 문법 변환
    &quot;@babel/preset-react&quot;, // React 문법 변환
    &quot;@babel/preset-typescript&quot; // TypeScript 변환
  ]
}</code></pre>
<ol start="6">
<li><p>React 컴포넌트 작성</p>
<p>src/index.js</p>
</li>
</ol>
<pre><code class="language-javascript">import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom&quot;;
import App from &quot;./App&quot;;

ReactDOM.render(&lt;App /&gt;, document.getElementById(&quot;root&quot;));</code></pre>
<p>  src/App.js</p>
<pre><code class="language-javascript">import React from &quot;react&quot;;

function App() {
  return (
    &lt;div&gt;
      &lt;h1&gt;Hello, React with Webpack!&lt;/h1&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<ol start="7">
<li><p>HTML 템플릿 작성</p>
<p>public/index.html</p>
</li>
</ol>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;React Webpack Example&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;root&quot;&gt;&lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<blockquote>
<p>index.html이 최상위 경로에 있을 수도 있음.
-&gt; webpack.config.js에서 경로 수정 필요</p>
<pre><code class="language-javascript"> template: &#39;./index.html&#39;,</code></pre>
</blockquote>
<ol start="8">
<li>package.json 스크립트 추가</li>
</ol>
<pre><code class="language-json">{
  &quot;name&quot;: &quot;react-webpack-example&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;webpack serve --mode development&quot;,
    &quot;build&quot;: &quot;webpack --mode production&quot;
  },
  &quot;dependencies&quot;: {
    &quot;react&quot;: &quot;^18.0.0&quot;,
    &quot;react-dom&quot;: &quot;^18.0.0&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.0.0&quot;,
    &quot;@babel/preset-env&quot;: &quot;^7.0.0&quot;,
    &quot;@babel/preset-react&quot;: &quot;^7.0.0&quot;,
    &quot;babel-loader&quot;: &quot;^8.0.0&quot;,
    &quot;css-loader&quot;: &quot;^5.0.0&quot;,
    &quot;html-webpack-plugin&quot;: &quot;^5.0.0&quot;,
    &quot;style-loader&quot;: &quot;^2.0.0&quot;,
    &quot;webpack&quot;: &quot;^5.0.0&quot;,
    &quot;webpack-cli&quot;: &quot;^4.0.0&quot;,
    &quot;webpack-dev-server&quot;: &quot;^3.0.0&quot;
  }
}</code></pre>
<ol start="9">
<li>애플리케이션 실행</li>
</ol>
<pre><code class="language-bash">npm start</code></pre>
<p>개발 서버를 시작하고, 브라우저에서 해당 애플리케이션 확인 가능</p>
<hr>
<h2 id="✏️-vite">✏️ Vite</h2>
<h3 id="vite란">Vite란?</h3>
<p>Vite는 차세대 프론트엔드 환경을 제공하는 번들러로, 특히 <strong>개발 서버와 빌드 성능 면에서 매우 빠른 속도</strong>를 자랑합니다. <strong>Vite는 ES 모듈을 기본으로 사용하여, 개발 중에는 브라우저가 필요한 모듈만 동적으로 로드하게 함으로써 빠른 핫 모듈 리플레이스먼트(HMR)를 제공</strong>합니다. 또한, <strong>빌드 단계에서는 Rollup을 사용하여 최적화된 번들을 생성</strong>합니다.</p>
<h3 id="vite와-webpack의-관계">Vite와 Webpack의 관계</h3>
<p>Vite와 Webpack은 모두 모듈 번들러로서의 역할을 하지만, 접근 방식과 사용 사례가 다릅니다.</p>
<ul>
<li><strong>개발 속도</strong>: <strong>Vite는 개발 서버를 제공할 때 ES 모듈 기반으로 작동하며, 필요한 모듈만 즉시 로드하기 때문에 초기 로딩이 매우 빠릅니다</strong>. 반면, <strong>Webpack은 초기 번들링을 수행</strong>해야 하기 때문에 비교적 느릴 수 있습니다.</li>
<li><strong>빌드 속도</strong>: <strong>Vite는 Rollup을 사용해 빌드를 최적화</strong>하며, <strong>Webpack은 다양한 플러그인과 설정을 통해 빌드를 최적화</strong>합니다. <strong>Vite는 단순하고 빠른 빌드에 유리하며, Webpack은 복잡한 애플리케이션에 대한 세밀한 설정이 가능</strong>합니다.</li>
<li><strong>생태계와 확장성</strong>: Webpack은 수년간의 발전을 통해 방대한 플러그인 생태계를 구축해 왔으며, 거의 모든 형태의 프로젝트에 적용할 수 있습니다. 반면, Vite는 비교적 새로운 도구로, 빠른 성능을 제공하지만, 특정 플러그인이나 설정이 필요한 복잡한 프로젝트에서는 Webpack이 더 적합할 수 있습니다.</li>
<li><strong>사용 사례</strong>: Vite는 빠른 개발 피드백이 중요한 소규모 프로젝트나 프로토타이핑에 적합하며, Webpack은 대규모 애플리케이션이나 복잡한 빌드 설정이 필요한 프로젝트에 적합합니다.</li>
</ul>
<p>두 도구는 상호 보완적인 관계에 있으며, 프로젝트의 요구 사항에 따라 적절한 번들러를 선택하는 것이 중요합니다. Vite는 특히 최신 프로젝트에서 빠르게 자리 잡고 있지만, Webpack은 여전히 많은 대규모 프로젝트에서 사용되고 있습니다.</p>
<hr>
<blockquote>
<p>추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[JavaScript History API와 URL 관리 가이드]]></title>
            <link>https://velog.io/@hi-rachel/JavaScript-History-API%EC%99%80-URL-%EA%B4%80%EB%A6%AC-%EA%B0%80%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@hi-rachel/JavaScript-History-API%EC%99%80-URL-%EA%B4%80%EB%A6%AC-%EA%B0%80%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Thu, 08 Aug 2024 12:48:59 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>애플리케이션을 구현하다보면 특정 상황에서 뒤로 가기를 했을 때 예상되는 페이지가 있거나 의도하는 페이지로 이동을 시도하는 상황이 생길 수 있습니다.
History API나 URL 변경 방식을 제대로 알지 못하면 뒤로 가기를 했을 때 엉뚱한 곳으로 가는 상황이 생기거나, 특정 URL로 변경하려면 어떻게 해야 하는지 모르기 때문에 이에 대한 학습이 필요해 한 번 정리해봤습니다.</p>
</blockquote>
<h2 id="javascript의-history-api">JavaScript의 History API</h2>
<p>JavaScript의 History API는 웹 브라우저의 세션 기록(history)을 조작할 수 있는 강력한 도구입니다. 이를 통해 개발자는 사용자가 방문한 페이지의 URL을 변경하거나, 뒤로 가기/앞으로 가기 기능을 제어할 수 있습니다. History API는 주로 단일 페이지 애플리케이션(SPA)에서 사용됩니다.</p>
<p><a href="https://developer.mozilla.org/ko/docs/Web/API/History_API">참고 - MDN History API</a></p>
<h3 id="⭐️-주요-메서드-및-속성">⭐️ 주요 메서드 및 속성</h3>
<ol>
<li><p>history.length
현재 브라우저 세션의 기록 목록에 있는 항목의 수를 반환합니다.</p>
<pre><code class="language-javascript">console.log(history.length); // 예: 5</code></pre>
</li>
<li><p>history.state
현재 기록 항목과 관련된 상태 객체를 반환합니다.</p>
<pre><code class="language-javascript">console.log(history.state);</code></pre>
</li>
<li><p>history.back()
세션 기록에서 이전 페이지로 이동합니다.</p>
<pre><code class="language-javascript">history.back();</code></pre>
</li>
<li><p>history.forward()
세션 기록에서 다음 페이지로 이동합니다.</p>
<pre><code class="language-javascript">history.forward();</code></pre>
</li>
<li><p>history.go(n)
세션 기록에서 특정 위치로 이동합니다. n이 0이면 현재 페이지를 다시 로드하고, 양수이면 앞으로, 음수이면 뒤로 이동합니다.</p>
<pre><code class="language-javascript">history.go(n);</code></pre>
</li>
<li><p>history.pushState(state, title, url)
세션 기록 스택에 상태를 추가합니다. URL을 변경하지만 페이지를 새로 고침하지 않습니다.</p>
<pre><code class="language-javascript">history.pushState({ page: 1 }, &quot;title 1&quot;, &quot;/page1&quot;);</code></pre>
</li>
<li><p>history.replaceState(state, title, url)
현재 기록 항목을 주어진 상태와 URL로 바꿉니다.</p>
<pre><code class="language-javascript">history.replaceState({ page: 2 }, &quot;title 2&quot;, &quot;/page2&quot;);</code></pre>
</li>
</ol>
<h3 id="뒤로-가기-앞으로-가기-이벤트">뒤로 가기, 앞으로 가기 이벤트</h3>
<p>window.onpopstate 이벤트
브라우저의 뒤로 가기 또는 앞으로 가기 버튼을 누르거나, history.back(), history.forward(), history.go() 메서드를 호출할 때 발생합니다. 이 이벤트를 통해 상태를 복원할 수 있습니다.</p>
<pre><code class="language-javascript">window.onpopstate = function (event) {
  console.log(
    &quot;location: &quot; + document.location + &quot;, state: &quot; + JSON.stringify(event.state)
  );
  // 상태 복원 로직
};</code></pre>
<pre><code class="language-javascript">window.addEventListener(&quot;popstate&quot;, (event) =&gt; {
  alert(
    `location: ${document.location}, state: ${JSON.stringify(event.state)}`
  );
});

history.pushState({ page: 1 }, &quot;title 1&quot;, &quot;?page=1&quot;);
history.pushState({ page: 2 }, &quot;title 2&quot;, &quot;?page=2&quot;);
history.replaceState({ page: 3 }, &quot;title 3&quot;, &quot;?page=3&quot;);
history.back(); // &quot;location: http://example.com/example.html?page=1, state: {&quot;page&quot;:1}&quot;라는 알림이 발생합니다.
history.back(); // &quot;location: http://example.com/example.html, state: null&quot;라는 알림이 발생합니다.
history.go(2); // &quot;location: http://example.com/example.html?page=3, state: {&quot;page&quot;:3}&quot;라는 알림이 발생합니다.</code></pre>
<blockquote>
<p><strong>세션 기록 동작 단계별 자세한 설명</strong></p>
<ol>
<li><p>history.pushState({ page: 1 }, &quot;title 1&quot;, &quot;?page=1&quot;);
•    현재 페이지 URL은 <a href="http://example.com/example.html%EC%9E%85%EB%8B%88%EB%8B%A4">http://example.com/example.html입니다</a>.
•    pushState는 현재 URL을 <a href="http://example.com/example.html?page=1%EB%A1%9C">http://example.com/example.html?page=1로</a> 변경하고, 상태 { page: 1 }를 기록에 추가합니다.
•    세션 기록 스택: [null, { page: 1 }]
•    현재 페이지: <a href="http://example.com/example.html?page=1">http://example.com/example.html?page=1</a></p>
</li>
<li><p>history.pushState({ page: 2 }, &quot;title 2&quot;, &quot;?page=2&quot;);
•    현재 페이지 URL은 <a href="http://example.com/example.html?page=1%EC%9E%85%EB%8B%88%EB%8B%A4">http://example.com/example.html?page=1입니다</a>.
•    pushState는 현재 URL을 <a href="http://example.com/example.html?page=2%EB%A1%9C">http://example.com/example.html?page=2로</a> 변경하고, 상태 { page: 2 }를 기록에 추가합니다.
•    세션 기록 스택: [null, { page: 1 }, { page: 2 }]
•    현재 페이지: <a href="http://example.com/example.html?page=2">http://example.com/example.html?page=2</a></p>
</li>
<li><p>history.replaceState({ page: 3 }, &quot;title 3&quot;, &quot;?page=3&quot;);
•    현재 페이지 URL은 <a href="http://example.com/example.html?page=2%EC%9E%85%EB%8B%88%EB%8B%A4">http://example.com/example.html?page=2입니다</a>.
•    replaceState는 현재 URL을 <a href="http://example.com/example.html?page=3%EB%A1%9C">http://example.com/example.html?page=3로</a> 변경하고, 상태 { page: 3 }로 기존 상태를 대체합니다.
•    세션 기록 스택: [null, { page: 1 }, { page: 3 }]
•    현재 페이지: <a href="http://example.com/example.html?page=3">http://example.com/example.html?page=3</a></p>
<ol start="4">
<li><p>history.back();
•    현재 페이지 URL은 <a href="http://example.com/example.html?page=3%EC%9E%85%EB%8B%88%EB%8B%A4">http://example.com/example.html?page=3입니다</a>.
•    back 메서드는 세션 기록에서 이전 항목으로 이동합니다.
•    이동 후 페이지 URL: <a href="http://example.com/example.html?page=1">http://example.com/example.html?page=1</a>
•    상태: { page: 1 }
•    콘솔 출력: &quot;location: <a href="http://example.com/example.html?page=1">http://example.com/example.html?page=1</a>, state: {&quot;page&quot;:1}&quot;</p>
</li>
<li><p>history.back();
•    현재 페이지 URL은 <a href="http://example.com/example.html?page=1%EC%9E%85%EB%8B%88%EB%8B%A4">http://example.com/example.html?page=1입니다</a>.
•    back 메서드는 세션 기록에서 이전 항목으로 이동합니다.
•    이동 후 페이지 URL: <a href="http://example.com/example.html">http://example.com/example.html</a>
•    상태: null
•    콘솔 출력: &quot;location: <a href="http://example.com/example.html">http://example.com/example.html</a>, state: null&quot;</p>
</li>
<li><p>history.go(2);
•    현재 페이지 URL은 <a href="http://example.com/example.html%EC%9E%85%EB%8B%88%EB%8B%A4">http://example.com/example.html입니다</a>.
•    go 메서드는 세션 기록에서 지정된 위치로 이동합니다. 2는 두 단계 앞으로 이동하는 것을 의미합니다.
•    이동 후 페이지 URL: <a href="http://example.com/example.html?page=3">http://example.com/example.html?page=3</a>
•    상태: { page: 3 }
•    콘솔 출력: &quot;location: <a href="http://example.com/example.html?page=3">http://example.com/example.html?page=3</a>, state: {&quot;page&quot;:3}&quot;</p>
</li>
</ol>
</li>
</ol>
</blockquote>
<h2 id="url-관련-메서드-및-속성">URL 관련 메서드 및 속성</h2>
<h3 id="1-windowlocation">1. <strong>window.location</strong></h3>
<p>window.location 객체는 현재 문서의 URL을 나타내며, URL과 관련된 여러 정보를 얻고 변경할 수 있는 속성과 메서드를 제공합니다.</p>
<blockquote>
<p>window는 브라우저 환경에서 자바스크립트 코드가 실행될 때 제공되는 전역 객체.
window 객체의 모든 속성과 메서드는 전역 네임스페이스에 존재하므로 window 생략 가능.</p>
</blockquote>
<h3 id="주요-속성">주요 속성</h3>
<ol>
<li><p>window.location.href
현재 페이지의 전체 URL을 반환하거나 설정합니다.</p>
<pre><code class="language-javascript">console.log(window.location.href); // &quot;https://www.example.com/path/page.html&quot;
window.location.href = &quot;https://www.example.com/newpage.html&quot;; // 페이지 이동</code></pre>
</li>
<li><p>window.location.protocol
URL의 프로토콜 부분을 반환합니다. (예: “http:”, “https:”)</p>
<pre><code class="language-javascript">console.log(window.location.protocol); // &quot;https:&quot;</code></pre>
</li>
<li><p>window.location.host
호스트 이름과 포트 번호를 반환합니다. (예: “<a href="http://www.example.com:80%E2%80%9D">www.example.com:80”</a>)</p>
<pre><code class="language-javascript">console.log(window.location.host); // &quot;www.example.com&quot;</code></pre>
<blockquote>
<p>✅ 표준 포트 번호 생략
<strong>HTTP (포트 80)</strong> &gt; <strong>HTTPS (포트 443)</strong>
표준 포트를 사용할 경우 window.location.host는 포트 번호를 포함하지 않고 호스트 이름만 반환.</p>
</blockquote>
</li>
<li><p>window.location.hostname
호스트 이름을 반환합니다. (예: “<a href="http://www.example.com%E2%80%9D">www.example.com”</a>)</p>
<pre><code class="language-javascript">console.log(window.location.hostname); // &quot;www.example.com&quot;</code></pre>
</li>
<li><p>window.location.port
포트 번호를 반환합니다. (예: “80”, “443”)</p>
<pre><code class="language-javascript">console.log(window.location.port); // &quot;443&quot;</code></pre>
</li>
<li><p>window.location.pathname
URL의 경로 부분을 반환합니다. (예: “/path/page.html”)</p>
<pre><code class="language-javascript">console.log(window.location.pathname); // &quot;/path/page.html&quot;</code></pre>
</li>
<li><p>window.location.search
URL의 쿼리 문자열 부분을 반환합니다. (예: “?name=value”)</p>
<pre><code class="language-javascript">console.log(window.location.search); // &quot;?name=value&quot;</code></pre>
</li>
<li><p>window.location.hash
URL의 해시(#) 부분을 반환합니다. (예: “#section1”)</p>
<pre><code class="language-javascript">console.log(window.location.hash); // &quot;#section1&quot;</code></pre>
</li>
<li><p>window.location.origin
현재 URL의 원점을 반환합니다. (예: “<a href="https://www.example.com%E2%80%9D">https://www.example.com”</a>)</p>
<pre><code class="language-javascript">console.log(window.location.origin); // &quot;https://www.example.com&quot;</code></pre>
</li>
</ol>
<h3 id="⭐️-주요-메서드---원하는-url로-조작하기">⭐️ 주요 메서드 - 원하는 URL로 조작하기</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/location">참고</a></p>
<ol>
<li><p>window.location.assign(url)
지정된 URL로 이동합니다.</p>
<pre><code class="language-javascript">window.location.assign(&quot;https://www.example.com&quot;);</code></pre>
</li>
<li><p>window.location.replace(url)
<strong>지정된 URL로 이동하며, 현재 페이지를 브라우저 히스토리에서 제거</strong>합니다. 즉, 뒤로 가기 버튼을 눌렀을 때 replace 메서드로 이동하기 전 페이지로 돌아갈 수 없습니다.</p>
<pre><code class="language-javascript">window.location.replace(&quot;https://www.example.com&quot;);</code></pre>
</li>
<li><p>window.location.reload(forceReload)
현재 문서를 다시 로드합니다. forceReload가 true이면 서버에서 새로고침을 강제하고, false이면 캐시된 버전을 사용할 수 있습니다.</p>
<pre><code class="language-javascript">window.location.reload(); // 기본: 캐시된 버전을 사용할 수 있음
window.location.reload(true); // 서버에서 새로고침을 강제</code></pre>
</li>
</ol>
<h3 id="2-document-api">2. document API</h3>
<p>document 객체는 웹 페이지의 콘텐츠를 조작할 수 있는 API를 제공합니다. 이는 DOM(Document Object Model)을 통해 HTML 문서 구조를 표현하며, JavaScript로 웹 페이지를 동적으로 변경할 수 있게 해줍니다. document 객체를 사용하여 웹 페이지의 요소를 탐색하고, 수정하고, 이벤트를 추가할 수 있습니다.</p>
<p><strong>URL 관련</strong></p>
<ol>
<li><p>document.location
window.location 객체와 동일하게 현재 문서의 URL을 반환하거나 설정합니다.</p>
<pre><code class="language-javascript">console.log(document.location.href); // 현재 URL을 출력
document.location.href = &quot;https://www.example.com&quot;; // 새 URL로 이동</code></pre>
</li>
<li><p>document.referrer
현재 문서를 참조한 문서의 URL을 반환합니다.</p>
<pre><code class="language-javascript">console.log(document.referrer); // 사용자가 이 페이지로 오기 전의 페이지 URL을 출력</code></pre>
</li>
</ol>
<h2 id="url-uri-urn-개념-및-url의-각-부분">URL, URI, URN 개념 및 URL의 각 부분</h2>
<blockquote>
<p>✏️ <strong>URL, URI, URN 개념 정리</strong></p>
<ul>
<li>URI (Uniform Resource Identifier): 웹 상의 자원을 식별하는 문자열입니다. URI는 URL과 URN을 포함하는 상위 개념입니다. URI는 특정 리소스에 대한 식별 정보를 제공합니다.</li>
<li>URL (Uniform Resource Locator): 자원의 위치를 나타내는 URI의 한 형태로, 프로토콜, 호스트, 경로 등 자원의 접근 방법을 포함합니다. 예: <a href="https://www.example.com/path/to/resource">https://www.example.com/path/to/resource</a>.</li>
<li>URN (Uniform Resource Name): 자원의 이름을 나타내는 URI의 한 형태로, 자원의 위치와 관계없이 고유하게 식별합니다. 예: urn:isbn:0451450523.</li>
</ul>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/f0aa71c1-db81-4c8d-a056-115e9f146442/image.png" alt=""></p>
<p><a href="https://danielmiessler.com/p/difference-between-uri-url/">참고 - difference-between-uri-url</a>
<a href="https://velog.io/@hi-rachel/HTTP-%EC%9B%B9-%EA%B8%B0%EB%B3%B8-%EC%A7%80%EC%8B%9D-1.-%EC%9D%B8%ED%84%B0%EB%84%B7-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-2.-URI%EC%99%80-%EC%9B%B9-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%9A%94%EC%B2%AD-%ED%9D%90%EB%A6%84">참고 - URI</a></p>
<h3 id="url의-각-부분에-대한-이해">URL의 각 부분에 대한 이해</h3>
<p>URL(Uniform Resource Locator)은 웹 상의 자원을 식별하는 문자열입니다. URL은 여러 부분으로 구성되며, 각 부분은 특정한 역할을 합니다.</p>
<ol>
<li><p>프로토콜 (Scheme)
자원에 접근하기 위해 사용하는 프로토콜을 지정합니다.
예: http, https, ftp
예시: https://</p>
</li>
<li><p>호스트 (Host)
자원이 위치한 서버의 도메인 이름 또는 IP 주소를 지정합니다.
예: <a href="http://www.example.com">www.example.com</a>
예시: <a href="https://www.example.com">https://www.example.com</a></p>
</li>
<li><p>포트 (Port)
서버의 특정 네트워크 포트를 지정합니다. 기본 포트를 사용하는 경우 생략될 수 있습니다.
예: :80, :443
예시: <a href="https://www.example.com:443">https://www.example.com:443</a></p>
</li>
<li><p>경로 (Path)
서버 상의 특정 자원에 대한 경로를 지정합니다.
예: /path/to/resource
예시: <a href="https://www.example.com/path/to/resource">https://www.example.com/path/to/resource</a></p>
</li>
<li><p>쿼리 문자열 (Query String)
자원에 대한 추가적인 매개변수를 지정합니다. ?로 시작하며 &amp;로 구분됩니다.
예: ?key1=value1&amp;key2=value2
예시: <a href="https://www.example.com/path/to/resource?key1=value1&amp;key2=value2">https://www.example.com/path/to/resource?key1=value1&amp;key2=value2</a></p>
</li>
<li><p>프래그먼트 (Fragment)
문서 내의 특정 부분을 지정합니다. #로 시작합니다.
예: #section1
예시: <a href="https://www.example.com/path/to/resource?key1=value1&amp;key2=value2#section1">https://www.example.com/path/to/resource?key1=value1&amp;key2=value2#section1</a></p>
</li>
</ol>
<blockquote>
<p>전체 URL 예시: <a href="https://www.example.com:443/path/to/resource?key1=value1&amp;key2=value2#section1">https://www.example.com:443/path/to/resource?key1=value1&amp;key2=value2#section1</a></p>
<p>• 프로토콜: https
• 호스트: <a href="http://www.example.com">www.example.com</a>
• 포트: 443
• 경로: /path/to/resource
• 쿼리 문자열: ?key1=value1&amp;key2=value2
• 프래그먼트: #section1</p>
</blockquote>
<p><strong>정리 - 실제 예시</strong></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;URL Parts Example&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;button onclick=&quot;showURLParts()&quot;&gt;Show URL Parts&lt;/button&gt;

    &lt;script&gt;
      function showURLParts() {
        console.log(&quot;전체 URL: &quot; + location.href);
        console.log(&quot;프로토콜: &quot; + location.protocol);
        console.log(&quot;호스트: &quot; + location.host);
        console.log(&quot;호스트 이름: &quot; + location.hostname);
        console.log(&quot;포트: &quot; + location.port);
        console.log(&quot;경로: &quot; + location.pathname);
        console.log(&quot;쿼리 문자열: &quot; + location.search);
        console.log(&quot;프래그먼트: &quot; + location.hash);
      }
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<h2 id="history-api-실제-사용-예시">History API 실제 사용 예시</h2>
<h3 id="react">React</h3>
<p>React에서는 React Router를 사용하여 History API를 쉽게 사용할 수 있습니다. React Router는 SPA에서 클라이언트 측 라우팅을 처리하는 데 사용됩니다.</p>
<pre><code class="language-javascript">import React from &quot;react&quot;;
import { BrowserRouter as Router, Route, Switch, Link } from &quot;react-router-dom&quot;;

function Home() {
  return &lt;h1&gt;Home&lt;/h1&gt;;
}

function About() {
  return &lt;h1&gt;About&lt;/h1&gt;;
}

function Contact() {
  return &lt;h1&gt;Contact&lt;/h1&gt;;
}

function App() {
  return (
    &lt;Router&gt;
      &lt;nav&gt;
        &lt;Link to=&quot;/&quot;&gt;Home&lt;/Link&gt;
        &lt;Link to=&quot;/about&quot;&gt;About&lt;/Link&gt;
        &lt;Link to=&quot;/contact&quot;&gt;Contact&lt;/Link&gt;
      &lt;/nav&gt;
      &lt;Switch&gt;
        &lt;Route exact path=&quot;/&quot; component={Home} /&gt;
        &lt;Route path=&quot;/about&quot; component={About} /&gt;
        &lt;Route path=&quot;/contact&quot; component={Contact} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}

export default App;</code></pre>
<p><a href="https://reactrouter.com/en/main/upgrading/v5#remove-redirects-inside-switch">참고 - React Router 공식 문서</a></p>
<h3 id="nextjs">Next.js</h3>
<p>Next.js는 서버 사이드 렌더링(SSR)을 지원하는 React 프레임워크입니다. Next.js에서는 기본적으로 페이지 간 이동이 서버 측에서 처리되지만, 클라이언트 측 네비게이션을 위해 next/router, next/navigation을 사용할 수 있습니다.</p>
<h3 id="page-router">Page Router</h3>
<p>next/router를 사용합니다.</p>
<pre><code class="language-javascript">import { useRouter } from &quot;next/router&quot;;

function Home() {
  const router = useRouter();

  const navigateTo = (url) =&gt; {
    router.push(url);
  };

  return (
    &lt;div&gt;
      &lt;h1&gt;Home&lt;/h1&gt;
      &lt;button onClick={() =&gt; navigateTo(&quot;/about&quot;)}&gt;Go to About&lt;/button&gt;
      &lt;button onClick={() =&gt; navigateTo(&quot;/contact&quot;)}&gt;Go to Contact&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default Home;</code></pre>
<p><a href="https://nextjs.org/docs/pages/api-reference/functions/use-router">참고 - Next.js 공식 문서 Page Router/useRouter</a></p>
<h3 id="app-router">App Router</h3>
<p>next/navigation을 사용합니다.</p>
<pre><code class="language-javascript">&quot;use client&quot;;

import { useRouter } from &quot;next/navigation&quot;;

export default function Page() {
  const router = useRouter();

  return (
    &lt;button type=&quot;button&quot; onClick={() =&gt; router.push(&quot;/dashboard&quot;)}&gt;
      Dashboard
    &lt;/button&gt;
  );
}</code></pre>
<p><a href="https://nextjs.org/docs/app/api-reference/functions/use-router">참고 - Next.js 공식 문서 App Router/useRouter</a></p>
<hr>
<blockquote>
<p>추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프론트엔드 면접 준비] Browser 질문 목록 (feat.  HTTP, TCP/UDP)]]></title>
            <link>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-Browser-feat.-HTTP-TCPUDP</link>
            <guid>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-Browser-feat.-HTTP-TCPUDP</guid>
            <pubDate>Thu, 08 Aug 2024 11:00:25 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hi-rachel/post/43502b4b-3c22-4f60-9956-0b53308e25d9/image.png" alt=""></p>
<blockquote>
<p>실제 면접에서 받은 질문들 앞에는 ⭐️ 별을 붙였습니다.</p>
</blockquote>
<h2 id="브라우저-렌더링-과정-설명해주세요">브라우저 렌더링 과정 설명해주세요.</h2>
<p>브라우저가 화면에 나타내는 요소를 렌더링할 때, 웹킷이나 게코 등과 같은 각 브라우저 렌더링 엔진을 사용합니다. 렌더링 엔진이 HTML, CSS, JS로 렌더링시 CRP(Critical Rendering Path)라는 프로세스를 사용하며 다음 단계로 이루어집니다.</p>
<p>첫 번째로, <strong>HTML를 파싱 후, DOM 트리를 구축</strong>합니다.
두 번째로, <strong>CSS를 파싱 후, CSSOM 트리를 구축</strong>합니다.
세 번째로, <strong>JS를 실행</strong>합니다 (HTML 중간에 스크립트가 있다면 해당 스크립트의 실행이 완료될때까지 HTML 파싱이 중단됩니다. 이를 피하고 싶다면 제거하거나 async, defer 속성을 이용할 수 있습니다)
네 번째로, <strong>DOM과 CSSOM를 조합하여 렌더트리를 구축</strong>합니다.
(이때, display: none 속성과 같이 화면에 보이지도 않고 공간도 차지하지 않는 것은 렌더 트리로 구축되지 않음)
다음으로, <strong>뷰포트를 기반으로 렌더트리의 각 노드가 가지는 정확한 위치와 크기를 계산</strong>합니다. (<strong>Layout</strong>)</p>
<p>마지막으로, <strong>계산한 위치/크기를 기반으로 화면에 그립니다</strong>. (<strong>Paint</strong> 단계)</p>
<blockquote>
<p>✏️ <strong>용어 정리</strong>
CRP : HTML, CSS, JS를 화면에 픽셀로 변화시키는 일련의 단계</p>
<p>파싱: 하나의 프로그램을 런타임 환경이 실제로 실행할 수 있는 내부 포맷으로 분석하고 변환하는 것. 문서의 내용을 토큰으로 분석하고, 문법적 의미와 구조를 반영한 parse tree를 생성한다.</p>
<p>뷰포트(viewport): 웹 페이지를 볼 때 보이는 영역</p>
</blockquote>
<h2 id="reflow-repaint-되는-시점">Reflow, Repaint 되는 시점</h2>
<p>Layout = Reflow: 생성된 DOM 노드의 <strong>레이아웃 수치(너비, 높이, 위치 등) 변</strong>경 시 영향 받은 모든 노드의 (자신, 자식, 부모, 조상(결국 모든 노드)) 수치를 다시 계산하여(Recalculate), 렌더 트리를 재생성하는 과정</p>
<ul>
<li>DOM 요소 추가, 제거 또는 변경</li>
<li>CSS 스타일 추가, 제거, 변경</li>
<li>CSS 클래스 추가</li>
<li>CSS 애니메이션, 트랜지션, 애니메이션의 모든 프레임에서 리플로우 발생</li>
<li>offsetWidth 와 offsetHeight 의 사용. offsetWidth 와 offsetHeight 속성을 읽으면, 초기 리플로우가 트리거되어 수치가 계산</li>
<li>유저 인터랙션으로 인한 hover, 필드의 텍스트 입력, 창 크기 조절, 글꼴 크기 변경, 스타일시트 또는 글꼴 전환 등</li>
</ul>
<p>Repaint: Reflow 과정이 끝난 후 재 생성된 렌더 트리를 다시 그리는 과정</p>
<ul>
<li>가시성이 변경되는 순간(opacity, background, visibility, outline)</li>
<li>리플로우가 실행된 순간 뒤에 실행</li>
</ul>
<blockquote>
<p>✏️ <strong>용어 정리</strong>
offsetWidth: 요소의 너비를 반환. 보더(border), 수직 패딩(vertical padding), 수직 스크롤바(만약 존재한다면), 수직 마진(vertical margin)을 포함
offsetHeight: 요소의 높이를 반환. 보더(border), 수평 패딩(horizontal padding), 수평 스크롤바(만약 존재한다면), 수평 마진(horizontal margin)을 포함 (가시 영역 포함)
렌더링된 요소의 크기를 기준으로 계산. 읽기 전용 속성.</p>
</blockquote>
<h3 id="reflow-repaint-모두-발생하지-않는-속성">Reflow, Repaint 모두 발생하지 않는 속성?</h3>
<p>cursor, orphans, perspective는 Reflow, Repaint가 발생하지 않습니다.</p>
<p>transform, opacity는 Reflow를 발생시키지 않고 Repaint만 발생시킵니다.</p>
<blockquote>
<p>✏️ <strong>용어 정리</strong>
orphans: 페이지나 컨테이너의 맨 아래에 있는 텍스트 블록의 최소 줄 수를 설정
perspective: 3D 공간에서 요소를 바라보는 관점을 설정. 요소 자체가 아닌 요소의 자식 요소에 적용되는 3D 변환에 영향을 준다.
transform: 요소에 2D 또는 3D 변환을 적용. 변환에는 회전, 크기 조절, 기울이기, 이동 등이 포함.</p>
</blockquote>
<h2 id="google에-httpswwwgooglecom을-검색하면-일어나는-일">google에 <a href="https://www.google.com%EC%9D%84">https://www.google.com을</a> 검색하면 일어나는 일</h2>
<p>사용자가 웹 브라우저를 통해 <a href="https://www.google.com%EC%9D%84">https://www.google.com을</a> 입력하면 IP 주소값을 찾기 위해 캐싱된 DNS 기록이 있는지 확인합니다. 캐시된 데이터가 없다면 URL 주소 중 도메인 네임(google.com) 부분을 DNS(도메인 이름 시스템) 서버에서 재귀적으로 검색합니다.
DNS 서버에서 해당 도메인 네임에 해당하는 IP 주소(예: 192.0.2.44)를 찾으면 사용자가 입력한 URL 정보와 함께 전달합니다.
브라우저는 HTTP 프로토콜을 사용하여 요청 메시지를 생성하고 HTTP 요청 메시지는 TCP/IP 프로토콜을 사용하여 서버로 전송됩니다.
서버는 response 메시지를 생성하여 다시 브라우저에게 데이터를 전송합니다.
브라우저는 response를 받아 파싱하여 화면에 렌더링합니다.</p>
<blockquote>
<p>✏️ <strong>용어 정리</strong>
DNS: 도메인 이름 시스템(DNS)은 사람이 읽을 수 있는 도메인 이름(예: <a href="http://www.amazon.com">www.amazon.com</a> )을 머신이 읽을 수 있는 IP 주소(예: 192.0.2.44)로 변환합니다. 모든 통신에는 주소가 필요합니다. 출발지와 도착지의 주소를 알아야 통신을 할 수 있습니다. 우리는 이 주소를 IP라고 부릅니다. IP 주소로 변환하는 과정에 개입하는 것이 DNS 입니다.</p>
<p>URL: URL(Uniform Resource Locator)은 통합 자원 지시자로 인터넷의 리소스를 가리키는 표준 명칭으로 서버의 자원을 요청할 때 사용됩니다. URL을 통해 인터넷 상의 모든 리소스를 요청할 수 있으며, HTTP, FTP 등의 자원 요청도 가능합니다.</p>
<p>프로토콜: 프로토콜은 통신하기 위한 약속들을 기술적으로 잘 정의해 둔 것입니다. 데이터를 송수신하는 순서와 내용을 결정합니다. HTTP, TCP/IP, UDP 모두 프로토콜입니다.</p>
<p>프로토콜 스위트: 네트워크 통신에서 여러개 프로토콜이 모여 하나의 집합을 이루는 것을 의미함</p>
<p>IP: IP (Internet Protocol)은 비신뢰성, 비연결지향 데이터그램 프로토콜로 패킷을 받아서 주소를 해석하고 경로를 결정하여 다음 호스트로 전송하는 역할을 합니다.</p>
<p>response: HTTP 메시지는 서버와 클라이언트 간에 데이터가 교환되는 방식입니다. 메시지 타입은 두 가지가 있습니다. 요청(request)은 클라이언트가 서버로 전달해서 서버의 액션이 일어나게끔 하는 메시지고, 응답(response)은 요청에 대한 서버의 답변입니다.</p>
</blockquote>
<h3 id="tcpip란">TCP/IP란?</h3>
<p>TCP/IP는 프로토콜 스위트로, TCP(Transmission Control Protocol)와 IP(Internet Protocol)를 합쳐서 부르는 말입니다. 송신자가 수신자에게 IP 주소를 사용해서 데이터를 전달할 때, <strong>IP는 데이터의 전달 경로를 결정</strong>하고, <strong>TCP는 데이터가 제대로 전달되었는지 확인하는 역할</strong>을 합니다.</p>
<h3 id="tcp란">TCP란?</h3>
<p><strong>TCP (전송 제어 프로토콜)은 두 개의 호스트를 연결하고 데이터 스트림을 교환하게 해주는 중요한 네트워크 프로토콜</strong>입니다. TCP는 데이터 전송을 제어하고 데이터를 어떻게 보낼 지, 어떻게 맞출 지 정합니다. 또한 데이터와 패킷이 보내진 순서대로 전달하는 것을 보장해줍니다.신뢰성과 연결성을 책임지기 위한 프로토콜이 TCP입니다. 호스트와 호스트간의 데이터 전송은 IP(인터넷 계층 프로토콜)에 의지하면서 동시에 신뢰성 있는 전송에 대해서는 TCP가 책임지는 구조입니다.</p>
<p>TCP 연결시 3-wayhandshake로, 종료시 4-wayhandshake 사용으로 신뢰성과 연결성을 보장합니다.</p>
<h3 id="tcp와-udp의-차이는">TCP와 UDP의 차이는?</h3>
<p>TCP와 UDP 두가지는 전송계층입니다. TCP는 연결형 프로토콜로 데이터 신뢰성과 순서를 보장하는 반면에,
UDP는 비연결형 프로토콜로 데이터 신뢰성을 체크하지 않기 때문에, 비교적 TCP보다 전송속도가 빠르다는 장점이 있습니다.</p>
<h3 id="tcp와-udp-각각의-적절한-사용처">TCP와 UDP 각각의 적절한 사용처?</h3>
<p>채팅 서버-클라이언트간에는 빠른 데이터 송신보다도 신뢰성 있는 데이터 송수신이 중요하기 때문에 TCP 프로토콜을 사용하는 것이 좋습니다.</p>
<p>실시간 스트리밍 서비스에서는 빠른 속도가 필요하고 신뢰성이 크게 중요하지 않기 때문에 UDP 프로토콜을 사용하는 것이 좋습니다.</p>
<h3 id="dns에서-tcp와-udp중-뭘-사용하나요">DNS에서 TCP와 UDP중 뭘 사용하나요?</h3>
<p>DNS는 UDP를 사용합니다. UDP를 사용하는 이유는 작은 쿼리와 응답이 빠른속도로 처리되어야 하기 때문입니다.</p>
<h2 id="http란">HTTP란?</h2>
<p><strong>HTTP(HyperText Transfer Protocol)은 TCP 기반의 클라이언트와 서버 사이에 이루어지는 요청/응답 프로토콜</strong>입니다. HTTP는 Text Protocol로 사람이 쉽게 읽고 쓸 수 있습니다. 프로토콜 설계상 클라이언트가 요청을 보내면 반드시 응답을 받아야 합니다. 응답을 받아야 다음 request를 보낼 수 있습니다.</p>
<h3 id="http와-https-차이점은">HTTP와 HTTPS 차이점은?</h3>
<p>HTTP와 HTTPS는 보안적인 차이와 SEO차이가 있습니다.</p>
<ol>
<li><p>보안적 차이
만일 HTTP의 클라이언트와 서버간에 데이터를 교환할때 원본 데이터를 주고 받기 때문에 해커에 의해서 가로채기 쉽습니다. 하지만, HTTPS는 네트워크로 전송되는 데이터를 암호화합니다. 때문에 해커가 데이터를 가로채도 암호화가 되어 있어서 어떤 내용인지 알기 어렵습니다.</p>
</li>
<li><p>SEO 차이
일반적으로 검색엔진은 HTTPS의 웹사이트의 신뢰성을 더 높게 산정합니다.</p>
</li>
</ol>
<p>HTTPS는 HTTP 프로토콜로 송수신하는 일반 텍스트를 SSL 또는 TLS 프로토콜을 통해 암호화합니다.</p>
<h2 id="rest란">REST란?</h2>
<p>자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것입니다. HTTP URI를 통해 자원을 명시하고 HTTP 메서드(POST, GET, PUT, DELETE)를 통해 해당 자원에 대한 CRUD를 적용하는 것을 말합니다. 즉, 자원 기반의 구조 설계의 중심에 자원이 있고, HTTP 메서드를 통해 이를 처리합니다.</p>
<h3 id="api란">API란?</h3>
<p>응용프로그램에서 사용할 수 있도록 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스입니다. 쉽게 말해 프로그램끼리 통신할 수 있도록 하는 중재자입니다.</p>
<h3 id="rest-api란">REST API란?</h3>
<p>REST 원칙을 적용하여 서비스 API를 설계한 것을 말합니다.</p>
<h2 id="cors란">CORS란?</h2>
<p>CORS(Cross-Origin Resource Sharing)란 웹 브라우저에서 외부 도메인 서버와 통신하기 위한 방식을 표준화한 스펙입니다. 서버와 클라이언트가 정해진 헤더를 통해 서로 요청이나 응답에 반응할지 결정하는 방식으로 교차 출처 자원 공유(cross-origin resource sharing)라는 이름으로 포준화 되었습니다.</p>
<h3 id="cors가-왜-필요한가요">CORS가 왜 필요한가요?</h3>
<p>웹 브라우저는 보안 상의 이유로 스크립트가 동일 출처 정책(Same-Origin Policy)에 따라 자신의 출처(도메인, 프로토콜, 포트)와 다른 출처의 리소스에 접근하는 것을 제한합니다. CORS는 이러한 제한을 완화하기 위한 표준 방법입니다. CORS를 사용해 보안 정책을 유지하면서 필요한 자원 접근을 허용하는 중요한 역할을 합니다.</p>
<h3 id="cors에-대처하는-방법과-우회하는-방법">CORS에 대처하는 방법과 우회하는 방법</h3>
<ol>
<li>개발자가 테스트 혹은 개발 환경에서 웹 브라우저 실행 옵션이나 플러그인을 통해 동일 출처 회피하는 방법이 있습니다.</li>
<li>CORS 구현이 안되어 있는 서버로 ajax 요청을 해야하지만 서버쪽 컨트롤이 불가능할 경우: jsonp 방식으로 요청하는 방법이 있습니다.</li>
<li>서버 설정 수정: ajax 요청을 해야 하는 다른 도메인의 서버를 클라이언트와 같이 개발하거나 서버 개발쪽 수정 요청이 가능한 경우: 서버에서 CORS 요청이 허용되도록 구현합니다.</li>
<li>프록시 서버 사용: 클라이언트와 서버 사이에 프록시 서버를 두어 CORS 문제를 해결할 수 있습니다. <strong>프록시 서버는 클라이언트의 요청을 받아 서버로 전달하고, 서버의 응답을 다시 클라이언트로 전달</strong>합니다.</li>
</ol>
<pre><code>Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS
Access-Control-Max_Age: 3600
Access-Control-Allow-Headers: Origin,Accept,X-requested-With,Content-Type,Access-Control-Request-Method,Access-
Control-Request-Headers,Authorization</code></pre><ul>
<li>Access-Control-Allow-Origin: 요청을 허용하는 출처, &#39;*&#39; 이면 모든 곳에 공개되어 있음을 의미합니다.</li>
<li>Access-Control-Allow_Methods: 요청을 허용하는 메서드, 기본값은 GET,POST라고 보면 됩니다. 이 헤더가 없으면 GET과 POST요청만 가능합니다. 만약 이 헤더가 지정되어 있으면, 클라이언트는 헤더값에 해당하는 메서드일 경우에만 실제 요청을 시도하게 됩니다.</li>
<li>Access-Control-Max-Age: 클라이언트에서 preflight의 요청 결과를 저장할 기간을 지정. 클라이언트에서 preflight 요청의 결과를 저장하고 있을 시간입니다. 해당 시간 동안은 preflight 요청을 다시 하지 않게 됩니다.</li>
<li>Access-Control-Allow_Headers : 요청을 허용하는 헤더</li>
</ul>
<h3 id="웹-브라우저-실행-옵션-플러그인">웹 브라우저 실행 옵션, 플러그인</h3>
<p>1-1. 웹 브라우저 실행 옵션: 웹브라우저 실행 시 외부 요청을 허용하는 옵션을 사용, same origin policy는 결국 클라이언트인 웹 브라우저가 요청을 해도 되는지 판단해서 결정하는 것으로 이 과정만 무시한다면 어디든 요청하지 못할 이유는 없습니다. 크롬같은 웹 브라우저들은 실행 시 커맨드 라인 옵션을 통해서 외부 도메인 요청가능 여부를 확인하는 동작을 무시하게 할 수 있습니다.</p>
<p>1-2. 플러그인: 외부 요청을 가능하게 해주는 플러그인 설치, 서버에서 받은 요청의 응답에 특정 header(Access-Control-Allow-Origin: *)만 추가하면 웹 브라우저가 요청이 가능한 사이트로 인식하여 요청이 가능합니다. 크롬의 경우 웹스토어에 요청을 가로채서 응답에 위 header를 추가해주는 플러그인이 있습니다. 웹스토어에서 cors로 검색하면 확장 프로그램 검색 결과에서 찾을 수 있습니다.</p>
<h3 id="jsonp방식이란">jsonp방식이란?</h3>
<p>웹 브라우저에서 css나 js 같은 리소스 파일들은 동일 출처 정책에 영향을 받지 않고 로딩이 가능합니다. 이런 점을 응용해서 <strong>외부 서버에서 읽어온 js 파일을 json으로 바꿔주는</strong> 일종의 편법적인 방법입니다. 단점은 리소스 파일을 GET 메서드로 읽어오기 때문에 <strong>GET 방식의 API만 요청이 가능</strong>합니다.</p>
<h2 id="브라우저-저장소의-차이점-로컬-스토리지와-세션-스토리지-쿠키에-대해서-설명해주세요">(브라우저 저장소의 차이점) 로컬 스토리지와 세션 스토리지, 쿠키에 대해서 설명해주세요.</h2>
<p><strong>로컬 스토리지</strong>는 HTML5에서 제공하는 <strong>클라이언트측 데이터 저장 메커니즘</strong>입니다. 데이터는 <strong>브라우저의 로컬에 영구적으로 저장</strong>됩니다. 사용자가 페이지를 닫고 다시 열어도 데이터는 보존되지만 다른 브라우저에서 열면 유지되지 않습니다.
JS를 이용해 데이터를 설정하고, 다시 읽고 삭제 가능합니다.</p>
<p><strong>세션 스토리지</strong>도 HTML5에서 제공하는 <strong>클라이언트측 데이터 저장 메커니즘</strong>입니다. 데이터는 <strong>브라우저 세션 동안만 유지</strong>됩니다. 즉 브라우저를 닫으면 데이터가 삭제됩니다.
<strong>JS</strong>를 사용하여 데이터를 설정하고 읽고 삭제 가능합니다.
주로 임시적인 데이터나 세션 동안 필요한 정보를 저장하는데 사용됩니다.</p>
<p><strong>쿠키는 클라이언트와 서버 사이에 상태 정보를 유지하는데 사용되는 작은 데이터 조각</strong>입니다. <strong>브라우저가 서버로부터 쿠키를 받아서 저장하고, 나중에 같은 서버에 요청할 때마다 쿠키를 함께 전송하는 방식</strong>입니다. 만료 날짜를 설정하여 지속성을 제어할 수 있습니다.
주로 사용자 로그인 상태 유지, 사용자 환경 설정, 사용자 추적 등 다양한 용도로 사용됩니다.</p>
<h3 id="세션이란">세션이란?</h3>
<p>웹 개발에서 사용자가 웹 서버에 접속하여 브라우저를 닫을 때까지 유지되는 상태</p>
<h3 id="세션-하이재킹이란">세션 하이재킹이란?</h3>
<p>사용자의 세션을 도용하여 해당 사용자로 위장하여 시스템에 접근하는 공격 기법입니다.</p>
<h3 id="쿠키랑-세션의-차이">쿠키랑 세션의 차이?</h3>
<p>쿠키는 클라이언트에 저장되는 작은 데이터 파일이고, 세션은 서버 측에서 관리되는 사용자 상태의 일부입니다. 보안적으로 더 안전한 정보 관리가 필요한 경우, 세션을 사용하는 것이 일반적으로 권장됩니다.</p>
<h3 id="쿠키의-종류에-대해서-설명해주세요">쿠키의 종류에 대해서 설명해주세요.</h3>
<ol>
<li><p><strong>세션 쿠키 (Session Cookies)</strong>:
보통 만료시간(Expire date) 설정하고 <strong>메모리</strong>에만 저장되며 브라우저 종료시 쿠키를 삭제한다.</p>
</li>
<li><p><strong>지속 쿠키 (Persistent Cookies)</strong>:
장기간 유지되는 쿠키 파일로 저장되어 브라우저 종료와 관계없이 사용한다.</p>
</li>
<li><p><strong>보안 쿠키 (Secure Cookies)</strong>:
<strong>HTTPS</strong> 에서만 사용되도록 설정된 쿠키. 쿠키 정보가 암호화되어 전송된다.</p>
</li>
</ol>
<ul>
<li><p>HttpOnly 설정:
HttpOnly 쿠키는 클라이언트 측 JavaScript에서 접근할 수 없도록 제한된 쿠키.
XSS(Cross-Site Scripting) 공격을 예방하기 위해 사용.</p>
</li>
<li><p>SameSite 설정:
SameSite 쿠키는 Cross-Site Request Forgery (CSRF) 공격을 방지하기 위한 쿠키 설정.
SameSite=Strict, SameSite=Lax</p>
</li>
</ul>
<h2 id="⭐️-csrf-xss-공격에-대해-말해보세요">⭐️ CSRF, XSS 공격에 대해 말해보세요.</h2>
<p><strong>CSRF(Cross-Site Requset Forgery) 크로스 사이트 위조 요청 공격은 사용자가 인증된 세션을 통해 악의적인 요청을 수행하게 만드는 공격</strong>입니다. <strong>CSRF 공격은 사용자가 신뢰할 수 있는 웹 사이트에 로그인한 상태에서 다른 웹사이트를 방문했을 때 발생</strong>합니다. 데이터 도용 및 손실, 금전적 손실, 계정 탈취 및 설정 변경 등의 위험이 있습니다.</p>
<p><strong>XSS(Cross-Site Scripting)는 공격자가 악성 스크립트를 신뢰할 수 있는 웹사이트에 삽입하여 다른 사용자 브라우저에서 실행되도록 하는 공격</strong> 기법입니다. 개인 정보 탈취, 피싱 공격, 웹사이트 변조, 악성 코드 배포 등의 위험이 있습니다.</p>
<h3 id="쿠키-메서드와-프로퍼티에-대해-설명해주세요">쿠키 메서드와 프로퍼티에 대해 설명해주세요.</h3>
<p>쿠키 메서드로는 <strong>document.cookie</strong>로 현재 페이지에 설정된 모든 쿠키를 가져오거나 설정할 수 있고 encodeURIComponent()는 쿠키에 저장할 값이나 이름이 안전하게 인코딩할 때 사용할때 사용합니다. 반대로 디코딩할 때는 decodeURIComponent() 함수를 이용합니다.</p>
<p>쿠키 프로퍼티로는 쿠키의 이름과 값이 반드시 설정되어야 하기 때문에 name=value가 있고, expires=date로 쿠키의 만료 날짜를 설정해줄 수 있습니다. 또 path로 쿠키의 유효한 경로, domain으로 쿠키가 유효한 도메인을 설정할 수 있습니다.
보안 관련해서 HttpOnly 프로퍼티를 설정해 클라이언트측 JS에서 쿠키에 접근할 수 없도록 해 XSS 공격을 방지할 수 있고 secure 설정으로 쿠키가 HTTPS 연결을 통해서만 전송될 수 있게 할 수 있습니다.</p>
<h3 id="각-공격을-방어할-수-있는-방법은">각 공격을 방어할 수 있는 방법은?</h3>
<p>CSRF 공격 방지 방법은 CSRF 토큰을 사용해 각 요청에 대한 고유한 <strong>CSRF 토큰</strong>을 생성하고, 서버는 이 토큰을 검증하여 요청이 신뢰할 수 있는 출처에서 왔는지 확인하는 방법이 있습니다. 또 서버는 요청의 <strong>Referer 헤더</strong>를 확인하여 <strong>요청이 올바른 출처에서 왔는지 검증하는 방법</strong>이 있습니다.
<strong>쿠키의 SameSite 속성을 Strict 또는 Lax로 설정</strong>하여 크로스 사이트 요청에서 쿠키가 전송되지 않도록 할 수도 있습니다.
또한 민감한 작업에 대해서는 <strong>재인증</strong>(비밀번호 입력 등)을 요구하여 실제 사용자 인증을 강화하고, CORS를 적절히 설정하여 신뢰할 수 있는 도메인만 서버 자원에 접근할 수 있도록 제한합니다.</p>
<p>XSS 공격은 다음과 같은 방법으로 예방할 수 있습니다. <strong>사용자 입력 값을 철저히 검증</strong>하고, 사용자 입력이 포함된 모든 출력을 HTML, JavaScript, CSS 등 해당 문맥에 맞게 <strong>적절히 인코딩</strong>합니다. 또 <strong>웹서버에 콘텐츠 보안 정책 CSP(Content Security Policy)를 설정하여 브라우저가 신뢰할 수 있는 소스에만 스크립트를 로드</strong>하도록 합니다.
<strong>쿠키에 HttpOnly 속성을 설정</strong>하여 클라이언트측 스크립트(JS)를 통해 접근할 수 없도록 합니다.</p>
<ul>
<li>https를 사용합니다.</li>
</ul>
<blockquote>
<p>✏️ <strong>용어 정리</strong>
인코딩: 데이터를 특정 형식으로 변환하는 과정. 보안을 강화하고 데이터를 안전하게 전달하기 위해 사용된다.
ex_ HTML 인코딩은 사용자가 입력한 &lt;, &gt;, &amp; 같은 문자를 &lt;, &gt;, &amp; 등으로 변환하여 브라우저가 이들을 HTML 태그나 엔티티가 아닌 텍스트로 해석하도록 만든다.</p>
</blockquote>
<h2 id="브라우저-상태코드">브라우저 상태코드</h2>
<p>2xx: 클라이언트 요청 성공적으로 처리</p>
<p>3xx: 요청을 완료하기 위해 유저 에이전트(주로 웹 브라우저, 클라이언트 프로그램)의 추가 조치 필요</p>
<p>4xx: 클라이언트 오류 - 클라이언트의 요청에 잘못된 문법 등으로 서버가 요청을 수행할 수 없음</p>
<p>5xx: 서버 오류</p>
<p><a href="https://velog.io/@hi-rachel/HTTP-%EC%9B%B9-%EA%B8%B0%EB%B3%B8-%EC%A7%80%EC%8B%9D-6.-HTTP-%EC%83%81%ED%83%9C%EC%BD%94%EB%93%9C">참고</a></p>
<h2 id="http-get-post-방식에-대해-설명해주세요">HTTP GET, POST 방식에 대해 설명해주세요.</h2>
<p>GET 방식은 일반적으로 서버에서 정보를 조회할 때, 요청에 필요한 데이터를 URL에 붙여서 전송합니다.
POST 방식은 서버에 정보를 입력 또는 추가할 때 사용합니다. 요청에 필요한 데이터를 HTTP request body 부분에 담아 전송합니다.</p>
<h2 id="put과-post의-차이점을-아시나요">PUT과 POST의 차이점을 아시나요?</h2>
<p><strong>PUT 메서드는 클라이언트가 서버의 특정 리소스에 데이터를 저장하거나 업데이트할 때 사용</strong>됩니다. <strong>동일한 요청을 여러 번 보내더라도 결과가 동일한 멱등성이 보장</strong>되는 특징이 있습니다. 즉, 동일한 데이터를 같은 URI에 요청을 여러번 보내도 결과는 항상 동일한 리소스가 저장됩니다. (전체 업데이트)</p>
<p><strong>POST 메서드는 서버의 리소스에 데이터를 제출하여 새로운 리소스를 생성하거나 서버에서 특정 작업을 수행할 때 사용</strong>됩니다. 여러 번 요청시 매번 다른 결과를 낼 수 있어 멱등성을 보장하지 않습니다. 예를 들어, 동일한 POST 요청을 여러 번 보내면 새로운 리소스가 그때마다 생성될 수 있습니다. → 리소스를 추가하거나 서버가 정의한 작업을 수행(전체 또는 부분 데이터 제출 가능)</p>
<p><strong>PUT은 특정 리소스를 정확히 지정하고 업데이트하거나 생성할 때</strong>, <strong>POST는 새로운 리소스를 생성하거나 서버에서 정의된 작업을 수행</strong>할 때 유용합니다.</p>
<hr>
<h2 id="📌-참고-자료">📌 참고 자료</h2>
<p><a href="https://github.com/Esoolgnah/Frontend-Interview-Questions?tab=readme-ov-file">깃허브 - 프론트엔드 면접질문 중요도별 정리</a></p>
<p><a href="https://www.youtube.com/watch?v=z1Jj7Xg-TkU">브라우저는 어떻게 화면을 렌더링할까?</a></p>
<p><a href="https://stupidsecurity.tistory.com/9">쿠키란?</a></p>
<p><a href="https://www.linkedin.com/pulse/what-critical-rendering-path-rohit-kumar/">What is a Critical Rendering Path?</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프론트엔드 면접 준비] JavaScript 질문 목록 (feat. TypeScript)]]></title>
            <link>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A7%88%EB%AC%B8-%EB%AA%A9%EB%A1%9D-feat.%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</link>
            <guid>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A7%88%EB%AC%B8-%EB%AA%A9%EB%A1%9D-feat.%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8</guid>
            <pubDate>Tue, 06 Aug 2024 04:04:13 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hi-rachel/post/34c9953b-ea0f-496a-bf9f-f126d6b89111/image.webp" alt=""></p>
<blockquote>
<p>실제 면접에서 받은 질문들 앞에는 ⭐️ 별을 붙였습니다.</p>
</blockquote>
<h1 id="javascript">JavaScript</h1>
<h2 id="자바스크립트는-어떤-언어일까요">자바스크립트는 어떤 언어일까요?</h2>
<p>자바스크립트는 웹 페이지의 동적인 동작을 구현하는데 주로 사용되는 인터프리터 언어입니다. (코드가 한 줄씩 순차적으로 실행) JS의 특징으로는 동적 타입을 사용하고 싱글 스레드이면서 논 블록킹 언어입니다.</p>
<h2 id="자바스크립트-데이터-타입">자바스크립트 데이터 타입</h2>
<p>자바스크립트 원시 타입은 number, string, boolean, null, undefined, symbol이 있습니다. 원시 타입은 값이 저장되는 위치가 메모리 상에 직접적으로 저장됩니다.</p>
<p>자바스크립트 참조 타입은 객체, 배열, 함수가 있습니다. 참조 타입은 값이 저장되는 위치가 메모리 상의 주소이며, 해당 주소를 통해 실제 값에 접근합니다.</p>
<h2 id="이벤트-루프란">이벤트 루프란?</h2>
<p><strong>이벤트 루프는 콜 스택을 모니터하고 태스크 큐에서 수행할 작업이 있는지 확인하는 싱글 스레드 루프</strong>입니다. 콜 스택이 비어 있고 태스크 큐에 콜백 함수가 있는 경우, 함수는 큐에서 제거되고 실행될 콜 스택으로 푸시됩니다.</p>
<h3 id="싱글-스레드란">싱글 스레드란?</h3>
<p>싱글 스레드(single thread)는 한 번에 하나의 작업을 순차적으로 처리하는 방식입니다. 즉, 한 시점에 하나의 코드 실행만 가능합니다. 이는 프로그램 흐름이 단순하고 예측 가능해 디버깅과 테스트가 상대적으로 쉽고, 다중 스레드 환경에서 발생할 수 있는 동기화 문제, 데이터 경합 등을 신경쓸 필요가 없는 장점이 있습니다. 단점으로는 한 번에 하나의 작업만 처리하므로 성능 제약이 있고, 긴 작업이 실행 중일때 다른 작업이 대기 상태가 되어 반응성이 떨어질 수 있습니다.</p>
<h3 id="콜-스택이란">콜 스택이란?</h3>
<p>JS 엔진이 함수 호출을 관리하는 방식 중 하나로, 함수 호출과 실행 순서를 추적하는 자료 구조입니다. 콜 스택은 기본적으로 LIFO 후입선출 방식으로 작동합니다. 즉 마지막에 추가된 항목이 가장 먼저 제거됩니다.</p>
<p><strong>재귀 호출</strong>
함수가 자기 자신을 호출할 때마다 새로운 실행 컨텍스트가 콜 스택에 푸시됩니다.
재귀 호출이 너무 깊어지면 콜 스택의 크기를 초과하여 “스택 오버플로우(Stack Overflow)“가 발생할 수 있습니다.</p>
<h2 id="자바스크립트가-싱글스레드인데-비동기-처리가-어떻게-가능한가요">자바스크립트가 싱글스레드인데 비동기 처리가 어떻게 가능한가요?</h2>
<p>자바스크립트가 싱글 스레드인데 비동기 처리가 가능한 이유는 이벤트 루프와 콜백 큐를 통해 가능합니다.
비동기 작업은 브라우저 또는 Node.js 환경에서 실행됩니다. 자바스크립트 엔진의 콜스택에 비동기 작업이 발생하면 해당 작업을 백그라운드로 보냅니다. 백그라운드에서 비동기 작업이 완료되면, 해당 작업의 콜백 함수를 태스크큐로 보냅니다. 이벤트루프는 계속해서 콜스택과 태스트큐를 확인하고 콜스택이 비었을때 태스크큐에 콜백 함수가 있다면 이를 콜스택으로 이동시켜 실행합니다. 이러한 과정을 통해 JS는 싱글 스레드이지만 비동기 처리가 가능합니다.</p>
<h3 id="자바스크립트는-왜-싱글-스레드로-설계되었나요">자바스크립트는 왜 싱글 스레드로 설계되었나요?</h3>
<p>JS는 1995년 처음 개발되었고, 당시 웹 앱은 지금처럼 복잡하지 않아 사용자 인터랙션 처리가 싱글 스레드 환경에서도 충분했습니다.</p>
<h3 id="마이크로태스크-큐--태스크-큐-차이점">마이크로태스크 큐 &amp; 태스크 큐 차이점</h3>
<p><strong>마이크로태스크 큐가 태스크 큐보다 우선순위가 더 높아서 해당 큐에 있는 콜백이 먼저 실행</strong>됩니다.
<strong>태스크 큐는 setTimeout, setInterval, I/O 작업 등 일반적인 비동기 작업</strong>의 콜백을 저장하는 용도이고,
<strong>마이크로태스크 큐는 Promise 관련 작업이나 async/await의 후속 작업</strong> 등의 용도로 <strong>보다 짧은 지연 시간의 비동기 작업을 저장하는 용도</strong>입니다.</p>
<h2 id="⭐️-클로저에-대해-설명해주세요">⭐️ 클로저에 대해 설명해주세요.</h2>
<p>클로저란 함수와 그 함수가 선언된 렉시컬 환경의 조합입니다. 클로저는 외부 함수가 반환된 후에도 외부 함수의 변수 범위의 체인에 접근할 수 있는 함수입니다. 예를 들어 외부와 내부 함수가 있을때, 외부함수 실행이 끝나더라도 내부함수는 외부함수의 변수를 참조할 수 있습니다.</p>
<h3 id="렉시컬-스코프란">렉시컬 스코프란?</h3>
<p>렉시컬 스코프란 함수를 선언한 시점에 상위 스코프가 결정되는 것을 말합니다.</p>
<h3 id="스코프란">스코프란?</h3>
<p>스코프는 변수가 접근할 수 있는 유효 범위를 나타냅니다.</p>
<h3 id="스코프-체인에-대해-설명해주세요">스코프 체인에 대해 설명해주세요.</h3>
<p>스코프 체인은 현재 스코프에서 변수를 찾지 못할 경우, 상위 스코프로 이동하여 변수를 찾는 과정입니다. JS에서 함수가 중첩될 때 내부 함수는 외부 함수의 스코프에 접근할 수 있습니다. 스코프 체인은 전역 스코프까지 올라가면서 변수를 검색합니다.</p>
<h2 id="실행-문맥컨텍스트에-대해-설명해주세요">실행 문맥(컨텍스트)에 대해 설명해주세요.</h2>
<p><strong>실행 컨텍스트는 실행할 코드에 제공할 환경 정보들을 모아놓은 객체</strong>입니다. 실행 컨텍스트는 동일한 환경에 있는 코드들을 실행할 때 필요한 환경 정보들을 모아 객체를 구성하고, 이를 콜 스택에 쌓아올렸다가, 가장 위에 쌓여있는 컨텍스트와 관련 있는 코드들을 실행하는 식으로 전체 코드의 환경과 순서를 보장합니다. 어떤 실행 컨텍스트가 활성화되는 시점에 선언된 변수를 위로 끌어올리고 외부 환경 정보를 구성하고, this 값을 설정하는 등의 동작을 수행합니다. 실행 컨텍스트는 자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는 개념입니다. 만약 실행 컨텍스트를 구성하고 싶다면, 함수를 실행해보면 됩니다.</p>
<ol>
<li><p><strong>전역 실행 컨텍스트 생성/소스코드 실행</strong></p>
<ul>
<li><strong>var로 선언한 전역 변수는 객체 환경 레코드</strong>에 저장됨.</li>
<li><strong>const, let으로 선언한 전역 변수는 선언적 환경 레코드</strong>에 저장됨.</li>
<li>edit 함수 실행 컨텍스트 생성/소스코드 실행</li>
</ul>
</li>
<li><p><strong>전역 환경 레코드와 달리 함수 환경 레코드는 분리되지 않고, 한 장소에서 var,const,let 모두를 처리</strong>한다.</p>
<ul>
<li>추가로 알아야 하는 것들:
실행 컨텍스트들은 <strong>실행 컨텍스트 스택</strong>에 하나씩 쌓이고 사라진다. <strong>소스코드 평가 과정에서는 선언문이 실행되고, 스코프에 등록</strong>된다. <strong>소스코드 실행 과정에서는 변수에 값이 할당되고 함수가 호출</strong>된다.</li>
</ul>
</li>
</ol>
<h2 id="⭐️-this가-javascript에서-어떻게-작동하는지-설명하세요">⭐️ this가 JavaScript에서 어떻게 작동하는지 설명하세요.</h2>
<p><strong>this 키워드는 함수가 호출될 때 함수의 실행 문맥을 참조하는 특별한 객체</strong>입니다.
this의 값은 함수가 어떻게 호출되었는지에 따라 동적으로 결정됩니다.</p>
<ul>
<li><strong>생성자 함수 호출(new)</strong>을 할 경우, <strong>미래에 생성할 인스턴스가 바인딩</strong>됩니다.</li>
<li><strong>메서드 호출</strong>을 할 경우, 마침표 연산자 앞에 기술한 객체가 바인딩됩니다.</li>
<li><strong>일반 함수</strong> 호출시, 기본적으로 <strong>전역 객체가 바인딩</strong>됩니다. 브라우저에서는 window 객체, 엄격 모드(&#39;use strict&#39;)에서는 undefined이 됩니다.
위의 규칙 중 다수가 적용되면 더 상위 규칙이 승리하고 this값을 설정합니다. (우선순위는 <strong>생성자 함수 &gt; 명시적 바인딩 (call, apply, bind) &gt; 암시적 바인딩 (메서드 호출) &gt; 기본 바인딩 (전역 객체 또는 undefined) &gt; 화살표 함수 (외부 스코프의 this)</strong> 순)</li>
</ul>
<p>함수가 ES2015 화살표 함수인 경우 위의 모든 규칙을 무시하고 생성된 시점에서 주변 스코프의 this값을 받습니다.</p>
<ul>
<li><strong>화살표 함수</strong>는 자신만의 this 바인딩을 가지지 않고, 선언될 시점에서의 <strong>상위 스코프</strong>가 바인딩됩니다.</li>
</ul>
<h3 id="call-apply-bind에-대해-설명해주세요">call, apply, bind에 대해 설명해주세요.</h3>
<p>call 메서드는 함수의 this 값을 명시적으로 설정하고, 이후의 인수들을 개별적으로 전달하여 함수를 즉시 호출합니다.
apply 메서드는 call과 비슷하지만 함수의 인수를 배열로 전달합니다. 이 역시 함수를 즉시 호출합니다.
bind 메서드는 함수의 this값을 역시 명시적으로 설정하고, 주어진 인수들로 새로운 함수를 반환합니다. 반환된 함수는 나중에 호출될 수 있습니다.</p>
<h2 id="⭐️-호이스팅에-대해-설명하세요">⭐️ 호이스팅에 대해 설명하세요.</h2>
<p>호이스팅은 JS에서 변수나 함수 선언이 그 범위 내에서 최상단으로 끌어올려지는 동작을 의미합니다. 이로 인해 코드에서 변수를 선언하기 전에 참조할 수 있는 것처럼 보이는 현상이 발생합니다. 호이스팅은 변수와 함수의 선언만 끌어올려지며 초기화는 끌어올려지지 않습니다.</p>
<h3 id="⭐️-var-let-const-키워드-관점에서-호이스팅-설명해주세요">⭐️ var, let, const 키워드 관점에서 호이스팅 설명해주세요.</h3>
<p>var은 함수 스코프로 선언과 초기화가 동시에 이루어집니다.
let, const는 블록 스코프로 선언 단계에서만 호이스팅이 됩니다.</p>
<p>따라서 var로 선언하기 전에 해당 변수를 console.log 해보면 할당된 undefined가 출력되고,
let, const로 선언하기 전 해당 변수를 consoel.log 해보면 TDZ에 의해 Reference Error가 출력됩니다.</p>
<h3 id="tdztemporal-dead-zone_일시적-사각지대이란">TDZ(Temporal Dead Zone_일시적 사각지대)이란?</h3>
<p>let, const로 선언한 변수는 선언과 동시에 초기화되지 않고 선언만 호이스팅이 됩니다. 따라서 <strong>초기화가 되기 전에는 참조가 불가능</strong>한데 이 상태를 표현하기 위해 <strong>TDZ(Temporal Dead Zone)</strong> 개념이 사용됩니다. <strong>선언 전에 변수를 사용하는 것을 허용하지 않는 개념상의 공간</strong>입니다.</p>
<p>TDZ에 있는 식별자에 접근하는 것은 ReferenceError를 발생시킵니다.</p>
<h3 id="⭐️-추가적인-var-let-const의-차이점">⭐️ 추가적인 var, let, const의 차이점</h3>
<p>var, let은 재할당이 가능하지만 const는 상수로 재할당이 불가합니다.</p>
<blockquote>
<p>✏️ 정리
var: 함수 스코프, 재할당 가능, 호이스팅 시 undefined로 초기화
let: 블록 스코프, 재할당 가능, 호이스팅 시 Temporal Dead Zone 적용
const: 블록 스코프, 재할당 불가, 호이스팅 시 Temporal Dead Zone 적용</p>
</blockquote>
<h3 id="블록-스코프란">블록 스코프란?</h3>
<p>ES6에서 도입된 개념으로, <strong>중괄호 {}로 둘러싸인 코드 블록 내에서 선언된 변수는 해당 블록 스코프에서만 유효</strong>하다는 의미입니다.</p>
<h3 id="함수-스코프란">함수 스코프란?</h3>
<p>함수 스코프란 <strong>함수 내에서 선언된 변수들이 해당 함수 내에서만 접근 가능</strong>하다는 것을 의미합니다. 블록({}) 내부에서 선언된 변수도 함수 스코프 내에 포함됩니다.</p>
<h2 id="이벤트-위임에-대해서-설명하세요">이벤트 위임에 대해서 설명하세요.</h2>
<p><strong>이벤트 위임은 이벤트 리스너를 하위 요소에 추가하는 대신 상위 요소에 추가하는 기법</strong>입니다. 이 기법은 DOM의 이벤트 버블링(event bubbling) 특성을 활용하여, 하위 요소에서 이벤트가 발생될 때마다 상위 요소의 리스너가 실행되도록 합니다.</p>
<p>장점으로는 각 하위 항목에 이벤트 핸들러를 연결하지 않고, 상위 요소에 하나의 단일 핸들러만 필요하기 때문에 메모리 사용 공간이 줄어듭니다.
또 제거된 요소에서 핸들러를 해제하고 새 요소에 대해 이벤트를 바인딩할 필요가 없습니다.</p>
<h3 id="이벤트-버블링과-캡처링에-대해서-설명해주세요">이벤트 버블링과 캡처링에 대해서 설명해주세요.</h3>
<p>이벤트 버블링은 한 요소에서 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고 이어서 부모 요소의 핸들러가 동작하고, 이러한 과정이 최상단 요소를 만날때까지 반복되면서 이벤트가 전파되는 것을 말합니다.</p>
<p>이벤트 캡쳐링은 이벤트 버블링과 반대로 한 요소에서 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고 자식요소의 핸들러가 동작, 이러한 과정을 반복하며 최하위 요소를 만날 때까지 반복되며 전파되는 것을 말합니다.
addEventListener() 메서드의 세 번째 매개변수로 true로 설정하면 이벤트 캡처링이 발생합니다.</p>
<h3 id="이벤트-버블링-캡처링을-방지하려면-어떻게-해야-하나요">이벤트 버블링, 캡처링을 방지하려면 어떻게 해야 하나요?</h3>
<p>이벤트 전파를 막는 방법은 event.preventDefault()를 사용하면 이벤트에 대한 구현체의 기본 동작을 실행하지 않습니다. 예를 들어 a 태그 클릭시 href로 이동하지 않게 하거나 form 안에 submit 역할을 하는 버튼을 눌렀어도 새로고침하지 않게 하는 경우 사용합니다.
event.stopPropagation()은 현재 이벤트가 버블링되거나 캡쳐링 되는 것을 막습니다.
event.stopImmediatePropagation()은 버블링, 캡쳐링뿐만 아니라 해당 요소에 등록된 다른 이벤트 리스너들도 실행되지 않도록 합니다.</p>
<h2 id="ajax에-대해-설명해주세요">Ajax에 대해 설명해주세요.</h2>
<p>ajax는 서버와 비동기적으로 데이터를 교환하고 웹페이지를 업데이트할 수 있는 기술입니다. 비동기적으로 처리되기 때문에 페이지 전체를 새로고침하지 않고도 수행될 수 있습니다. XMLHttpRequset 객체, fetch() API가 사용됩니다.</p>
<h3 id="ajax를-사용하는-것의-장단점">Ajax를 사용하는 것의 장단점</h3>
<p>장점: 페이지 전체를 새로고침하지 않고도 서버와 통신할 수 있어 사용자 경험을 향상시킵니다. 또 부분적인 데이터 갱신을 통해 응답 시간이 단축되고 네트워크 대역폭을 절약할 수 있습니다. JSON, XML, HTML 등 다양한 형식의 데이터를 처리할 수 있습니다.</p>
<p>단점: SEO에 불리할 수 있습니다. 일부 웹 크롤러는 JS를 실행하지 않아 JS에 의해 로드된 컨텐츠를 볼 수 없습니다.</p>
<h2 id="프로토타입에-대해-설명해주세요">프로토타입에 대해 설명해주세요.</h2>
<p><strong>프로토타입은 객체가 다른 객체로부터 상속받을 수 있도록 해주는 객체</strong>입니다. 자바스크립트는 프로토타입 기반 언어로서 객체를 생성하고 상속하는 메커니즘을 제공합니다. 모든 JS 객체는 다른 객체에 기초하여 생성됩니다. 이를 위해 각 객체는 내부적으로 ‘<strong>proto</strong>’라는 내부 속성을 가지고 있는데, 이 속성은 객체를 생성한 생성자 함수의 프로토타입 객체를 가리킵니다.</p>
<p>프로토타입을 사용하는 이유는 여러 객체가 동일한 프로토타입을 공유함으로써 메모리 사용을 줄일 수 있고, 프로토타입 체인을 통해 상속을 자연스럽게 구현할 수 있기 때문입니다. 또 실행 중에 프로토타입 객체를 수정하여 모든 객체에 즉시 적용 가능합니다(동적 프로퍼티 및 메서드 추가 가능).</p>
<h3 id="프로토타입-상속이-어떻게-작동하는지-설명하세요">프로토타입 상속이 어떻게 작동하는지 설명하세요.</h3>
<p>프로토타입 상속은 객체가 다른 객체의 프로퍼티와 메서드를 상속받는 메커니즘을 말합니다. 예를 들어, 어떤 객체가 특정 메서드를 호출할 때 그 객체 자신의 해당 메서드가 없다면, JS는 이 객체의 프로토타입 체인을 따라 올라가며 해당 메서드를 찾습니다. 이 과정에서 상위 프로토 타입 객체에 정의된 메서드가 실행되어 해당 객체에 상속됩니다. 만약 최상위 프로토 타입 객체에서도 해당 메서드가 없다면 null 에서는 더 이상 메서드를 찾을 수 없어 (TypeError: Cannot read property &#39;method&#39; of undefined) 오류가 발생합니다.</p>
<h2 id="attribute와-property의-차이점에-대해-설명하세요">attribute와 property의 차이점에 대해 설명하세요.</h2>
<p><strong>attribute는 HTML 마크업에 정의</strong>되지만 <strong>property는 DOM에 정의</strong>됩니다.</p>
<p><strong>attribute</strong>는 <strong>HTML 태그 내에서 정의된 키-값 쌍</strong>으로 객체의 데이터를 설명하거나 특정 메타 데이터를 지정합니다. 예를 들어<code>HTML</code> 태그에서 <code>class, type, id</code> 등을 의미합니다.</p>
<p><strong>property</strong>는 <strong>DOM 객체의 속성</strong>으로, JavaScript를 통해 동적으로 읽고 쓸 수 있습니다.</p>
<p>HTML attribute는 초기 DOM property의 값을 설정하지만, 이후 JavaScript로 DOM property를 변경해도 HTML attribute는 그대로 남아 있습니다.</p>
<p><a href="https://stackoverflow.com/questions/6003819/what-is-the-difference-between-properties-and-attributes-in-html">참고</a></p>
<h2 id="⭐️-es6에서-달라진-점-말해주세요">⭐️ ES6에서 달라진 점 말해주세요.</h2>
<p>ES6에서는 let, const, 화살표 함수, 클래스, 템플릿 리터럴, 구조 분해 할당, 기본 매개변수 기본값 설정, 나머지 매개변수와 전개 연산자, import 키워드, 프로미스, 심볼, 향샹된 객체 리터럴이 추가되었습니다.</p>
<p><strong>자세한 설명</strong></p>
<ol>
<li><p>let과 const
let: 블록 스코프 변수를 선언합니다. 함수 스코프가 아닌 블록 스코프를 가지므로, var의 호이스팅 문제를 해결합니다.
const: 블록 스코프 상수로, 선언과 동시에 초기화되어야 하며, 이후 재할당이 불가능합니다.</p>
</li>
<li><p>화살표 함수 (Arrow Functions)
구문: () =&gt; {} 형태의 간결한 함수 선언 방식.
this 바인딩: 화살표 함수는 자신만의 this를 가지지 않고, 외부 스코프의 this를 유지합니다.</p>
</li>
<li><p>클래스 (Classes)
클래스 문법: ES5의 프로토타입 기반 상속을 간단하고 명확하게 표현하는 구문.</p>
</li>
<li><p>템플릿 리터럴 (Template Literals)
문자열 템플릿: 백틱(`)을 사용하여 문자열 내에서 변수를 쉽게 포함할 수 있습니다.</p>
</li>
<li><p>구조 분해 할당 (Destructuring Assignment)
배열 및 객체 분해: 배열이나 객체의 속성을 개별 변수로 쉽게 분해할 수 있습니다.</p>
</li>
<li><p>기본 매개변수 (Default Parameters)
기본값 설정: 함수 매개변수에 기본값을 설정할 수 있습니다.</p>
</li>
<li><p>나머지 매개변수와 전개 연산자 (Rest and Spread Operators)
나머지 매개변수: 가변 인수를 배열 형태로 받을 수 있습니다. 함수의 매개변수 수가 정해져 있지 않고 호출할 때마다 다른 수의 인수를 전달할 수 있습니다.
전개 연산자: 배열이나 객체를 개별 요소로 분해할 수 있습니다.</p>
</li>
<li><p>모듈 (Modules)
모듈화: import와 export 키워드를 사용하여 코드의 모듈화를 지원합니다.</p>
</li>
<li><p>프로미스 (Promises)
비동기 처리: 콜백 헬을 방지하고, 비동기 작업을 더 간결하게 작성할 수 있습니다.</p>
</li>
<li><p>심볼 (Symbols)
고유 식별자: 객체 속성의 고유 식별자로 사용됩니다.</p>
</li>
<li><p>향상된 객체 리터럴 (Enhanced Object Literals)
개선된 문법: 객체 리터럴의 속성을 정의할 때 변수명을 직접 사용할 수 있고, 메서드 축약 구문을 사용할 수 있습니다.</p>
</li>
</ol>
<h2 id="es6에서-arrow-함수를-언제-왜-쓸까요">ES6에서 Arrow 함수를 언제, 왜 쓸까요?</h2>
<p>Arrow 함수는 함수 본연의 입출력 기능을 직관적으로 표현해줍니다. 파라미터가 하나일 때 소괄호를, return 한 줄만 있을 때 중괄호와 return을 생략할 수 있어 코드가 간결해집니다.
또한, 내부의 this 값이 함수가 선언된 곳의 this 값을 그대로 사용하므로, this의 변경을 피할 수 있습니다. 단, 일반 함수와 용도가 완전히 같지 않아 항상 대체할 수는 없습니다.</p>
<p><a href="https://github.com/Esoolgnah/Frontend-Interview-Questions/blob/main/Notes/important-3/es6-arrow-function.md">참고</a></p>
<h2 id="클래스가-뭔지-설명해주세요">클래스가 뭔지 설명해주세요.</h2>
<p>클래스는 객체 지향 프로그래밍에서 사용되는 개념으로 객체를 생성하기 위한 템플릿을 말합니다. 클래스를 사용하면 코드의 재사용성을 높이고, 복잡한 시스템을 더 쉽게 설계할 수 있습니다. 객체 지향 프로그래밍의 주요 원칙으로는 캡슐화, 상속, 다형성이 있습니다.</p>
<ol>
<li><strong>캡슐화 (Encapsulation)</strong>:</li>
</ol>
<ul>
<li>객체의 속성과 메서드를 하나로 묶고, 외부로부터 내부의 상태를 숨기는 것입니다. 이를 통해 데이터의 무결성을 유지하고, 객체의 사용 방법을 단순화할 수 있습니다.</li>
</ul>
<ol start="2">
<li><strong>상속 (Inheritance)</strong>:</li>
</ol>
<ul>
<li>하나의 클래스가 다른 클래스의 속성과 메서드를 물려받는 것입니다. 이를 통해 코드의 재사용성을 높이고, 계층 구조를 형성할 수 있습니다.</li>
</ul>
<ol start="3">
<li><strong>다형성 (Polymorphism)</strong>:</li>
</ol>
<ul>
<li>동일한 메서드나 속성 이름이 클래스에 따라 다르게 동작하는 것입니다. 이를 통해 객체 간의 상호작용을 단순화하고 유연성을 높일 수 있습니다.</li>
</ul>
<h2 id="생성자란">생성자란?</h2>
<p>JS의 생성자 함수는 새로운 객체를 생성하고 초기화 하는데 사용합니다. 객체를 생성할때 new라는 키워드와 대문자로 시작해서 선언합니다. 생성자 함수는 this를 사용하여 새로운 객체의 속성을 정의할 수 있습니다.</p>
<h3 id="익명-함수란">익명 함수란?</h3>
<p>익명 함수는 이름이 없는 함수로, 일반적으로 함수 리터럴(function literal)을 사용하여 정의됩니다. 익명 함수는 주로 함수 표현식(function expression)으로 사용되며, 변수에 할당하거나 직접 호출할 수 있습니다.</p>
<h3 id="익명-함수의-일반적인-사용-사례는-무엇인가요">익명 함수의 일반적인 사용 사례는 무엇인가요?</h3>
<p>익명 함수는 다음과 같은 경우에 주로 사용됩니다:</p>
<ol>
<li>일회성 함수: 한 번만 사용되고 재사용되지 않는 함수.</li>
<li>콜백 함수: 다른 함수에 인수로 전달되어 특정 이벤트나 작업이 완료된 후 호출되는 함수.</li>
<li>즉시 실행 함수 (IIFE): 정의와 동시에 즉시 실행되는 함수로, 변수나 코드 블록을 캡슐화하여 전역 범위로의 누출을 방지합니다.</li>
</ol>
<p>익명 함수는 코드의 캡슐화와 일회성 작업, 이벤트 핸들러와 콜백 함수 등에서 유용하게 사용됩니다.</p>
<h3 id="함수-선언문과-함수-표현식의-차이">함수 선언문과 함수 표현식의 차이?</h3>
<p>함수 선언문으로 정의된 함수는 호이스팅됩니다. 이는 함수 선언이 코드의 최상단으로 끌어올려지기 때문에, 함수가 정의되기 전에도 호출할 수 있음을 의미합니다. 또한 같은 스코프 내에서 여러 번 정의할 수 있습니다.</p>
<pre><code class="language-javascript">greet(); // 출력: &quot;Hello, World!&quot;

function greet() {
  console.log(&quot;Hello, World!&quot;);
}</code></pre>
<p>함수 표현문은 함수 표현식은 익명 함수일 수도 있으며, 변수에 할당됩니다. 변수에 할당된 함수는 변수 이름을 통해 호출할 수 있습니다.
함수 표현식은 호이스팅되지 않습니다. 함수 표현식이 정의되기 전에 호출하면 undefined 오류가 발생합니다.
변수에 할당된 함수는 해당 변수로 재정의할 수 있지만, 변수 이름을 통해 호출해야 합니다.</p>
<pre><code class="language-javascript">console.log(greet); // 출력: undefined

const greet = function () {
  console.log(&quot;Hello, World!&quot;);
};

greet(); // 출력: &quot;Hello, World!&quot;</code></pre>
<h2 id="require와-import-차이점">require와 import 차이점</h2>
<p>둘 다 모듈 키워드로 외부 파일이나 라이브러리를 불러올 때 사용합니다. CommonJS 모듈 시스템에서는 require을 사용하고, import는 ES6부터 새로 도입된 키워드로 export한 파일을 import로 불러옵니다. require는 프로그램의 어느 지점에서나 호출 가능하지만, imports는 파일의 시작 부분에서만 실행할 수 있습니다.</p>
<p>일반적으로 import는 사용자가 필요한 모듈 부분만 선택하고 로드할 수 있기 때문에 더 선호됩니다. import는 require보다 성능이 우수하며 메모리를 절약합니다.</p>
<h2 id="콜백에-대해-설명해주세요">콜백에 대해 설명해주세요.</h2>
<p><strong>콜백 함수는 다른 함수의 인자로 전달되어 특정 작업이 완료되면 호출</strong>되는 함수입니다. <strong>주로 비동기 작업의 결과나 에러 처리를 위해 사용</strong>됩니다.</p>
<p>콜백 함수를 호출하는 방법에는 동기, 비동기 두 가지 방식이 있습니다. <strong>동기식 콜백은 중간에 비동기 작업 없이 외부 함수 호출 직후에 호출</strong>되고, <strong>비동기식 콜백은 asynchronous 작업이 완료된 후 나중에 호출</strong>됩니다.</p>
<p><strong>동기식 콜백의 예는 Array.prototype.map(), Array.prototype.forEach()에 전달된 콜백 함수</strong>가 있습니다.
<strong>비동기식 콜백의 예는 setTimeOut(), Promise.prototype.then()</strong>이 있습니다.</p>
<h3 id="map-foreach의-차이점">map, forEach의 차이점</h3>
<p>forEach는 map과 달리 원본 객체를 변형하고, return 값을 반환하지 않습니다.
map은 원본 객체를 변형하지 않고, 변형된 새로운 배열을 반환합니다.</p>
<h3 id="⭐️-콜백-지옥이란">⭐️ 콜백 지옥이란?</h3>
<p>여러 개의 비동기 작업이 연달아 발생할 때 콜백 함수가 중첩되어 코드가 복잡해지는 현상입니다. ES6에서 도입된 Promise나 async awiat을 사용하면 보다 간단하고 직관적인 구조로 비동기 코드를 작성할 수 있어 콜백 지옥을 방지할 수 있습니다.</p>
<h2 id="⭐️-promise에-대해-설명해주세요">⭐️ Promise에 대해 설명해주세요.</h2>
<p>Promise는 ES6에 등장한 비동기 작업을 관리하기 위해 사용되는 객체로, 비동기 작업의 완료 또는 실패 여부를 추적하고 이를 처리하는 코드를 제공합니다.</p>
<p>Promise는 <strong>대기 중(Pending), 완료(Fullfiled), 실패(Rejected)</strong> 3가지 상태를 가지며 이를 이용해 비동기 작업의 흐름을 제어할 수 있습니다.
Promise의 then 메서드는 또 다른 Promise를 반환하므로 여러 비동기 작업을 순차적으로 처리할 수 있습니다.</p>
<h3 id="promiseall에-대해서-설명해주세요">Promise.all()에 대해서 설명해주세요.</h3>
<p>Promise.all()은 여러 개의 Promise가 모두 이행될 때까지 기다리며, 하나라도 거부되면 전체가 거부됩니다.</p>
<h3 id="promiserace에-대해서-설명해주세요">Promise.race()에 대해서 설명해주세요.</h3>
<p>Promise.race는 가장 먼저 이행되거나 거부된 Promise의 결과를 반환합니다.</p>
<h3 id="promise와-callback를-비교-설명해주세요">Promise와 Callback를 비교 설명해주세요.</h3>
<p>Promise와 콜백(callback)은 모두 JavaScript에서 비동기 작업을 처리하는 데 사용되는 방법입니다.</p>
<p>Promise를 사용하면 콜백 지옥을 방지하고 코드를 구조화하여 가독성을 높일 수 있습니다.
Promise는 catch 메서드를 통해 에러를 한 번에 처리할 수 있지만 콜백은 각각의 비동기 함수에서 별도로 에러를 처리해야 합니다. 또한, Promise는 then 메서드를 사용하여 비동기 작업을 순차적으로 처리할 수 있어 코드를 직관적으로 작성할 수 있습니다. 콜백은 보통 중첩된 구조로 순서를 보장하기 어렵습니다.
Promise는 async/await와 함께 사용될 수 있어 더 간편하게 작성할 수 있습니다.</p>
<h3 id="promise와-async-await를-비교-설명해주세요">Promise와 Async, Await를 비교 설명해주세요.</h3>
<p>Promise는 비동기 작업의 완료 또는 실패를 나타내는 객체이고, async/await는 Promise를 더 간단하고 동기 코드처럼 작성할 수 있게 해주는 문법입니다.</p>
<p>async 키워드를 사용하여 함수를 비동기 함수로 선언하고 <strong>async는 항상 Promise를 반환</strong>합니다. <strong>이 함수 내에서 await 키워드를 만나면, 해당 Promise가 해결될 때까지 비동기적으로 기다립니다</strong>. await은 Promise가 해결될 때까지 함수 실행을 일시 중단하고, 해결된 후에는 마이크로태스크 큐에 다음 작업을 넣어 실행을 재개합니다.</p>
<h2 id="동기와-비동기의-차이점">동기와 비동기의 차이점</h2>
<p><strong>동기</strong>는 말 그대로 ‘<strong>동시에 일어난다</strong>’는 뜻 입니다. <strong>코드 순서대로 실행</strong>되고 여러 가지 요청을 동시에 처리할 수 없습니다.</p>
<p><strong>비동기</strong>는 ‘<strong>동시에 일어나지 않는다</strong>’를 의미합니다. 하나의 요청에 따른 응답을 즉시 처리하지 않아도, 그 대기 시간 동안 또 다른 요청에 대해 처리가 가능한 방식입니다. JavaScript에서는 이벤트 루프를 사용하여 비동기 작업을 처리하는 작동 방식 덕에 이러한 처리가 가능합니다.</p>
<p>예를 들어 쉽게 말하면 카페에서 커피를 줄서서 주문할때 앞에 사람이 커피를 받아야 다음 사람이 주문할 수 있는 것은 동기 처리이고, 커피를 주문한 사람마다 진동벨을 주고 음료가 완료되면 손님을 부르는 방식이 비동기 처리입니다.</p>
<h2 id="blocking과-non-blocking에-대해-설명해주세요">Blocking과 Non-Blocking에 대해 설명해주세요.</h2>
<p>블로킹(blocking)은 코드의 실행이 다른 코드의 실행을 막는다는 것을 의미합니다.
반면, 논블로킹(Non-blocking)은 코드의 실행이 다른 코드의 실행을 막지 않는다는 것을 의미합니다.</p>
<h2 id="깊은-복사와-얕은-복사에-대해-설명해주세요">깊은 복사와 얕은 복사에 대해 설명해주세요.</h2>
<p>얕은 복사는 객체를 참조하고 있어서 값을 변경하면 참조하고 있던 객체의 값도 변경됩니다. 깊은 복사는 다른 객체로 복사하는 것이라서 값을 변경하면 원본 객체는 변하지 않습니다.</p>
<h3 id="원본을-변경불가를-위해-어떻게-해야-할까요">원본을 변경불가를 위해 어떻게 해야 할까요?</h3>
<p>원본 데이터를 변경할 수 없도록 하려면 JavaScript에서는 주로 객체나 배열의 복사본을 만들거나, 객체를 동결(immutable)시키는 방법을 사용합니다.</p>
<ol>
<li><p>객체 동결 (Object.freeze)
Object.freeze 메서드를 사용하면 객체를 동결할 수 있습니다. 동결된 객체는 변경이 불가능해집니다.</p>
</li>
<li><p>깊은 복사 (Deep Copy)
깊은 복사를 통해 원본 객체의 복사본을 만들어 원본 객체를 변경하지 않도록 할 수 있습니다. 이는 특히 중첩된 객체나 배열을 다룰 때 유용합니다.</p>
<ol>
<li><p><strong>JSON.parse와 JSON.stringify 사용</strong></p>
<pre><code class="language-javascript">const copy = JSON.parse(JSON.stringify(original));</code></pre>
</li>
<li><p><strong>라이브러리 사용 (예: lodash)</strong></p>
</li>
<li><p><strong>상수 사용 (const)</strong>
객체나 배열의 레퍼런스를 const로 선언하면, 변수 자체의 재할당은 불가능하지만 객체의 속성은 여전히 변경할 수 있습니다. 따라서 const만으로는 원본 데이터 변경을 완전히 막을 수는 없습니다.</p>
</li>
<li><p><strong>함수 내부에서 객체 변경 방지</strong>
함수 내에서 원본 객체를 변경하지 않도록 복사본을 만들어 사용하는 방법입니다.</p>
</li>
</ol>
</li>
</ol>
<h3 id="objectassign-과-spread-등-객체를-복사하는-방법들이-가진-문제점이-무엇인가요">Object.Assign 과 spread 등 객체를 복사하는 방법들이 가진 문제점이 무엇인가요?</h3>
<ul>
<li><strong>Object.assign: 중첩된 객체의 경우 얕은 복사(shallow copy)만 수행하므로, 중첩된 객체가 있는 경우 원본 객체가 변경</strong>될 수 있습니다.</li>
<li><strong>Spread 연산자: 역시 얕은 복사만을 수행하므로 중첩된 객체에 대해서는 동일한 문제가 발생</strong>합니다.</li>
<li><strong>JSON.parse(JSON.stringify(obj)): 이 방법은 객체를 완전히 복사하지만, 함수나 undefined 같은 값들을 복사할 수 없습니다</strong>.</li>
</ul>
<h3 id="어떤-단계까지-immutable불변한가요">어떤 단계까지 immutable(불변)한가요?</h3>
<ol>
<li><p><strong>원시 데이터 유형 (Primitive Types)</strong>: 원시 데이터 유형인 <strong>숫자(Number), 문자열(String), 불린(Boolean), null, undefined는 불변성</strong>을 가지고 있습니다. <strong>이들은 값 자체가 변경되지 않고 새로운 값이 할당되어야만 변경</strong>됩니다.</p>
</li>
<li><p><strong>객체 (Objects)</strong>: <strong>객체는 참조 타입이며 불변성을 가지고 있지 않습니다</strong>. <strong>객체의 프로퍼티는 변경될 수 있고, 객체 자체의 참조가 변경될 수 있습니다</strong>. <strong>그러나 객체를 불변하게 유지하기 위해 Immutable.js와 같은 라이브러리를 사용하여 변경 불가능한 객체를 생성</strong>할 수 있습니다.</p>
</li>
<li><p><strong>배열 (Arrays)</strong>: <strong>배열 역시 객체와 마찬가지로 참조 타입이며 불변성을 가지고 있지 않습니다</strong>. <strong>배열의 요소는 변경될 수 있고, 배열 자체의 참조가 변경될 수 있습니다</strong>. 마찬가지로 Immutable.js와 같은 라이브러리를 사용하여 변경 불가능한 배열을 생성할 수 있습니다.</p>
</li>
</ol>
<h2 id="자바스크립트-메모리-관리에-대해-아는-대로-말해주세요">자바스크립트 메모리 관리에 대해 아는 대로 말해주세요.</h2>
<p>JS의 메모리 관리는 자동으로 수행되며, 이를 가비지 컬렉션이라고 합니다. JS엔진은 메모리를 자동으로 할당하고 해제합니다. 가비지 컬렉션은 더 이상 사용되지 않는 객체를 자동으로 메모리에서 해제하여 메모리 누수를 방지하는 메커니즘입니다.</p>
<h3 id="가비지-컬렉터가-어떻게-작동하는지-설명해주세요">가비지 컬렉터가 어떻게 작동하는지 설명해주세요.</h3>
<p>가비지 컬렉터는 Mark and Sweep 알고리즘을 사용합니다. <strong>마크</strong> 단계에서 <strong>루트 객체에서 시작해 도달 가능한 모든 객체를 마크</strong>합니다. <strong>스위프</strong> 단계에서 <strong>마크되지 않은 객체를 메모리에서 해제</strong>하는 방식으로 동작합니다.</p>
<h2 id="제너레이터란">제너레이터란?</h2>
<p>제네레이터(Generator)는 자바스크립트의 함수 중 하나로, 일반 함수와 달리 실행 도중에 여러 번 멈추고 재개할 수 있는 특성을 가지고 있습니다. 제네레이터는 function* 키워드로 정의되며, yield 키워드를 사용해 실행을 일시 중지하고 값을 반환합니다. 제네레이터 함수는 호출 시 즉시 실행되지 않고, 대신 이터레이터 객체를 반환합니다. 이 이터레이터 객체를 통해 제네레이터의 실행을 제어할 수 있습니다.</p>
<hr>
<h1 id="typescript">TypeScript</h1>
<h2 id="⭐️-타입스크립트-잘-아시나요-사용-경험">⭐️ 타입스크립트 잘 아시나요? 사용 경험</h2>
<p>여러 프로젝트에서 타입스크립트를 사용한 경험이 있습니다. 해당 경험으로 타입 상속, 유틸리티 타입을 통해 중복을 줄이고 재사용하는 법을 배웠습니다. 또한 타입스크립트 사용으로 타입 체크를 통해 오류를 방지할 수 있어 타입스크립트 사용을 지향하는 편입니다.</p>
<h2 id="자바스크립트와-타입스크립트의-차이를-설명해주세요">자바스크립트와 타입스크립트의 차이를 설명해주세요</h2>
<p>자바스크립트는 동적 타입 언어로 <strong>변수의 타입을 런타임 시점에 결정</strong>합니다.
타입스크립트는 정적 타입 언어로, <strong>변수의 타입을 코드 작성 시점에 명시하여 타입 오류를 미리 방지</strong>합니다.</p>
<h2 id="타입스크립트에서-타입을-지정할-때-인터페이스와-타입은-뭐가-다른지-설명해주세요">타입스크립트에서 타입을 지정할 때 인터페이스와 타입은 뭐가 다른지 설명해주세요.</h2>
<ul>
<li><strong>인터페이스: 주로 객체의 구조를 정의할 때 사용되며, extends 키워드를 사용해 상속이 가능</strong>합니다.</li>
<li><strong>타입(Type): 객체뿐만 아니라 원시 타입, 유니온 타입(| 연산자), 교차 타입(&amp; 연산자), 튜플 등을 정의할 수 있습니다.</strong></li>
</ul>
<p>인터페이스는 동일한 이름으로 여러 번 선언되면 TS가 이를 병합합니다. 타입은 선언 병합을 지원하지 않습니다.</p>
<h2 id="any-unknown의-공통점과-차이점을-설명해주세요">any, unknown의 공통점과 차이점을 설명해주세요.</h2>
<p>공통점은 any와 unknown은 모두 모든 타입을 할당할 수 있는 타입입니다.</p>
<p>차이점은 any는 타입 안전성을 무시하며 자유롭게 사용할 수 있는 반면, <strong>unknown은 타입 안전성을 보장하고, 사용하기 전에 반드시 타입 확인이 필요합니다. unknown은 any보다 더 안전한 타입으로 간주됩니다.</strong></p>
<hr>
<blockquote>
<p>면접 질문 목록을 모두 외우려고 하는 것은 추천드리지 않고, 질문을 받았을 때 간단하게 핵심을 말할 수 있도록 연습하는 것을 추천합니다. 또 꼬리 질문이 들어왔을때 대답할 수 있게 원리에 대해 이해하는 것이 중요합니다. 질문 목록이 굉장히 많지만 회바회 질문이 다르고 ⭐️이 실제 면접 질문이 나온 부분임을 확인해주세요! 또한 답변은 개인의 경험에 따라 달라질 수 있습니다.</p>
</blockquote>
<blockquote>
<p>추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)</p>
</blockquote>
<hr>
<h2 id="📌-참고-자료">📌 참고 자료</h2>
<p><a href="https://github.com/Esoolgnah/Frontend-Interview-Questions?tab=readme-ov-file">깃허브 - 프론트엔드 면접질문 중요도별 정리</a></p>
<p><a href="https://www.frontendinterviewhandbook.com/kr/javascript-questions#this%EA%B0%80-javascript%EC%97%90%EC%84%9C-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%91%EB%8F%99%ED%95%98%EB%8A%94%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%84%B8%EC%9A%94">프론트엔드 면접 질문 - JS 질문</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프론트엔드 면접 준비] React 질문 목록 (feat. Next.js)]]></title>
            <link>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%A4%91%EC%9A%94%ED%95%9C-%EB%AA%A8%EB%93%A0-%EA%B2%83</link>
            <guid>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%9D%98-%EC%A4%91%EC%9A%94%ED%95%9C-%EB%AA%A8%EB%93%A0-%EA%B2%83</guid>
            <pubDate>Sat, 03 Aug 2024 03:54:43 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>최근 면접 준비를 하면서 공부한 React 중요 개념에 대해 정리해봤습니다.
프론트엔드 면접 질문 목록을 찾아보면 대부분 중요한 질문들이 비슷한데 해당 질문 목록과 실제 면접 경험 + 본인의 프로젝트 경험을 넣어 내용 정리했습니다.
참고로 실제 면접에서 받은 질문들 앞에는 ⭐️ 별을 붙였습니다.</p>
</blockquote>
<h2 id="리액트란">리액트란?</h2>
<p>React는 사용자 인터페이스를 구축하기 위한 자바스크립트 라이브러리로 Facebook에서 개발하고 관리합니다. 빠르고 효율적인 렌더링을 통해 동적인 웹 애플리케이션을 쉽게 개발할 수 있도록 도와줍니다.</p>
<h2 id="리액트를-사용하는-이유">리액트를 사용하는 이유</h2>
<p>React는 가상 돔을 활용하여 효율적인 UI 업데이트를 가능케 하며, 컴포넌트 기반 구조로 독립적이고 재사용 가능한 컴포넌트로 분리하여 개발해 각 상태관리와 로직을 관리할 수 있습니다. 또 큰 커뮤니티와 생태계를 갖추고 있어 다양한 라이브러리와 도구를 활용하여 빠르게 애플리케이션을 개발할 수 있습니다.</p>
<h2 id="dom이란">DOM이란?</h2>
<p>DOM(Document Object Model)은 웹 페이지의 구조를 프로그래밍적으로 접근하고 조작할 수 있는 방법을 제공하는 표준 인터페이스입니다. HTML, XML 문서의 계층적 구조를 트리 형태로 표현한 것으로, 웹 브라우저가 웹 페이지를 렌더링할 때 이 구조를 사용합니다.</p>
<p>최상위 노드는 문서 전체를 나타내는 document 객체이고, &lt;div&gt;, &lt;p&gt; 등 웹 페이지의 각 요소는 DOM 트리의 하나의 노드로 표현됩니다. JavaScript로 DOM을 직접 조작 가능합니다. 또한 키보드 입력, 마우스 이동 등의 사용자 인터랙션에 대한 이벤트를 처리하는 메커니즘을 제공합니다.</p>
<h2 id="⭐️-가상돔이란">⭐️ 가상돔이란?</h2>
<p><a href="https://www.youtube.com/watch?v=XWqs1mMPJ30&amp;ab_channel=%ED%94%84%EB%A1%A0%ED%8A%B8%EB%A7%A8">참고</a></p>
<p>Virtual DOM은 실제 DOM의 복사본으로, 웹 성능을 최적화하기 위해 사용되는 DOM 관리 방법입니다. 애플리케이션 상태 변경시 가상 DOM 객체를 통해 변경된 부분만 찾아내어 이를 실제 DOM에 적용하는 기능을 합니다.</p>
<p>Virtual DOM의 동작 순서는 크게 Diffing, Reconciliation 두 가지로 구분할 수 있습니다. Diffing이란 가상돔에서 변경점을 찾아내는 과정을 의미하며, Reconciliation은 찾아낸 변경점을 실제 DOM에 적용하는 과정을 의미합니다.</p>
<h3 id="가상돔-동작-과정">가상돔 동작 과정</h3>
<p>애플리케이션이 처음 실행될 때 애플리케이션의 초기 상태를 담은 Virtual DOM을 메모리 상에 하나 생성합니다. 이후 애플리케이션이 실행되면서 상태가 변경된 부분이 있는 경우, 새로운 버전의 Virtual DOM을 메모리상에 하나 더 생성합니다. 새로운 버전의 Virtual DOM이 생성된 후, 이전 버전의 Virtual DOM과 비교하는 과정이 Diffing에 돌입하고, 변경점을 찾아냅니다. 이 과정에서 두 Virtual DOM 트리의 각 노드를 비교하여 어떤 부분이 변경되었는지 확인합니다. 변경점을 찾아낸 이후에는, 실제 DOM에 적용하는 과정인 Reconciliation에 돌입합니다. 이 과정에서 변경된 부분만 실제 DOM에 업데이트하기 때문에, 브라우저 성능이 향상될 수 있는 것입니다. Reconciliation이 완료된 이후, 또 다른 변경점이 생기면 구 버전의 Virtual DOM이 폐기되고, 새로운 변경 사항을 반영한 최신 버전의 Virtual DOM이 다시 생성됩니다.</p>
<h3 id="state-props-상태-변화가-생길때마다-이러한-과정이-수행되나요">state, props 상태 변화가 생길때마다 이러한 과정이 수행되나요?</h3>
<p>짧은 시간안에 여러 개의 state, props가 동시에 변경되면 이를 각각 처리하는 것이 아니라 한꺼번에 모아서 처리하는 Batch Update가 이루어집니다.</p>
<h3 id="virtual-dom을-사용하는-것이-그렇지-않은-것보다-좋은가요">Virtual DOM을 사용하는 것이 그렇지 않은 것보다 좋은가요?</h3>
<p>항상 그런 것은 아닙니다. 간단한 애플리케이션 경우에는 가상돔을 사용하는 것이 오히려 오버헤드를 초래할 수 있습니다. 가상돔 자체도 메모리 공간을 차지하고 Diffing하는 과정 역시 CPU를 활용하기 때문입니다. 다만, DOM 트리가 복잡하고, 상태 변경도 빈번하게 일어나는 대규모 애플리케이션의 경우 사람의 인지 능력으로는 정확히 어떤 DOM을 업데이트해야 하는지 식별하기 어렵기 때문에 가상돔을 사용하는 것입니다. 따라서 애플리케이션의 복잡도와 요구 사항에 맞게 가상돔 적용 여부를 정하는 것이 좋습니다.</p>
<h2 id="react-18버전에서는-뭐가-달라졌나요">React 18버전에서는 뭐가 달라졌나요?</h2>
<p>React 18에서는 동시성 모드(Concurrent Mode)가 도입되어 긴 렌더링 작업을 중단하고 사용자 입력과 같은 더 중요한 작업을 먼저 처리할 수 있습니다. 자동 일괄 처리 기능(Automatic Batching)이 향상되어 이벤트 핸들러뿐만 아니라 비동기 코드 내에서도 일괄 처리가 가능해졌습니다. 또한 useTransition 훅을 사용하여 상태 업데이트의 우선순위를 구분할 수 있으며, useDeferredValue 훅을 사용해 긴급하지 않은 상태 업데이트에서 이전 값을 사용할 수 있습니다. Suspense 기능도 개선되어 데이터를 가져오는 동안 컴포넌트의 로딩 상태를 더 쉽게 관리할 수 있습니다.</p>
<h3 id="batch-update란">Batch Update란</h3>
<p>Batch Update(일괄 업데이트)는 여러 상태 업데이트를 하나의 단위로 묶어 한 번에 처리하는 방식입니다. React에서는 이러한 배치 업데이트를 통해 성능을 최적화할 수 있습니다. 상태 업데이트가 일어날 때마다 리렌더링이 발생하면 성능에 큰 영향을 미칠 수 있기 때문에, React는 여러 업데이트를 모아서 한 번에 처리함으로써 리렌더링 횟수를 줄입니다.</p>
<h3 id="react에서의-batch-update">React에서의 Batch Update</h3>
<p>React는 이벤트 핸들러 내에서 발생하는 여러 상태 업데이트를 자동으로 일괄 처리합니다. 예를 들어, 버튼 클릭 시 여러 상태를 변경해야 하는 경우, React는 각 상태 업데이트마다 리렌더링하지 않고, 모든 상태 업데이트가 완료된 후에 한 번만 리렌더링합니다.</p>
<h3 id="react-18에서의-batch-update-확장">React 18에서의 Batch Update 확장</h3>
<p>React 18에서는 비동기 코드에서도 일괄 처리가 가능하도록 기능이 확장되었습니다. 기존에는 이벤트 핸들러 내에서만 일괄 처리가 가능했지만, 이제는 Promise나 setTimeout과 같은 비동기 작업에서도 일괄 처리가 지원됩니다.</p>
<h2 id="jsx-tsx란">JSX, TSX란?</h2>
<p>JSX는 JavaScript XML로 자바스크립트 코드 안에 HTML과 같은 구문을 사용할 수 있게 해줘 이를 통해 UI 구조를 직관적으로 작성할 수 있습니다.
TSX란 TypeScript XML로 JSX와 유사하지만 타입스크립트의 타입 시스템을 활용할 수 있습니다. 이를 활용하면 타입 체크를 통해 더 안전한 코드를 작성할 수 있습니다.</p>
<h2 id="spa-csr-ssr-ssg의-개념">SPA, CSR, SSR, SSG의 개념</h2>
<p>SPA는 단일 페이지 애플리케이션으로 초기에 필요한 코드를 모두 로드한 후, 페이지를 다시 로드하지 않고 동적으로 콘텐츠를 업데이트하는 방식입니다.</p>
<p>CSR는 클라이언트 측에서 페이지를 동적으로 렌더링하는 방식입니다. 초기 페이지 로드 후, 클라이언트가 JS를 사용하여 데이터를 가져와 렌더링합니다.</p>
<p>SSR은 서버 측에서 초기 페이지 렌더링을 수행하고, 완성된 HTML을 클라이언트에게 전달하는 방식입니다. 페이지가 서버에서 렌더링되기 때문에 초기 로딩 시간이 단축되고 SEO에 유리합니다.</p>
<p>SSG(Static Site Generation)는 빌드 타임에 모든 페이지를 미리 렌더링하여 정적 파일(HTML, CSS, JS)로 생성합니다. 생성된 정적 파일들은 서버나 CDN을 통해 제공됩니다.</p>
<h3 id="ssr과-ssg의-차이">SSR과 SSG의 차이</h3>
<table>
<thead>
<tr>
<th>특성</th>
<th>SSR</th>
<th>SSG</th>
</tr>
</thead>
<tbody><tr>
<td>렌더링 시점</td>
<td>요청 시 서버에서 렌더링</td>
<td>빌드 시 미리 렌더링</td>
</tr>
<tr>
<td>초기 로드 속도</td>
<td>빠름</td>
<td>매우 빠름</td>
</tr>
<tr>
<td>데이터 최신성</td>
<td>최신 데이터 제공</td>
<td>빌드 시점 이후 데이터 반영 어려움</td>
</tr>
<tr>
<td>서버 부하</td>
<td>요청마다 서버 부하 있음</td>
<td>거의 없음</td>
</tr>
<tr>
<td>SEO</td>
<td>매우 좋음</td>
<td>매우 좋음</td>
</tr>
<tr>
<td>사용 사례</td>
<td>동적 컨텐츠, 사용자별 데이터가 많은 페이지</td>
<td>정적 컨텐츠, 자주 변경되지 않는 페이지</td>
</tr>
</tbody></table>
<p>SSR은 요청시마다 서버에서 HTML을 렌더링하므로 동적 컨텐츠에 적합합니다. 예를 들어, 사용자별로 다른 데이터를 보여줘야 하는 경우 대시보드나 사용자 프로필 페이지에 적합합니다. 또 SEO가 중요한 페이지 블로그나 뉴스 사이트 등에 적합합니다.</p>
<p>SSG는 빌드 타임에 모든 데이터를 미리 렌더링하여 정적 파일로 생성하므로 정적 컨텐츠가 많은 페이지 혹은 빠른 초기 로드가 중요한 페이지에 적합합니다.</p>
<h2 id="nextjs와의-비교-nextjs의-특징">Next.js와의 비교, Next.js의 특징</h2>
<p>Next.js는 React를 기반으로 한 프레임워크로, 서버 사이드 렌더링(SSR)과 정적 사이트 생성(SSG)을 포함한 다양한 기능을 제공합니다.</p>
<p>파일/폴더 기반 라우팅, 이미지 최적화, 자동 코드 분할 등의 기능을 제공합니다.</p>
<p>(Next는 SEO, 페이징이 중요할 때 주로 사용하고, React는 사용자 인터랙션이 중요할 때 주로 사용합니다.)</p>
<h3 id="코드-분할이란">코드 분할이란?</h3>
<p>코드 분할(Code Splitting)은 애플리케이션의 코드베이스를 여러 개의 작은 번들로 나누는 기법을 말합니다. 이 기법을 통해 초기 로드 시간을 줄이고, 사용자가 필요로 하는 코드만을 로드함으로써 네트워크 트래픽을 줄일 수 있습니다. 또한 코드를 더 작은 모듈로 나누어 유지보수가 쉽고 특정 기능이나 페이지의 변경이 전체 애플리케이션의 미치는 영향을 줄입니다. 또한 여러 개의 작은 파일을 병렬로 로드할 수 있어 더 빠르게 애플리케이션을 사용할 수 있습니다. 이러한 성능 이점으로 코드 분할은 특히 대규모 애플리케이션에서 중요한 성능 최적화 기술 중 하나입니다.</p>
<h3 id="nextjs의-image-컴포넌트를-사용하였을-때-기존-img-태그와-다른-점을-설명해주세요">Next.js의 Image 컴포넌트를 사용하였을 때 기존 img 태그와 다른 점을 설명해주세요.</h3>
<p>Next.js의 Image 컴포넌트를 사용하면 이미지 최적화를 자동으로 처리해 페이지 성능을 향상시킵니다. 또한 이미지 크기를 미리 알고 있기 때문에 레이아웃 시프트를 방지할 수 있고 이미지 로딩 전 홀더 이미지 설정으로 사용자 경험을 향상시킬 수 있습니다.</p>
<h4 id="레이아웃-시프트layout-shift란">레이아웃 시프트(Layout Shift)란?</h4>
<p>이미지가 로드되기 전과 후에 페이지의 레이아웃이 변경되는 현상을 의미합니다. 이는 사용자 경험에 악영향을 미칠 수 있으며, 특히 이미지가 많은 페이지에서 문제가 됩니다.</p>
<h3 id="hydration이란">Hydration이란?</h3>
<p>Next.js에서 서버사이드 렌더링을 하기 전 초기 상태를 적용하는 과정을 말합니다. 서버에서 렌더링된 HTML을 클라이언트로 전달하고, 클라이언트에서 JavaScript가 실행되면서 초기 상태를 클라이언트와 동기화하는 과정을 말합니다.</p>
<h2 id="⭐️-flux-패턴이란">⭐️ Flux 패턴이란?</h2>
<p>Flux 패턴은 Facebook에서 만든 아키텍처 패턴으로, React에서 데이터의 흐름을 관리하는 데 사용됩니다. Flux는 단방향 데이터 흐름을 특징으로 하며, Action -&gt; Dispatcher -&gt; Store -&gt; View의 흐름을 따릅니다. View에서 사용자가 상호작용하면 Action이 Dispatcher를 통해 전파되고, Store는 Action을 처리하여 View를 갱신합니다. 이 패턴은 React의 선언형 프로그래밍 스타일과 잘 맞아 데이터 변경을 명확하게 처리할 수 있습니다.</p>
<h3 id="단방향-패턴의-장단점">단방향 패턴의 장단점?</h3>
<p>단방향 데이터 흐름 패턴의 장점은 데이터가 항상 한 방향으로 흐르기 때문에 상태 변화의 흐름을 예측 가능하고 쉽게 추적할 수 있어 디버깅과 문제 해결에 용이합니다. 또 상태 관리가 명확하게 이루어져 코드의 가독성과 유지보수성이 향상됩니다. 각 컴포넌트는 자신의 상태와 props만 신경쓰면 됩니다. 또한 상태가 중앙에서 관리되므로 상태 변경이 일관되게 관리되어 데이터의 일관성이 유지될 수 있습니다. 추가로 상태와 뷰가 명확하게 분리되어 있어 개별 컴포넌트의 테스트가 쉬워집니다.</p>
<p>단점은 설정과 보일러플레이트 코드가 많을 수 있으며, 초기 학습 곡선이 존재합니다.</p>
<h3 id="⭐️-다른-디자인-패턴과의-비교">⭐️ 다른 디자인 패턴과의 비교</h3>
<ol>
<li><p>MVC (Model-View-Controller)
MVC 패턴은 애플리케이션을 모델, 뷰, 컨트롤러의 세 가지 주요 컴포넌트로 분리합니다. 모델은 데이터와 비즈니스 로직을 관리하고, 뷰는 사용자 인터페이스를 관리하며, 컨트롤러는 모델과 뷰 사이의 상호작용을 관리합니다.</p>
<ul>
<li>장점: 코드의 관심사를 분리하여 유지보수성과 재사용성을 높입니다.</li>
<li>단점: 컴포넌트 간의 상호작용이 복잡해질 수 있으며, 특히 대규모 애플리케이션에서 컨트롤러가 비대해질 수 있습니다.</li>
</ul>
</li>
<li><p>MVVM (Model-View-ViewModel)
MVVM 패턴은 모델, 뷰, 뷰모델로 구성됩니다. 뷰모델은 뷰와 모델 사이의 데이터 바인딩을 관리하여 뷰가 모델의 상태 변화를 쉽게 반영할 수 있게 합니다.</p>
<ul>
<li>장점: 데이터 바인딩을 통해 뷰와 모델 간의 상호작용을 단순화하고, 뷰와 모델의 분리를 강화합니다.</li>
<li>단점: 데이터 바인딩이 과도하게 사용되면 디버깅이 어려워질 수 있습니다.</li>
</ul>
</li>
<li><p>Redux
Redux는 Flux 패턴에서 발전한 상태 관리 라이브러리로, 단일 스토어와 순수 함수인 리듀서(Reducer)를 사용합니다.</p>
<ul>
<li>장점: 상태 변화가 예측 가능하며, 중간 상태를 쉽게 추적하고 디버깅할 수 있습니다.</li>
<li>단점: 설정과 보일러플레이트 코드가 많을 수 있으며, 초기 학습 곡선이 존재합니다.</li>
</ul>
</li>
</ol>
<h3 id="단방향-바인딩-양방향-바인딩-차별점-말해주세요">단방향 바인딩, 양방향 바인딩 차별점 말해주세요.</h3>
<p>단방향 바인딩은 데이터가 한 방향으로 흐르고, 양방향 바인딩은 데이터가 양방향으로 흐르는 차이가 있습니다. 단방향 바인딩은 주로 모델에서 뷰로 데이터가 전달되고 뷰의 변경은 모델의 영향을 주지 않지만 양방향 바인딩은 모델, 뷰 모두 서로가 영향을 줍니다. 따라서 단방향 바인딩이 데이터 흐름이 단방향이기때문에 디버깅이 용이하고 코드의 복잡성이 낮습니다. 양방향 바인딩은 이러한 것이 상대적으로 어렵지만, 사용자 인터페이스 반응성이 더 높습니다. 양방향 데이터 바인딩을 제공하는 것은 Angular, Vue.js가 있습니다.</p>
<h3 id="선언적-프로그래밍과-명령형-프로그래밍의-차이를-아시나요">선언적 프로그래밍과 명령형 프로그래밍의 차이를 아시나요?</h3>
<p>선언적 프로그래밍 (Declarative Programming)은 “무엇을” 수행할 것인지를 기술하는 프로그래밍 패러다임입니다. 즉, 원하는 결과가 무엇인지를 설명하고, 그것을 어떻게 수행할지는 명시하지 않습니다. 예를 들어 함수형 프로그래밍, SQL, 리액트 등이 있습니다.</p>
<p>명령형 프로그래밍(Imperative Programming)은 “어떻게” 수행할 것인지를 기술하는 프로그래밍 패러다임입니다. 즉, 프로그램이 수행할 일련의 절차나 단계를 명령어로 명확하게 기술합니다.</p>
<h3 id="함수형-프로그래밍이란">함수형 프로그래밍이란?</h3>
<p>함수형 프로그래밍은 함수를 일급 시민으로 취급하고, 부작용을 피하며, 순수 함수를 선호하는 선언적 프로그래밍 방식입니다.</p>
<h2 id="⭐️-react의-생명-주기에-대해-설명하세요">⭐️ React의 생명 주기에 대해 설명하세요.</h2>
<p>리액트의 생명주기는 마운트(mount), 업데이트(updated), 언마운트(unmount) 크게 세단계로 분류됩니다.
마운트는 컴포넌트가 처음 DOM에 삽입되는 단계를 말하고, 업데이트는 컴포넌트가 다시 렌더링될 때 발생하는 단계입니다. 주로 props나 상태 변화에 의해 트리거됩니다. 마지막으로 컴포넌트가 DOM에서 제거되는 단계를 언마운트라고 합니다.</p>
<h3 id="⭐️-리액트에서-이러한-생명주기를-사용하는-이유는">⭐️ 리액트에서 이러한 생명주기를 사용하는 이유는?</h3>
<p>리액트에서 생명주기 메서드를 사용하는 이유는 컴포넌트의 생성, 업데이트, 제거 시점을 효과적으로 관리하기 위해서입니다.
업데이트를 통해 UI를 최신 상태로 유지하고 컴포넌트가 제거될 때 타이머나 구독을 정리하여 메모리 누수를 방지합니다. 또한 불필요한 리렌더링을 방지하여 성능을 개선합니다. 즉, 생명주기 메서드는 컴포넌트의 상태를 관리하고, 성능을 최적화하며, 자원을 적절히 정리하는 데 도움을 줍니다.</p>
<h3 id="⭐️-리액트에서-말고-소프트웨어-전반에서-사용되는-생명주기-개념에-대해-아시나요">⭐️ 리액트에서 말고 소프트웨어 전반에서 사용되는 생명주기 개념에 대해 아시나요?</h3>
<p>생명주기는 소프트웨어가 시작되고, 성장하며, 유지되고, 결국에는 종료되는 과정을 말합니다. 즉 소프트웨어가 처음 개발되기부터, 배포, 유지보수까지의 전체 과정을 말합니다.</p>
<p>주로 &#39;요구사항 분석 -&gt; 설계 -&gt; 개발 -&gt; 테스트 -&gt; 배포 -&gt; 유지보수&#39; 과정을 따릅니다.</p>
<p>이러한 생명주기 단계는 소프트웨어가 안정적이고 효과적으로 운영될 수 있도록 보장해줍니다. 계속해서 개선하고 문제를 해결하면서 소프트웨어의 품질과 사용자 만족도를 유지하는 데 필수적입니다.</p>
<h2 id="⭐️-리액트-훅이란">⭐️ 리액트 훅이란?</h2>
<p>리액트 훅이란 함수형 컴포넌트에서 상태와 생명주기 메서드를 사용할 수 있도록 해주는 기능입니다. React 16.8에서 도입된 훅은 클래스형 컴포넌트의 복잡한 구조를 피하고, 함수형 컴포넌트를 이용해 더 간결하고 직관적인 코드를 작성할 수 있게 합니다.</p>
<h3 id="react-주요-훅">React 주요 훅</h3>
<ol>
<li><p><strong>useState</strong>:</p>
<ul>
<li><strong>상태 변수를 선언하고, 해당 변수를 갱신할 수 있는 함수도 반환</strong>합니다.</li>
</ul>
<pre><code class="language-jsx">const [count, setCount] = useState(0);</code></pre>
<ul>
<li><code>count</code>는 상태 변수, <code>setCount</code>는 상태를 갱신하는 함수입니다.</li>
</ul>
</li>
<li><p><strong>useEffect</strong>:</p>
<ul>
<li><strong>컴포넌트가 렌더링된 이후에 실행될 부수 효과(side effects)를 수행</strong>합니다. 예를 들어, <strong>데이터 페칭, 구독(subscription) 설정</strong> 등이 있습니다.</li>
</ul>
<pre><code class="language-jsx">useEffect(() =&gt; {
  document.title = `You clicked ${count} times`;
}, [count]);</code></pre>
<ul>
<li><strong>첫 번째 인자는 수행할 함수, 두 번째 인자는 의존성 배열</strong>입니다. <strong>배열에 포함된 값이 변경될 때마다 이 함수가 실행</strong>됩니다.</li>
</ul>
</li>
<li><p><strong>useContext</strong>:</p>
<ul>
<li>컴포넌트 트리 전체에서 데이터를 공유할 수 있게 해주는 Context API를 사용합니다.</li>
</ul>
<pre><code class="language-jsx">const value = useContext(MyContext);</code></pre>
</li>
<li><p><strong>useReducer</strong>:</p>
<ul>
<li>상태 관리 로직을 더 세밀하게 제어할 수 있게 해줍니다. <code>useState</code>의 대안으로, 복잡한 상태 로직을 다룰 때 유용합니다.</li>
</ul>
<pre><code class="language-jsx">const [state, dispatch] = useReducer(reducer, initialState);</code></pre>
</li>
<li><p><strong>useCallback</strong>:</p>
<ul>
<li><strong>메모이제이션된 콜백 함수를 반환하여, 컴포넌트가 리렌더링될 때마다 동일한 함수를 생성하지 않도록 합니다.</strong></li>
</ul>
<pre><code class="language-jsx">const memoizedCallback = useCallback(() =&gt; {
  doSomething(a, b);
}, [a, b]);</code></pre>
</li>
<li><p><strong>useMemo</strong>:</p>
<ul>
<li><strong>메모이제이션된 값을 반환하여, 컴포넌트가 리렌더링될 때마다 동일한 값을 생성하지 않도록 합니다</strong>.</li>
</ul>
<pre><code class="language-jsx">const memoizedValue = useMemo(() =&gt; computeExpensiveValue(a, b), [a, b]);</code></pre>
</li>
<li><p><strong>useRef</strong>:</p>
<ul>
<li><strong>변경 가능한 ref 객체를 생성</strong>하여, <strong>DOM 요소나 클래스 인스턴스 같은 것을 참조</strong>할 수 있습니다.</li>
</ul>
</li>
</ol>
<h2 id="⭐️-프로젝트에서-상태관리-어떻게-하셨나요">⭐️ 프로젝트에서 상태관리 어떻게 하셨나요?</h2>
<p>프로젝트시 사용자 로그인 정보 등 전역 상태 관리가 필요한 데이터가 생겨 다양한 전역 상태 관리 라이브러리를 고민했습니다. 그 중 팀원간 협의를 거쳐 Zustand를 사용했습니다. 그 이유는 팀원간 공통적으로 사용할 수 있는 상태 관리 라이브러리가 없어 새로운 라이브러리를 선택해야 했고 ContextAPI, RTX 등 다양한 라이브러리를 고민하다 짧은 프로젝트 기간 내 가장 간단하고 직관적인 문법으로 쉽게 사용할 수 있고, 보일러플레이트 코드도 없어 간편한 Zustand를 사용했습니다.</p>
<h2 id="react에서-리렌더링되는-3가지-조건">React에서 리렌더링되는 3가지 조건</h2>
<ol>
<li>부모 컴포넌트 리렌더링될 때</li>
<li>props가 변경될 때</li>
<li>state가 변경될 때</li>
</ol>
<h2 id="⭐️-props와-state의-차이점">⭐️ Props와 State의 차이점</h2>
<p>Props는 부모 컴포넌트에서 자식 컴포넌트로 전달되는 데이터입니다. 이는 읽기 전용입니다.</p>
<p>State는 컴포넌트 내부에서 관리되는 동적인 데이터를 의미합니다. 컴포넌트 내부에서 변경 가능합니다.</p>
<h2 id="props-drilling이란">Props Drilling이란?</h2>
<p>Props Drilling은 React 애플리케이션에서 부모 컴포넌트로부터 자식 컴포넌트로 데이터나 함수를 전달할 때 발생하는 문제를 의미합니다. 이는 데이터나 콜백 함수가 여러 계층의 컴포넌트를 통해 깊게 전달될 때 발생합니다.</p>
<p>Props Drilling은 컴포넌트 간의 의존성을 증가시키고 재사용성을 감소시킵니다. 또한 구조가 복잡해져 유지보수가 어려워질 수 있습니다.</p>
<p>컴포넌트 구조를 재설계해 props drilling을 줄이거나 Context API, Redux 등의 상태 관리 라이브러리를 사용해 해결할 수 있습니다.</p>
<h2 id="⭐️-리액트에서-성능-최적화를-위해-사용할-수-있는-최적화-도구에-대해-아는대로-설명해주세요">⭐️ 리액트에서 성능 최적화를 위해 사용할 수 있는 최적화 도구에 대해 아는대로 설명해주세요.</h2>
<p>리액트 확장 프로그램(React Dev Tools)을 이용하여 색상으로 렌더링 빈도를 확인하고 불필요한 리렌더링이 발생하지 않도록 최적화할 수 있습니다. 또한 Lighthouse를 통해 성능, 웹 접근성, SEO, 초기 렌더링 시간, 권장 사항 등을 확인하고 이를 최적화할 수 있습니다.</p>
<hr>
<blockquote>
<p>💬 실제 면접 경험을 공유하자면 암기식 기술 질문을 계속 하는 곳도 있고 그런 질문 하나 없이 프로젝트 기반 질문만 하는 곳도 있었습니다.
제가 느끼기에는 자신이 한 프로젝트, 사용한 기술 기반으로 꼬리 질문을 준비하는 것이 제일 중요하고 나머지는 회사마다 차이가 크다고 느꼈습니다.
실제로 &#39;리액트가 뭔가요?&#39; 같은 질문은 받은 적이 없고 동작 원리를 이해하는 부분은 중요하다고 생각합니다. 기본 질문 외에 답변도 프로젝트 경험에 따라 달라질 수 있으니 참고해주세요.</p>
</blockquote>
<blockquote>
<p>추가하면 좋은 부분이나 잘못된 점이 있다면 댓글 남겨주세요. 감사합니다 :)</p>
</blockquote>
<hr>
<h2 id="참고-자료">참고 자료</h2>
<h3 id="📌-면접-준비-참고하기-좋은-영상">📌 면접 준비 참고하기 좋은 영상</h3>
<p><a href="https://www.youtube.com/watch?v=ZJR6WtDXCr4">bluevulpe블루불페 - 프론트엔드 주니어 기술 면접 답변 회고(feat.2023상반기이직준비)</a></p>
<p><a href="https://www.youtube.com/watch?v=XWqs1mMPJ30&amp;ab_channel=%ED%94%84%EB%A1%A0%ED%8A%B8%EB%A7%A8">프론트맨 - 프론트엔드 기술 면접 단골 질문</a></p>
<p><a href="https://www.youtube.com/watch?v=vR87GdV3VlA&amp;t=6s">라메개발자 - 프론트엔드 개발자 취업을 위한 면접 경험 공유 | 스타트업 | 대기업</a></p>
<p><a href="https://www.youtube.com/watch?v=SrFsloH10AA">인디스워크 - 프론트엔드 리드가 알려주는 개발자 채용과 면접 진행 방법</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] useEffect에 대한 오해, 리액트 생명주기, strictMode]]></title>
            <link>https://velog.io/@hi-rachel/React-useEffect%EC%97%90-%EB%8C%80%ED%95%9C-%EC%98%A4%ED%95%B4-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-strictMode</link>
            <guid>https://velog.io/@hi-rachel/React-useEffect%EC%97%90-%EB%8C%80%ED%95%9C-%EC%98%A4%ED%95%B4-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-strictMode</guid>
            <pubDate>Tue, 18 Jun 2024 09:29:16 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hi-rachel/post/77e6f9fd-7a8e-4665-85ec-7cd0d0a9d2d5/image.png" alt=""></p>
<blockquote>
<p>프론트엔드 공부하는 친구들과 얘기하다 보면 너무도 자주 사용하는 useEffect에 대해서 종종 오해하고 있는 경우가 있다고 생각했다. 그래서 한 번 정리해봤다.</p>
</blockquote>
<hr>
<h2 id="useeffect-개념">useEffect 개념</h2>
<p><strong>useEffect는 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook</strong>이다.</p>
<pre><code class="language-javascript">useEffect(setup, dependencies?)</code></pre>
<h3 id="마운트될-때만-실행하고-싶을-때">마운트될 때만 실행하고 싶을 때</h3>
<p>useEffect에서 설정한 함수를 컴포넌트가 맨 처음 렌더링될 때만 실행하고, 업데이트될 때는 실행하지 않으려면 함수의 두 번째 파라미터로 빈 배열을 넣어주면 된다.</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(&quot;마운트 될 때만 실행됩니다.&quot;);
}, []);</code></pre>
<h3 id="특정-값이-업데이트-될-때만-실행하고-싶을-때">특정 값이 업데이트 될 때만 실행하고 싶을 때</h3>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(name);
}, [name]);</code></pre>
<p>useEffect의 두 번째 파라미터로 전달되는 배열 안에 검사하고 싶은 값(의존 값)을 넣어 주면 된다. 빈 배열이나 의존 값이 들어있는 배열을 거의 넣고, 배열을 아예 생략하는 상황은 드물다.</p>
<h3 id="뒷정리">뒷정리</h3>
<p>useEffect는 기본적으로 렌더링되고 난 직후마다 실행되며, 두 번쨰 파라미터 배열에 무엇을 넣는지에 따라 실행되는 조건이 다르다.
컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 어떠한 작업을 수행하고 싶다면 useEffect에서 뒷정리(cleanup) 함수를 반환해 주어야 한다.</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(&quot;effect&quot;);
  consoel.log(name);
  return () =&gt; {
    console.log(&quot;cleanup&quot;);
    console.log(name);
  };
});</code></pre>
<p>위 코드의 콘솔로그 순서는</p>
<ol>
<li>컴포넌트가 처음 업데이트 될때</li>
</ol>
<pre><code>   effect
   name
   effect
   name</code></pre><ol start="2">
<li>컴포넌트가 리렌더링될 때</li>
</ol>
<pre><code>   cleanup
   name
   effect
   name
   cleanup
   name
   effect
   name</code></pre><ol start="3">
<li>컴포넌트가 언마운트될 때<pre><code>cleanup
name
cleanup
name</code></pre></li>
</ol>
<p>위 출력은 모두 개발 환경에서 두 번씩 찍힌 예시이고 아래 오해, 사용법에 이유를 적어놨다.</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
  console.log(&quot;effect&quot;);
  return () =&gt; {
    console.log(&quot;cleanup&quot;);
  };
}, []);</code></pre>
<p>오직 언마운트될 때만 뒷정리 함수를 호출하고 싶다면 useEffect 함수의 두 번째 파라미터에 비어있는 배열을 넣으면 된다.</p>
<hr>
<h3 id="리액트-컴포넌트의-생명주기---마운트-업데이트-언마운트">리액트 컴포넌트의 생명주기 - 마운트, 업데이트, 언마운트</h3>
<p><strong>마운트</strong>
: 컴포넌트가 처음 DOM에 삽입되는 단계.</p>
<p>함수형 컴포넌트에서의 예시</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
  // 마운트 시 실행될 코드
}, []);</code></pre>
<p><strong>업데이트</strong>
: 컴포넌트가 <strong>다시 렌더링</strong>될 때 발생하는 단계. 주로 props나 state 변화에 의해 트리거된다.</p>
<p>함수형 컴포넌트</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
  // 특정 값이 변경될 때 실행될 코드
}, [특정 값]);</code></pre>
<p><strong>언마운트</strong>
: 컴포넌트가 DOM에서 제거되는 단계.</p>
<pre><code class="language-javascript">useEffect(() =&gt; {
  return () =&gt; {
    // 언마운트 시 실행될 코드
  };
}, []);</code></pre>
<blockquote>
<p>클래스형 컴포넌트의 생명주기 메서드는 다르지만 여기서는 다루지 않겠다.</p>
</blockquote>
<hr>
<h3 id="useeffect에-대한-오해-사용법">useEffect에 대한 오해, 사용법</h3>
<ol>
<li><p><strong>useEffect는 컴포넌트의 최상위 수준이나 자체 Hook에서만 호출</strong>할 수 있다. 루프나 조건 내에서는 호출할 수 없다.</p>
</li>
<li><p><strong>React.StrictMode 모드에서 2번 실행</strong>
React.StrictMode가 적용된 개발 환경이면 useEffect를 사용한 코드에 문제가 있는지 없는지를 감지하기 위하여 두 번 실행이 된다.
<strong>이는 미래의 리액트에서는 컴포넌트가 사라졌다가 다시 나타나도 컴포넌트의 상태를 유지하는 기능을 도입할 예정인데, 컴포넌트가 나타날 때 useEffect가 두 번 실행이 되어도 컴포넌트 작동 방식에 문제가 없어야 추후 호환이 정상적으로 이뤄지기 때문이다.</strong> 이는 개발환경에서만 일어나는 현상이다.</p>
<p>-&gt; 이를 모르면 오해를 하기 쉬운데 useEffect 2번 작동이 문제가 있다거나, strict 모드를 없애야 한다 등 ..
하지만 위에 언급한 것처럼 이는 미래의 작동을 위해 일부러 2번이 작동하게 하는 스트레스 테스트일 뿐이다. 2번 실행을 하고 싶지 않다면 React.StrictMode를 쓰지 않거나 useEffect를 쓰지 않는 방법이 있다.</p>
<blockquote>
<p>정리하면
useEffect가 2번 작동하는건 잘못된게 아니다. 일부러 미래의 작동 방식을 위해 2번 작동하게 만들어둔거다.
strictMode일 때, 개발 환경일 때만 2번 작동한다.</p>
</blockquote>
<p>나는 프로젝트에서 로그인 부분을 구현시 토큰 요청을 useEffect로 보낼때 백엔드 로직에서 2번 요청을 연속적으로 받으면 종종 토큰이 제대로 인식이 안되는 문제가 있어서 react query 요청으로 바꿔 해결한 경험이 있다. 👉 <a href="https://velog.io/@hi-rachel/Slam-Talk-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-accessToken-%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0-ae6jx5nv">해당 글</a></p>
<p>React.StrictMode를 안쓰고 싶다면 다음과 같은 StrictMode가 있는 이유를 인식하고, 이러한 기능이 필요없다면 없애면 된다.</p>
<pre><code class="language-javascript">import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom&quot;;
import App from &quot;./App&quot;;

ReactDOM.render(
 &lt;React.StrictMode&gt;
   &lt;App /&gt;
 &lt;/React.StrictMode&gt;,
 document.getElementById(&quot;root&quot;)
);</code></pre>
<blockquote>
<p><strong>React.StrictMode</strong>
리액트 애플리케이션에서 잠재적인 문제를 감지하고, 안정성과 최적화를 위해 일부 기능을 활성화하는 개발 도구이다. 컴포넌트 렌더링이나 프로덕션 빌드에 영향을 미치지 않는다. 개발 중에 문제를 감지해 경고를 출력한다.</p>
<p><strong>주요 기능</strong></p>
<ul>
<li>중복 함수 호출: React.StrictMode는 개발 모드에서 일부 함수 컴포넌트의 효과와 라이프사이클 메서드를 두 번 호출한다. 이는 순수 함수의 순수성, 부작용 검사, 버그 조기 발견을 돕는다.</li>
<li>안전한 라이프사이클 메서드 사용: 사용하지 않는 또는 권장되지 않는 라이프사이클 메서드 사용에 대한 경고를 출력한다.</li>
<li>경고 활성화: 잠재적인 문제(예: 레거시 문자열 ref 사용, UNSAFE_로 시작하는 메서드 사용 등)에 대한 경고를 출력한다.</li>
<li>레거시 API 확인: StrictMode는 레거시 API의 사용을 감지하고 경고한다. 이는 향후 리액트 버전에서 호환되지 않을 수 있다.</li>
<li>불변성 확인: React가 의도한 방식대로 상태와 props를 불변하게 처리하지 않을 때 경고합니다.</li>
</ul>
<p>개발시 안정성과 성능 최적화, 미래 호환 확인을 해주는 도구이다.</p>
</blockquote>
<p>위와 같은 장점으로 StrictMode를 빼고 개발한 적은 없고, 이유가 없다면 굳이 안쓸 이유는 없다고 생각한다.</p>
</li>
<li><p>useEffect는 빈 배열을 명시하고 렌더링할 때마다 실행해야 하는 특정 로직이 있을때 주로 사용하는데 가끔 useEffect가 필요없이 불러오면 되는 코드에도 쓰는걸 발견할 때가 있다. 동작 원리를 이해하고 불필요한 상황에서의 사용을 피하자.</p>
</li>
</ol>
<hr>
<h3 id="참고-자료">참고 자료</h3>
<p>김민준, 『리액트를 다루는 기술(개정판)』, 길벗(2023)</p>
<p><a href="https://react.dev/reference/react/useEffect">https://react.dev/reference/react/useEffect</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[우아한 타입스크립트 with 리액트] - 6장. 타입스크립트 컴파일]]></title>
            <link>https://velog.io/@hi-rachel/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-with-%EB%A6%AC%EC%95%A1%ED%8A%B8-6%EC%9E%A5.-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BB%B4%ED%8C%8C%EC%9D%BC</link>
            <guid>https://velog.io/@hi-rachel/%EC%9A%B0%EC%95%84%ED%95%9C-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-with-%EB%A6%AC%EC%95%A1%ED%8A%B8-6%EC%9E%A5.-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%BB%B4%ED%8C%8C%EC%9D%BC</guid>
            <pubDate>Fri, 07 Jun 2024 07:00:10 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>우아한형제들 웹프론트엔드개발그룹, 『<a href="https://www.aladin.co.kr/m/mproduct.aspx?ItemId=327063952">우아한 타입스크립트 with 리액트</a>』, 한빛미디어(2023) p.184 ~ 198
해당 책을 읽고 공부하며 관련 내용을 정리한 글입니다.</p>
</blockquote>
<h2 id="61-자바스크립트의-런타임과-타임스크립트의-컴파일">6.1 자바스크립트의 런타임과 타임스크립트의 컴파일</h2>
<h4 id="1-런타임과-컴파일타임">1. 런타임과 컴파일타임</h4>
<p><strong>컴파일 타임: 소스코드가 컴파일 과정을 거쳐 컴퓨터가 인식할 수 있는 기계어 코드(바이트 코드)로 변환되어 실행할 수 있는 프로그램이 되는 과정</strong></p>
<p><strong>런타임: 소스코드의 컴파일이 완료되면 프로그램이 메모리에 적재되어 실행되는데 이 시간을 말함.</strong></p>
<h4 id="2-자바스크립트-런타임">2. 자바스크립트 런타임</h4>
<blockquote>
<p>= <strong>자바스크립트가 실행되는 환경</strong>
ex_크롬, 사파리 등의 인터넷 브라우저, Node.js
주요 구성 요소: <strong>자바스크립트 엔진, 웹 API, 콜백 큐, 이벤트 루프, 렌더 큐</strong></p>
</blockquote>
<h4 id="3-타입스크립트의-컴파일">3. 타입스크립트의 컴파일</h4>
<p><strong>tsc라는 컴파일러를 통해 자바스크립트 코드로 변환</strong>. 고수준(ts) -&gt; 고수준(js) 언어로 변환되는 것이기 때문에 <strong>트랜스파일(Transpile)</strong>이라고 부르기도 한다.</p>
<h4 id="타입스크립트-컴파일러가-소스코드를-컴파일하여-프로그램이-실행되기까지의-과정">타입스크립트 컴파일러가 소스코드를 컴파일하여 프로그램이 실행되기까지의 과정</h4>
<ol>
<li>타입스크립트 소스코드를 타입스크립트 AST로 만든다. (tsc)</li>
<li>타입 검사기가 AST를 확인하여 타입을 확인한다. (tsc)</li>
<li>타입스크립트 AST를 자바스크립트 소스로 변환한다. (tsc)</li>
<li>자바스크립트 소스코드를 자바스크립트 AST로 만든다. (런타임)</li>
<li>AST가 바이트 코드로 변환된다. (런타임)</li>
<li>런타임에서 바이트 코드가 평가(evaluate)되어 프로그램이 실행된다. (런타임)</li>
</ol>
<p>=&gt; 💡 개발자가 작성한 타입 정보는 1, 2단계에서만 사용된다. <strong>즉, 개발자가 작성한 타입 정보는 단지 타입을 확인하는 데만 쓰이며, 최종적으로 만들어지는 프로그램에는 아무 영향을 주지 않는다.</strong></p>
<p>컴파일 타임에 타입을 검사하기 때문에 에러가 발생하면 프로그램이 실행되지 않고, 이러한 특징으로 <strong>정적 타임 검사기</strong>라고 부른다.</p>
<blockquote>
<p>📍 <strong>용어 정리</strong>
<strong>AST(Abstract Syntax Tree)</strong>
: 컴파일러가 소스코드를 해석하는 과정에서 생성된 데이터 구조. 컴파일러는 어휘적 분석과 구문 분석을 통해 소스코드를 노드 단위의 트리 구조로 구성한다.</p>
</blockquote>
<blockquote>
<p><strong>어휘적 분석 (Lexical Analysis)</strong>
: 소스 코드를 토큰으로 분리하는 과정.</p>
<p><strong>구문적 분석 (Syntactic Analysis)</strong>
: 어휘적 분석에서 생성된 토큰을 <strong>구문 트리(Syntax Tree)</strong>나 <strong>추상 구문 트리(Abstract Syntax Tree, AST)</strong>로 변환하는 과정.
&quot;구문적&quot;이라는 단어는 언어의 구조(문법)를 다루는 것을 의미. 토큰들이 언어의 문법 규칙에 맞게 적절히 배치되어 있는지 확인하고, 그 구조를 분석.</p>
<p><strong>토큰 (Token)</strong>
: <strong>소스 코드에서 의미 있는 가장 작은 단위.</strong>
컴파일러의 어휘 분석 단계에서 소스 코드의 연속된 문자들을 그룹화하여 생성.
종류: <strong>키워드, 식별자, 리터럴, 연산자, 구두점 등</strong></p>
</blockquote>
<h2 id="62-타입스크립트-컴파일러의-동작">6.2 타입스크립트 컴파일러의 동작</h2>
<h4 id="타입스크립트-컴파일러의-역할">타입스크립트 컴파일러의 역할</h4>
<h4 id="1-코드-검사기-코드에-타입-오류-확인">1. 코드 검사기: 코드에 타입 오류 확인</h4>
<ul>
<li>컴파일타임에 문법 에러와 타입 관련 에러를 모두 검출</li>
</ul>
<h4 id="2-코드-변환기-구버전의-자바스크립트로-트랜스파일">2. 코드 변환기: 구버전의 자바스크립트로 트랜스파일</h4>
<ul>
<li>target 옵션을 사용하여 특정 버전의 JS로 컴파일 가능</li>
</ul>
<h2 id="63-타입스크립트-컴파일러의-구조">6.3 타입스크립트 컴파일러의 구조</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/73f7f980-4320-4748-9214-eaba69ad557a/image.png" alt=""></p>
<p><a href="https://github.com/microsoft/TypeScript/tree/main">https://github.com/microsoft/TypeScript/tree/main</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ES6 모듈]]></title>
            <link>https://velog.io/@hi-rachel/ES6-%EB%AA%A8%EB%93%88</link>
            <guid>https://velog.io/@hi-rachel/ES6-%EB%AA%A8%EB%93%88</guid>
            <pubDate>Fri, 31 May 2024 09:35:30 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>모듈이란?</strong>
: 🌟 <strong>프로그램을 구성하는 시스템을 기능 단위로 독립적인 부분으로 분리한 것</strong></p>
<ul>
<li>하나 이상의 논리적인 기능을 수행하기 위한 명령어들의 집합
ex_독립적인 프로그램 그 자체 혹은 함수나 메서드 등</li>
</ul>
</blockquote>
<hr>
<h2 id="자바스크립트-모듈">자바스크립트 모듈</h2>
<p><img src="https://velog.velcdn.com/images/hi-rachel/post/fbf94c32-2a84-49da-9707-7218d571a2c5/image.jpeg" alt=""></p>
<p>ES6 모듈(ECMAScript 2015 모듈)은 자바스크립트에서 코드를 모듈 단위로 분리하고 관리할 수 있게 해주는 시스템.
모듈을 사용하면 코드를 재사용 가능하고, 유지보수가 쉬우며, 네임스페이스 충돌을 피할 수 있다. ES6 모듈은 import와 export 구문을 사용하여 모듈 간에 기능을 공유.</p>
<h3 id="주요-특징">주요 특징</h3>
<ul>
<li><p><strong>정적인 구조</strong>: ES6 모듈은 정적으로 분석된다. 즉, 🌟 <strong>모듈의 구조와 의존성</strong>은 런타임이 아닌 <strong>컴파일 타임에 결정</strong>됨. 이를 통해 <strong>더 효율적인 트리 쉐이킹(tree-shaking)이 가능</strong>해진다.</p>
</li>
<li><p><strong>엄격 모드(Strict mode)</strong>: <strong>모든 ES6 모듈은 기본적으로 Strict 모드에서 실행</strong>된다. 별도로 &quot;use strict&quot;;를 선언할 필요가 없다.</p>
</li>
<li><p><strong>파일 단위 모듈</strong>: 각 파일은 자체적으로 모듈 스코프를 가진다. 따라서, 파일 내에서 선언된 변수는 해당 파일 내부에서만 유효하며, 다른 파일과 충돌하지 않는다.</p>
</li>
</ul>
<hr>
<h3 id="모듈-내보내기-export">모듈 내보내기 (Export)</h3>
<p>export 키워드를 사용하여 다른 모듈에서 사용할 수 있도록 기능(변수, 함수, 클래스 등)을 내보낼 수 있다.</p>
<ul>
<li>export의 두 가지 주요 유형</li>
</ul>
<h3 id="named-export">Named Export</h3>
<p><strong>여러 개</strong>의 이름을 지정하여 내보낼 수 있음. 모듈에서 필요한 것만 선택적으로 가져올 수 있음.</p>
<pre><code class="language-javascript">export const pi = 3.14159;

export function add(a, b) {
  return a + b;
}

export class Circle {
  constructor(radius) {
    this.radius = radius;
  }

  area() {
    return pi * this.radius * this.radius;
  }
}</code></pre>
<h3 id="default-export">Default Export</h3>
<p>모듈에서 <strong>하나</strong>의 기본 값을 내보낼 수 있다. 모듈을 가져올 때 이름을 지정하지 않고 임의의 이름을 사용할 수 있다.</p>
<pre><code class="language-javascript">export default class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return `Hello, my name is ${this.name}`;
  }
}</code></pre>
<hr>
<h3 id="모듈-가져오기-import">모듈 가져오기 (Import)</h3>
<p>import 키워드를 사용하여 다른 모듈에서 내보낸 기능을 가져올 수 있다.</p>
<h3 id="named-import">Named Import</h3>
<p>특정 이름으로 내보낸 기능을 가져온다. 중괄호를 사용하여 가져올 항목을 명시.</p>
<pre><code class="language-javascript">mport { pi, add, Circle } from &#39;./math.js&#39;;

console.log(pi); // 3.14159
console.log(add(2, 3)); // 5

const circle = new Circle(5);
console.log(circle.area()); // 78.53975</code></pre>
<h3 id="default-import">Default Import</h3>
<p>기본 값을 가져올 때는 임의의 이름을 사용할 수 있다.</p>
<pre><code class="language-javascript">import Person from &quot;./person.js&quot;;

const john = new Person(&quot;John&quot;);
console.log(john.greet()); // Hello, my name is John</code></pre>
<pre><code class="language-javascript">import { pi as PI, add as sum } from &quot;./math.js&quot;;

console.log(PI); // 3.14159
console.log(sum(2, 3)); // 5</code></pre>
<p>가져올 때 이름을 변경 가능.</p>
<h3 id="동적-import">동적 import</h3>
<p>import() 함수는 동적으로 모듈을 가져올 수 있게 한다. 이는 <strong>비동기적으로 작동</strong>하며, 주로 <strong>조건부 로딩이나 코드 스플리팅에 사용</strong>된다.</p>
<pre><code class="language-javascript">import(&quot;./math.js&quot;).then((math) =&gt; {
  console.log(math.pi); // 3.14159
  console.log(math.add(2, 3)); // 5
});</code></pre>
<hr>
<h2 id="결론">결론</h2>
<p>ES6 모듈은 <strong>코드의 모듈화를 통해 재사용성과 유지보수성을 높여준다</strong>. <strong>export와 import 키워드</strong>를 사용하여 <strong>모듈 간에 기능을 공유</strong>할 수 있으며, <strong>정적인 구조</strong> 덕분에 <strong>트리 쉐이킹 등의 최적화도 가능</strong>해진다. 모듈을 적절히 사용하면 대규모 프로젝트에서도 코드 관리를 효과적으로 할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 붕대 감기,  석유 시추 - Python]]></title>
            <link>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%B6%95%EB%8C%80-%EA%B0%90%EA%B8%B0-%EC%84%9D%EC%9C%A0-%EC%8B%9C%EC%B6%94-Python</link>
            <guid>https://velog.io/@hi-rachel/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%B6%95%EB%8C%80-%EA%B0%90%EA%B8%B0-%EC%84%9D%EC%9C%A0-%EC%8B%9C%EC%B6%94-Python</guid>
            <pubDate>Wed, 29 May 2024 14:44:22 GMT</pubDate>
            <description><![CDATA[<h3 id="문제---pccp-기출문제-1번">문제 - [PCCP 기출문제] 1번</h3>
<blockquote>
<p>프로그래머스 <a href="https://school.programmers.co.kr/learn/courses/30/lessons/250137">붕대 감기</a></p>
</blockquote>
<h3 id="풀이">풀이</h3>
<pre><code class="language-python"># t초 동안 붕대를 감으면서 1초마다 x만큼의 체력을 회복
# t초 연속으로 붕대를 감는데 성공한다면 y만큼의 체력을 추가 회복

# 몬스터에게 공격당해 기술이 취소당하거나 기술이 끝나면 그 즉시 붕대 감기 다시 사용, 연속 성공 시간 0 초기화

# 현재 체력이 0이하가 되면 캐릭터가 죽으며 더 이상 체력을 회복할 수 없음!

# 붕대감기 기술의 정보[시전 시간, 초당 회복량, 추가 회복량], 캐릭터가 가진 최대 체력,
# 몬스터 공격 패턴[공격 시간, 피해량]
def solution(bandage, health, attacks):
    max_health = health
    last_time = attacks[-1][0] + 1
    attack_time = []
    success_cnt = 0

    for attack in attacks:
        attack_time.append(attack[0])

    for i in range(1, last_time):
        # 죽으면 게임 끝
        if health &lt;= 0:
            break

        # 공격
        if i in attack_time:
            success_cnt = 0
            health -= attacks[attack_time.index(i)][1]
        else:
            # 공격받지 않는다면
            if health &lt; max_health:
                health += bandage[1]
                if health &gt; max_health:
                    health = max_health
            success_cnt += 1

        if success_cnt == bandage[0]:
            if health &lt; max_health:
                health += bandage[2]
                if health &gt; max_health:
                    health = max_health
            success_cnt = 0

    # 캐릭터가 끝까지 생존할 수 있는지 구해라(남은 체력 or -1 반환)
    return health if health &gt; 0 else -1</code></pre>
<p>첫 번째 풀이에서 6, 9번 테스트 케이스만 실패했는데 문제를 다시 자세히 읽어보고</p>
<blockquote>
<p>이때, 현재 체력이 0 이하가 되면 캐릭터가 죽으며 더 이상 체력을 회복할 수 없습니다.
<strong>-&gt; 체력이 0이하가 되면 종료 -&gt; 죽고나서 회복되지 않게 처리</strong></p>
</blockquote>
<p>이 부분을 추가해 맞출 수 있었다.</p>
<h3 id="개선-코드">개선 코드</h3>
<pre><code class="language-python">def solution(bandage, health, attacks):
    max_health = health
    last_time = attacks[-1][0] + 1
    attack_time_set = set()
    success_cnt = 0

    for attack in attacks:
        attack_time_set.add(attack[0])

    attack_dict = {attack[0]: attack[1] for attack in attacks}

    for i in range(1, last_time):
        # 죽으면 게임 끝
        if health &lt;= 0:
            break

        # 공격
        if i in attack_time_set:
            success_cnt = 0
            health -= attack_dict[i]
        else:
            # 공격받지 않는다면
            if health &lt; max_health:
                health += bandage[1]
                if health &gt; max_health:
                    health = max_health
            success_cnt += 1

        if success_cnt == bandage[0]:
            if health &lt; max_health:
                health += bandage[2]
                if health &gt; max_health:
                    health = max_health
            success_cnt = 0

    # 캐릭터가 끝까지 생존할 수 있는지 구해라(남은 체력 or -1 반환)
    return health if health &gt; 0 else -1</code></pre>
<p>attack_time을 집합으로 사용하고 attack_dict를 만들어 사용하면 공격 시간을 확인하는 시간을 줄일 수 있다. (집합을 사용하는 in 연산자는 평균적으로 O(1) 시간이 걸린다)</p>
<blockquote>
<p>⏰ 시간복잡도 O(n + T)
n: 공격 시간, T: last_time(최대 공격 시간)</p>
</blockquote>
<hr>
<h3 id="문제---pccp-기출문제-2번">문제 - [PCCP 기출문제] 2번</h3>
<blockquote>
<p>프로그래머스 <a href="https://school.programmers.co.kr/learn/courses/30/lessons/250136">석유 시추</a></p>
</blockquote>
<h3 id="풀이-1">풀이</h3>
<pre><code class="language-python"># 세로 n, 가로 m
# 시추관을 수직(열)으로 단 하나만 뚫을때, 가장 많은 석유를 뽑을 수 있는 시추관의 위치를 찾아라
# 상, 하, 좌, 우로 연결된 석유는 하나의 덩어리

from collections import deque

def solution(land):
    n = len(land) # 세로
    m = len(land[0]) # 가로
    visited = [[0 for _ in range(m)] for _ in range(n)]

     # 각 열마다 최대 석유 덩어리 크기를 저장할 배열
    max_oil_in_column = [0] * m

    # 상하좌우
    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]

    def bfs(i, j):
        queue = deque()
        queue.append((i, j))
        visited[i][j] = 1
        cnt = 1 # 석유 덩어리의 크기
        min_y, max_y = j, j

        while queue:
            x, y = queue.popleft()
            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]

                if 0 &lt;= nx &lt; n and 0 &lt;= ny &lt; m and land[nx][ny] == 1 and not visited[nx][ny]:
                    visited[nx][ny] = 1
                    queue.append((nx, ny))
                    cnt += 1
                    min_y = min(min_y, ny) # 열에서 가장 작은
                    max_y = max(max_y, ny) # 열에서 가장 큰

        # 최소, 최대 열 인덱스에 석유 덩어리의 크기 업데이트
        for y in range(min_y, max_y + 1):
                max_oil_in_column[y] += cnt



    # 탐색
    for i in range(n):
        for j in range(m):
            if land[i][j] == 1 and not visited[i][j]:
                bfs(i, j)

    # 가장 큰 석유 덩어리를 포함하는 열의 크기 반환
    return max(max_oil_in_column)</code></pre>
<p>bfs 탐색은 돌 수 있지만 누적한 값을 탐색 마지막에 저장하는 방법이 아닌 해당 석유 덩어리 칸마다 모두 해당 석유 덩어리 크기(탐색 완료 크기)로 업데이트하는 부분과
수직(열 인덱스)마다 최대 열을 찾아주는 부분을 모르겠어서 다른 풀이를 참고했다.</p>
<p>해당 부분은 <strong>bfs 탐색의 최소, 최대 열을 찾고, &#39;각 열마다 최대 석유 덩어리 크기를 저장할 배열&#39;에 해당 범위에 해당하는 열에 현재 석유 덩어리의 크기를 더해주면 된다.</strong>
마지막에 그 중 가장 큰 크기를 반환하면 수직으로 석유를 뽑았을때 가장 많은 석유를 뽑는 값을 알 수 있다.</p>
<blockquote>
<p>⏰ 시간복잡도 O(n * m)</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>