<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>어제의 나보다 성장한 오늘의 나</title>
    <link>https://8156217.tistory.com/</link>
    <description>성실한 개발자가 되기 위한 코딩 블로그</description>
    <language>ko</language>
    <pubDate>Tue, 19 May 2026 00:23:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>today_me</managingEditor>
    <image>
      <title>어제의 나보다 성장한 오늘의 나</title>
      <url>https://tistory1.daumcdn.net/tistory/5237942/attach/b6bde0caec5c4c3e8328056a5497fecb</url>
      <link>https://8156217.tistory.com</link>
    </image>
    <item>
      <title>FEConf 2025 참여 후기</title>
      <link>https://8156217.tistory.com/98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_3912.JPG&quot; data-origin-width=&quot;5712&quot; data-origin-height=&quot;4284&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZyQ7K/btsP4lmmh2B/Kui7NncIOiKJaKHdz3yMx1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZyQ7K/btsP4lmmh2B/Kui7NncIOiKJaKHdz3yMx1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZyQ7K/btsP4lmmh2B/Kui7NncIOiKJaKHdz3yMx1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZyQ7K%2FbtsP4lmmh2B%2FKui7NncIOiKJaKHdz3yMx1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;587&quot; height=&quot;440&quot; data-filename=&quot;IMG_3912.JPG&quot; data-origin-width=&quot;5712&quot; data-origin-height=&quot;4284&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세종대학교 광개토관에서 열린 &lt;b&gt;FECONF 2025&lt;/b&gt;를 다녀왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;일단 사람이 정말 많았다.&lt;/b&gt; 프론트엔드 개발자들만 모여있는데도 천 명은 족히 넘게 온 것 같았다. 에어컨이 빵빵해도 더워서 땀이 났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;컨퍼런스를 다녀오면 항상 현장에서 발표를 들을 때는 이해가 잘 되는데, 막상 집에 돌아오면 머릿속에 &lt;b&gt;키워드 몇 개&lt;/b&gt;만 남는 느낌이다. 그래서 까먹기 전에 핸드폰에 적어둔 메모를 기반으로 간단히 리서치를 하고 정리를 해봤다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. Svelte&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.1) fine-grained reactivity&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트는&amp;nbsp;상태가&amp;nbsp;변경되면&amp;nbsp;해당&amp;nbsp;컴포넌트와&amp;nbsp;자식&amp;nbsp;컴포넌트가&amp;nbsp;모두&amp;nbsp;리렌더링&amp;nbsp;된다.&lt;br /&gt;하지만&amp;nbsp;svelte는&amp;nbsp;변경한 특정 상태만을&amp;nbsp;렌더링&amp;nbsp;되도록&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있다고&amp;nbsp;한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1.2)&amp;nbsp;Virtual&amp;nbsp;DOM을&amp;nbsp;쓰지&amp;nbsp;않고&amp;nbsp;실제&amp;nbsp;DOM을&amp;nbsp;직접&amp;nbsp;조작&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Virtual&amp;nbsp;DOM을&amp;nbsp;사용하는&amp;nbsp;Vue나&amp;nbsp;React는&amp;nbsp;&lt;b&gt;Virtual&amp;nbsp;DOM&amp;nbsp;연산의&amp;nbsp;오버헤드&lt;/b&gt;가&amp;nbsp;있다.&lt;br /&gt;Svelte는&amp;nbsp;직접&amp;nbsp;DOM을&amp;nbsp;조작하기&amp;nbsp;때문에&amp;nbsp;해당&amp;nbsp;되지&amp;nbsp;않는다.&amp;nbsp;겉보기엔&amp;nbsp;DOM을&amp;nbsp;직접&amp;nbsp;다룬다는&amp;nbsp;점에서&amp;nbsp;과거의&amp;nbsp;jQuery와&amp;nbsp;비슷하다고&amp;nbsp;생각할&amp;nbsp;수&amp;nbsp;있지만,&amp;nbsp;&lt;b&gt;컴파일 타임에 최적화된 코드로 변환된다는 점에서 본질적으로 차별성이 있다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1.3) 컴파일러 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일 타임에 최적화된 코드로 변환하여 런타임 오버헤드가 거의 없다. 1.2에 포함된 내용이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. React Compiler&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.1) 자동 메모이제이션 처리&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;memo, useMemo 같은 최적화를 자동으로 적용해 불필요한 렌더링 방지한다.&lt;/b&gt;&lt;br /&gt;하지만 자동으로 여러 경우의 수를 미리 따져서 캐시를 만들어 두기 때문에 코드의 양이 많이 늘어난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;번들 사이즈가 커진다는 단점&lt;/b&gt;이 있다. 일종의 trade-off가 있는 것이다.&lt;br /&gt;&lt;br /&gt;프론트엔드&amp;nbsp;개발하면서&amp;nbsp;memo,&amp;nbsp;useMemo,&amp;nbsp;useCallback을&amp;nbsp;고민하는&amp;nbsp;것이&amp;nbsp;참&amp;nbsp;귀찮았는데,&amp;nbsp;솔깃한&amp;nbsp;인사이트였다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.2)&amp;nbsp;아직&amp;nbsp;실험&amp;nbsp;단계&lt;/b&gt;&lt;br /&gt;아직 RCRelease Candidate 버전이다. 그렇기 때문에 약간 사용이 꺼려 진다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Meta와 같은 회사에서는 이미 프로덕션 환경에 도입하여 사용하고 있지만, 앱에 컴파일러를 점진적으로 도입할지는 코드베이스의 건강 상태와 React의 규칙을 얼마나 잘 준수했는지에 따라 달라질 것입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;하지만 위와 같이 React 공식문서에서는 &lt;b&gt;Meta는 이미 잘쓰고 있다고 한다. ㅎㅎ&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.&amp;nbsp;Devup&amp;nbsp;UI&amp;nbsp;(CSS-in-JS)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js가 떠오르고 &lt;b&gt;서버 컴포넌트 개념이 등장하는 배경&lt;/b&gt;에서 런타임에 JS가 동적으로 CSS를 생성하는 &lt;b&gt;CSS-in-JS 방식은 호환이 잘되지 않아 인기가 조금씩 떨어졌다.&lt;/b&gt; 그래도 사용은 하고 싶어서 사람들이 모든 곳에 use client를 붙이곤 했지만 너무 별로다... 결국 &lt;b&gt;Tailwind처럼 빌드 시점에 클래스 기반 CSS를 생성하는 방식&lt;/b&gt;이 호환이 잘되서 각광받고 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&quot;음..왠지 더 잘 만들 수 있을거 같은데 ??&quot;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;라는&amp;nbsp;생각으로&amp;nbsp;CSS-in-JS이면서도&amp;nbsp;서버&amp;nbsp;컴포넌트에&amp;nbsp;호환될&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;라이브러리를&amp;nbsp;만들고&amp;nbsp;있다고&amp;nbsp;하셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;css variable 지원과 조건부 오퍼레이션 추가&lt;/li&gt;
&lt;li&gt;최신 번들러 (vite, rsbuild, next.js webpack) 지원&lt;/li&gt;
&lt;li&gt;코드 AST 변환 및 rust와 wa를 활용한 스타일 캐시 로직 작성&lt;/li&gt;
&lt;li&gt;rgba를 hex로 변환 및 중복된 색상 제거를 통한 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등등 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하여튼 엄청 깎으면서 만들고 계셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4.&amp;nbsp;웹&amp;nbsp;접근성와&amp;nbsp;ARIA&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근성 트리를 올바르게 구축하기 위해서는 &lt;span&gt;&lt;b&gt;ARIA 속성을 적극적으로 활용&lt;/b&gt;&lt;/span&gt;해야 한다. ARIA는 스크린리더나 보조기기가 요소를 정확히 인식하도록 도와주며, 이를 통해 &lt;span&gt;&lt;b&gt;모든 사용자가 차별 없이 이용할 수 있는 웹&lt;/b&gt;&lt;/span&gt;을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이 외에도 &lt;b&gt;SEO 최적화를 통한 비용 절감&lt;/b&gt;, &lt;b&gt;모노레포에서 폴리레포로의 마이그레이션&lt;/b&gt;&amp;nbsp;작업에 대해 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 인사이트들을 얻은 알찬 주말을 보냈다. 강의를 듣다가 예전에 next.js를 도입할 때 궁합이 좋은 CSS 라이브러리를 찾으면서 했던 고민들이 오랜만에 생각나기도 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://8156217.tistory.com/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://8156217.tistory.com/86&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1755968107248&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Next.js] Next.js와 호환되는 css와 그렇지 못한 css에 대한 고찰&quot; data-og-description=&quot;Next.js로 프로젝트를 하면서 드는 의문이 있다. 왜 MUI 같은 라이브러리들은 자꾸 호환이 안된다고 하는 걸까?? tailwind는 왜 되는걸까?? 공식 문서를 보면 다음과 같이 나와 있다. Next.js와 호환이 잘&quot; data-og-host=&quot;8156217.tistory.com&quot; data-og-source-url=&quot;https://8156217.tistory.com/86&quot; data-og-url=&quot;https://8156217.tistory.com/86&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/zWkcV/hyZzJE28Ns/x96o0SzffINBQD7DAcWyb0/img.png?width=800&amp;amp;height=599&amp;amp;face=0_0_800_599,https://scrap.kakaocdn.net/dn/dVB3mv/hyZzKqrge4/P9K5KW0prRlBYxwWcYm4VK/img.png?width=800&amp;amp;height=599&amp;amp;face=0_0_800_599,https://scrap.kakaocdn.net/dn/lafcN/hyZC7knDjN/cckKSo3nhDnX64YE4UKgr0/img.jpg?width=1002&amp;amp;height=1334&amp;amp;face=429_343_664_599&quot;&gt;&lt;a href=&quot;https://8156217.tistory.com/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://8156217.tistory.com/86&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/zWkcV/hyZzJE28Ns/x96o0SzffINBQD7DAcWyb0/img.png?width=800&amp;amp;height=599&amp;amp;face=0_0_800_599,https://scrap.kakaocdn.net/dn/dVB3mv/hyZzKqrge4/P9K5KW0prRlBYxwWcYm4VK/img.png?width=800&amp;amp;height=599&amp;amp;face=0_0_800_599,https://scrap.kakaocdn.net/dn/lafcN/hyZC7knDjN/cckKSo3nhDnX64YE4UKgr0/img.jpg?width=1002&amp;amp;height=1334&amp;amp;face=429_343_664_599');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Next.js] Next.js와 호환되는 css와 그렇지 못한 css에 대한 고찰&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Next.js로 프로젝트를 하면서 드는 의문이 있다. 왜 MUI 같은 라이브러리들은 자꾸 호환이 안된다고 하는 걸까?? tailwind는 왜 되는걸까?? 공식 문서를 보면 다음과 같이 나와 있다. Next.js와 호환이 잘&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;8156217.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고&amp;nbsp;나중에&amp;nbsp;&lt;b&gt;리액트&amp;nbsp;컴파일러&lt;/b&gt;를 한번 시도해 봐야겠다. 웹 성능과 개발 생산성이 많이 올라갈 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전에는 구글 컨퍼런스에서 v0를 알게 되어 잘 쓰고 있다. 컨퍼런스는 이런 꿀팁과 좋은 키워드들을 얻을 수 있어서 좋다!!&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/98</guid>
      <comments>https://8156217.tistory.com/98#entry98comment</comments>
      <pubDate>Sun, 24 Aug 2025 01:56:57 +0900</pubDate>
    </item>
    <item>
      <title>유네스코 유니트윈 르완다 출장</title>
      <link>https://8156217.tistory.com/97</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 유네스코 유니트윈(UNITWIN) 사업의 일환으로 &lt;b&gt;2025.7.28 ~ 2025.8.1 기간동안 르완다에 출장&lt;/b&gt;을 다녀오게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;출장 일정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 출장의 주요 일정은 &lt;b&gt;르완다 수도 키갈리에서 진행&lt;/b&gt;되었다.&lt;br /&gt;현지에서는&amp;nbsp;&lt;b&gt;Rwanda&amp;nbsp;Polytechnic과&amp;nbsp;University&amp;nbsp;of&amp;nbsp;Rwanda&amp;nbsp;두&amp;nbsp;학교가&amp;nbsp;참여&lt;/b&gt;했고,&amp;nbsp;우린&amp;nbsp;이들을&amp;nbsp;대상으로&amp;nbsp;&lt;b&gt;기업가&amp;nbsp;정신&amp;nbsp;훈련과&amp;nbsp;AI&amp;nbsp;관련&amp;nbsp;비즈니스&amp;nbsp;워크숍을&amp;nbsp;진행&lt;/b&gt;했다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;75분 동안의 AI 관련&amp;nbsp;강연&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;b&gt;&amp;lsquo;Product Development in AI Company&amp;rsquo;&lt;/b&gt; 라는 주제로 약 75분간 강연을 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_8506.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;2268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc2ag2/btsPHYYq6RC/IKSsiV9aQxQ5hjY1BqPk6K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc2ag2/btsPHYYq6RC/IKSsiV9aQxQ5hjY1BqPk6K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc2ag2/btsPHYYq6RC/IKSsiV9aQxQ5hjY1BqPk6K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc2ag2%2FbtsPHYYq6RC%2FIKSsiV9aQxQ5hjY1BqPk6K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;2268&quot; data-filename=&quot;IMG_8506.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;2268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;발표에서는 다음과 같은 내용들을 다루었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 관리&lt;/li&gt;
&lt;li&gt;AI 서비스 개발의 과정&lt;/li&gt;
&lt;li&gt;제품 고도화 방식&lt;/li&gt;
&lt;li&gt;기술 스택과 인프라&lt;/li&gt;
&lt;li&gt;Cursor, ChatGPT 등 실용적인 AI 툴들&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학생들은 AI 툴들이 익숙하다.&lt;br /&gt;&lt;b&gt;GPT는&amp;nbsp;이미&amp;nbsp;많이들&amp;nbsp;쓰고&amp;nbsp;있었고&amp;nbsp;Cursor를&amp;nbsp;사용해&amp;nbsp;본&amp;nbsp;친구들도&amp;nbsp;있었다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;일정&amp;nbsp;관리나&amp;nbsp;협업&amp;nbsp;도구에&amp;nbsp;대한&amp;nbsp;관심도&amp;nbsp;높았다.&lt;br /&gt;&lt;b&gt;실제 기업에서는 관리 툴들을 어떻게 활용하는 지 궁금해 했다&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;각 툴들이 다른 유사한 툴과의 차이점이 뭔지 많은 질문을 받았다.&lt;br /&gt;수준 높은 질문과 몰입도 있는 질문에 놀랐다. 그리고 아프리카식 억양에 다시 한 번 놀랐다..&lt;br /&gt;질문 이해하는 데 진땀 뺐다 ㅋㅋㅋㅋ...&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;Group Work&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학생들을 &lt;b&gt;6개 그룹(조당 약 10명)&lt;/b&gt;으로 나누고, 3박 4일 동안 하나의 비즈니스 아이템을 구상해서 마지막 날 발표하는 시간을 가졌다.&lt;br /&gt;처음엔&amp;nbsp;다들 서로 어색해했지만,&amp;nbsp;시간이&amp;nbsp;흐르면서&amp;nbsp;점점&amp;nbsp;친해지면서&amp;nbsp;다들&amp;nbsp;열기가&amp;nbsp;붙었다.&lt;br /&gt;&lt;br /&gt;내가&amp;nbsp;맡은&amp;nbsp;조는&amp;nbsp;&lt;b&gt;도시&amp;nbsp;소규모&amp;nbsp;농업인을&amp;nbsp;위한&amp;nbsp;스마트팜&amp;nbsp;솔루션을&amp;nbsp;주제로&amp;nbsp;선정&lt;/b&gt;했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_3688.JPG&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;739&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VcLzd/btsPHHpj909/dDhg8ImdiAhol8np3Q6y7K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VcLzd/btsPHHpj909/dDhg8ImdiAhol8np3Q6y7K/img.jpg&quot; data-alt=&quot;우리조 (3조)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VcLzd/btsPHHpj909/dDhg8ImdiAhol8np3Q6y7K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVcLzd%2FbtsPHHpj909%2FdDhg8ImdiAhol8np3Q6y7K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;323&quot; data-filename=&quot;IMG_3688.JPG&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;739&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;우리조 (3조)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&quot;&lt;b&gt;르완다의 도시에서는 채소가 너무 비싸다.&lt;/b&gt;&amp;nbsp;도시에서는 땅과 물이 부족해서 농사를 짓기 힘들기 때문에 외부에서 수입해야 하고, 이 과정에서 가격이 뻥튀기 된다.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이&amp;nbsp;문제를&amp;nbsp;해결하기&amp;nbsp;위해&amp;nbsp;&lt;b&gt;수직&amp;nbsp;농업과&amp;nbsp;실시간&amp;nbsp;토양&amp;nbsp;모니터링&amp;nbsp;시스템을&amp;nbsp;활용한&amp;nbsp;솔루션&lt;/b&gt;을 내놓았다.&lt;br /&gt;열심히&amp;nbsp;준비하더니만&amp;nbsp;결국&amp;nbsp;우리&amp;nbsp;조가&amp;nbsp;1등을&amp;nbsp;했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-05 오전 1.52.15.png&quot; data-origin-width=&quot;3130&quot; data-origin-height=&quot;1686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lOFFb/btsPHdV6ImF/iOLrNIktWzpZDzh1Ei8q71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lOFFb/btsPHdV6ImF/iOLrNIktWzpZDzh1Ei8q71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lOFFb/btsPHdV6ImF/iOLrNIktWzpZDzh1Ei8q71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlOFFb%2FbtsPHdV6ImF%2FiOLrNIktWzpZDzh1Ei8q71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3130&quot; height=&quot;1686&quot; data-filename=&quot;스크린샷 2025-08-05 오전 1.52.15.png&quot; data-origin-width=&quot;3130&quot; data-origin-height=&quot;1686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;서로&amp;nbsp;끌어안고&amp;nbsp;기뻐하는&amp;nbsp;모습을&amp;nbsp;보는데&amp;nbsp;엄청나게&amp;nbsp;기뻐보였다.&lt;br /&gt;예전에&amp;nbsp;친구들하고&amp;nbsp;해커톤&amp;nbsp;나갔을&amp;nbsp;때&amp;nbsp;상&amp;nbsp;받던&amp;nbsp;기억이&amp;nbsp;떠올랐었다.&lt;br /&gt;큰&amp;nbsp;상도&amp;nbsp;아닌데&amp;nbsp;그&amp;nbsp;때는&amp;nbsp;마치&amp;nbsp;노벨상&amp;nbsp;받은&amp;nbsp;거&amp;nbsp;기뻤었다.&lt;br /&gt;&lt;br /&gt;이&amp;nbsp;친구들의&amp;nbsp;몰입한&amp;nbsp;모습에&amp;nbsp;부러운&amp;nbsp;감정이&amp;nbsp;들었었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;르완다의 열악한 교육 환경&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;전기&amp;nbsp;공급의&amp;nbsp;부족&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;정전이&amp;nbsp;하루에도&amp;nbsp;몇&amp;nbsp;번씩&amp;nbsp;일어난다.&lt;br /&gt;그룹&amp;nbsp;워크&amp;nbsp;중엔&amp;nbsp;강당&amp;nbsp;전력&amp;nbsp;부족으로&amp;nbsp;저녁이&amp;nbsp;되면&amp;nbsp;금방&amp;nbsp;어두워졌었다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;일자리&amp;nbsp;부족&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;공학&amp;nbsp;계열&amp;nbsp;전공자도&amp;nbsp;일자리를&amp;nbsp;찾기&amp;nbsp;어렵다.&lt;br /&gt;University&amp;nbsp;of&amp;nbsp;Rwanda&amp;nbsp;학교는&amp;nbsp;르완다에서&amp;nbsp;매우&amp;nbsp;유명한&amp;nbsp;학교임에도&amp;nbsp;일자리를&amp;nbsp;찾지&amp;nbsp;못하는&amp;nbsp;경우가&amp;nbsp;많이&amp;nbsp;있다고&amp;nbsp;한다.&lt;br /&gt;건축이나&amp;nbsp;관광이&amp;nbsp;주&amp;nbsp;산업이고&amp;nbsp;기술은&amp;nbsp;아직이라고&amp;nbsp;한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.&amp;nbsp;컴퓨터&amp;nbsp;보급&amp;nbsp;늦음&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;컴퓨터가&amp;nbsp;보급된&amp;nbsp;지&amp;nbsp;아직&amp;nbsp;3년도&amp;nbsp;안&amp;nbsp;됐다.&lt;br /&gt;그래서&amp;nbsp;이메일&amp;nbsp;하나&amp;nbsp;보내는&amp;nbsp;데도&amp;nbsp;시간이&amp;nbsp;오래&amp;nbsp;걸리고,&amp;nbsp;타이핑이&amp;nbsp;서툰&amp;nbsp;경우도&amp;nbsp;많았다.&lt;br /&gt;&lt;br /&gt;환경이&amp;nbsp;좋지&amp;nbsp;않아&amp;nbsp;보였다.&lt;br /&gt;그래서&amp;nbsp;열정도&amp;nbsp;많고&amp;nbsp;하고&amp;nbsp;싶은&amp;nbsp;것들도&amp;nbsp;많아&amp;nbsp;보이는&amp;nbsp;데&amp;nbsp;환경이&amp;nbsp;받쳐주지&amp;nbsp;않는&amp;nbsp;느낌을&amp;nbsp;받았다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;느낀 점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;아이들이&amp;nbsp;참&amp;nbsp;열정이&amp;nbsp;넘친다.&lt;/b&gt;&amp;nbsp;이런&amp;nbsp;교육&amp;nbsp;기회도&amp;nbsp;직접&amp;nbsp;참여하고,&amp;nbsp;몰입도&amp;nbsp;있게&amp;nbsp;문제를&amp;nbsp;해결하려고&amp;nbsp;하는&amp;nbsp;모습이&amp;nbsp;보기&amp;nbsp;좋았다.&lt;br /&gt;&lt;b&gt;그런데&amp;nbsp;환경이&amp;nbsp;참&amp;nbsp;아쉽다.&lt;/b&gt;&amp;nbsp;일자리가&amp;nbsp;많고&amp;nbsp;교육&amp;nbsp;기회만&amp;nbsp;많으면&amp;nbsp;더&amp;nbsp;즐겁게&amp;nbsp;공부할&amp;nbsp;수&amp;nbsp;있을&amp;nbsp;텐데.&lt;br /&gt;이런&amp;nbsp;열정을&amp;nbsp;보며&amp;nbsp;좋은&amp;nbsp;환경에서&amp;nbsp;일하면서&amp;nbsp;열정이&amp;nbsp;부족한&amp;nbsp;내가&amp;nbsp;부끄러워&amp;nbsp;지기도&amp;nbsp;했다.&lt;br /&gt;&lt;br /&gt;그리고&amp;nbsp;기술이&amp;nbsp;참&amp;nbsp;매력적이라고&amp;nbsp;느꼈다.&amp;nbsp;기술은&amp;nbsp;만국&amp;nbsp;공통이기&amp;nbsp;때문에&amp;nbsp;&lt;b&gt;내가&amp;nbsp;가진&amp;nbsp;것을&amp;nbsp;쉽게&amp;nbsp;공유할&amp;nbsp;수&amp;nbsp;있다.&lt;/b&gt;&amp;nbsp;저번&amp;nbsp;스페인&amp;nbsp;MWC&amp;nbsp;박람회에서&amp;nbsp;부스를&amp;nbsp;운영했을&amp;nbsp;때도&amp;nbsp;신기했던&amp;nbsp;것이&amp;nbsp;&lt;b&gt;모두가&amp;nbsp;다른&amp;nbsp;나라에서&amp;nbsp;와서&amp;nbsp;같은&amp;nbsp;흥미를&amp;nbsp;나누고&amp;nbsp;있다는&amp;nbsp;것이&amp;nbsp;참&amp;nbsp;좋았다.&lt;/b&gt;&lt;br /&gt;특히&amp;nbsp;같이&amp;nbsp;가셨던&amp;nbsp;법&amp;nbsp;전공&amp;nbsp;박사님&amp;nbsp;한&amp;nbsp;분이&amp;nbsp;&lt;b&gt;&quot;법은 한 나라에 특정 되는 데 기술은 모두가 공유할 수 있다.&quot;&lt;/b&gt;고&amp;nbsp;부럽다고&amp;nbsp;말씀&amp;nbsp;해주셨다.&lt;br /&gt;&lt;br /&gt;앞으로는&amp;nbsp;내가&amp;nbsp;배우는&amp;nbsp;기술을&amp;nbsp;&lt;b&gt;더&amp;nbsp;가치있게&amp;nbsp;생각하려고&amp;nbsp;한다.&lt;/b&gt;&amp;nbsp;계속&amp;nbsp;공부하면서&amp;nbsp;기술을&amp;nbsp;어떻게&amp;nbsp;나누고&amp;nbsp;활용할지를&amp;nbsp;고민해봐야겠다.&lt;br /&gt;단순히 밥벌이 수단으로서의 기술도 물론 소중하지만, 잘 활용하면 더 큰 가치를 만들어낼 수 있을 것 같았다.&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/97</guid>
      <comments>https://8156217.tistory.com/97#entry97comment</comments>
      <pubDate>Tue, 5 Aug 2025 01:45:15 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] 데이터 요청 구조를 Server Action으로 통합해보기</title>
      <link>https://8156217.tistory.com/96</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js를 활용 하면서 많이 하게 되는 고민은,&amp;nbsp; &lt;b&gt;이걸 대체 어떻게 써야 우리 팀에 적합하게 활용할 수 있을까? &lt;/b&gt;입니다.&amp;nbsp;&amp;nbsp;&lt;br /&gt;서버 컴포넌트(Server Components), 서버 액션(Server Actions) 등 Next.js의 다양한 기능들을 접해보면 분명히 강력하고 놀라운 부분도 많지만, 때로는 &lt;b&gt;다양한 옵션들과 제약들로 인해 개발이 더 복잡해져서 오히려 개발 생산성이 저하&lt;/b&gt; &lt;b&gt;된다고 느껴질 때도 있습니다. &lt;/b&gt;결국 좋은 기술이 있더라도 팀에 맞게 쓰지 않으면 오히려 독이 될 수 있다는 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이번 글에서는 실제 프로젝트에서 경험한 &lt;b&gt;기존 데이터 요청 방식에서의 개발 생산성 이슈&lt;/b&gt;와, 이를 &lt;b&gt;Server Action 중심으로 통합함으로써 개선해 본 경험&lt;/b&gt;에 대해 공유드리고자 합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;다양한 방식으로 이뤄졌던 기존의 데이터 요청 구조&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;Next.js를 사용하면서 우리는 아래와 같이 상황에 따라 데이터 요청 방식을 다르게 가져가고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;서버&amp;nbsp;컴포넌트&amp;nbsp;내&amp;nbsp;fetch&lt;/b&gt;&lt;br /&gt;서비스 단 (services/) 들을 컴포넌트 내에서 직접 호출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1753100646403&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/page.tsx (서버 컴포넌트)
import { getUserByIdFromDB } from '@/services/user';

export default async function Page() {
  const user = await getUserByIdFromDB('123');
  return &amp;lt;div&amp;gt;{user.name}&amp;lt;/div&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;클라이언트&amp;nbsp;컴포넌트&amp;nbsp;내&amp;nbsp;fetch&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;api route handler를 만들고 이를 fetch를 통해 호출.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로는 tanstack-Query 사용하여 브라우저 캐시를 적극 활용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1753100716262&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/components/UserInfo.tsx (클라이언트 컴포넌트)
'use client';

export function UserInfo() {
  const [name, setName] = useState('');

  const fetchUser = async () =&amp;gt; {
    const res = await fetch('/api/user?id=123');
    const data = await res.json();
    setName(data.name);
  };

  return &amp;lt;button onClick={fetchUser}&amp;gt;{name || 'Load User'}&amp;lt;/button&amp;gt;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;호출하는 라우트 핸들러&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753100828789&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/api/user/route.ts
import { NextResponse } from 'next/server';

export async function GET(req: Request) {
  const { searchParams } = new URL(req.url);
  const id = searchParams.get('id');
  const user = await getUserByIdFromDB(id!);

  return NextResponse.json(user);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.&amp;nbsp;Mutation&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;server action을 활용하여 호출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1753100873746&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/components/EditUser.tsx
'use client';

import { updateUserName } from '@/actions/user';

const EditUser = () =&amp;gt; {
  const handleSubmit = async () =&amp;gt; {
    const res = await updateUserName('123', 'John');
    if (res.success) alert('Updated!');
  };

  return &amp;lt;button onClick={handleSubmit}&amp;gt;Update Name&amp;lt;/button&amp;gt;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;액션 정의&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753100942931&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/actions/user.ts
'use server';

export async function updateUserName(id: string, name: string) {
  return { success: true, ... };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;이렇게&amp;nbsp;데이터&amp;nbsp;요청&amp;nbsp;방식이&amp;nbsp;세&amp;nbsp;가지로&amp;nbsp;나누어져&amp;nbsp;있다&amp;nbsp;보니&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;문제들이&amp;nbsp;발생하기&amp;nbsp;시작했습니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구조적&amp;nbsp;불일치가&amp;nbsp;만든&amp;nbsp;DX&amp;nbsp;저하&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;라우팅&amp;nbsp;방식의&amp;nbsp;불일치&lt;/b&gt;&lt;br /&gt;- 서버 컴포넌트는 라우트 단 없이 바로 서비스 단 호출&lt;br /&gt;- 클라이언트 컴포넌트는 app/api 라우트를 통해 요청&lt;br /&gt;-&amp;nbsp;Mutation은&amp;nbsp;server&amp;nbsp;action을&amp;nbsp;통해&amp;nbsp;이루어짐&amp;nbsp;(route&amp;nbsp;역할을&amp;nbsp;대신&amp;nbsp;수행)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;응답&amp;nbsp;형태(response&amp;nbsp;type)의&amp;nbsp;불일치&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;서버&amp;nbsp;컴포넌트는&amp;nbsp;직접&amp;nbsp;타입이&amp;nbsp;적용된&amp;nbsp;결과값&amp;nbsp;반환&lt;br /&gt;-&amp;nbsp;API&amp;nbsp;Route는&amp;nbsp;Response.json()&amp;nbsp;형태로&amp;nbsp;wrapping&lt;br /&gt;-&amp;nbsp;Server&amp;nbsp;Action은&amp;nbsp;{&amp;nbsp;success:&amp;nbsp;boolean,&amp;nbsp;message?:&amp;nbsp;string,&amp;nbsp;data?:&amp;nbsp;T&amp;nbsp;}&amp;nbsp;식으로&amp;nbsp;custom&amp;nbsp;구조&amp;nbsp;사용&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.&amp;nbsp;호출&amp;nbsp;로직&amp;nbsp;분산으로&amp;nbsp;인한&amp;nbsp;폴더&amp;nbsp;구조&amp;nbsp;혼란&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;services/,&amp;nbsp;api/,&amp;nbsp;actions/&amp;nbsp;등&amp;nbsp;호출&amp;nbsp;위치가&amp;nbsp;제각각이라&amp;nbsp;개발자가&amp;nbsp;로직&amp;nbsp;위치를&amp;nbsp;예측하기&amp;nbsp;어려움&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조가 불일치 하다보니 자연스레 헷갈려하는 팀원들이 나타나기 시작했죠 ㅎㅎ..&lt;br /&gt;특히 이번에 새로 합류한 팀원이 프로젝트 구조를 이해하는 과정에서, &lt;b&gt;각기 다른 데이터 요청 방식으로 어디서 어떤 데이터를 요청하고 응답 받는지 예측 하기 어렵다&lt;/b&gt;는 피드백을 했습니다. &lt;b&gt;그래서&amp;nbsp;데이터&amp;nbsp;요청&amp;nbsp;방식을&amp;nbsp;통합&amp;nbsp;시켜서&amp;nbsp;개발&amp;nbsp;생산성을&amp;nbsp;높여&amp;nbsp;보고자&amp;nbsp;하였습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;Server Action를 활용한 데이터 처리 구조 통합&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;모든&amp;nbsp;데이터&amp;nbsp;요청은&amp;nbsp;Server&amp;nbsp;Action을&amp;nbsp;통해&amp;nbsp;처리한다&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;클라이언트와&amp;nbsp;서버&amp;nbsp;컴포넌트&amp;nbsp;모두&amp;nbsp;actions/에&amp;nbsp;정의된&amp;nbsp;함수만&amp;nbsp;사용&lt;br /&gt;-&amp;nbsp;fetch나&amp;nbsp;API&amp;nbsp;Route는&amp;nbsp;사용하지&amp;nbsp;않고,&amp;nbsp;Server&amp;nbsp;Action&amp;nbsp;&amp;rarr;&amp;nbsp;Service&amp;nbsp;함수&amp;nbsp;형태로&amp;nbsp;흐름을&amp;nbsp;통일&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;비즈니스&amp;nbsp;로직은&amp;nbsp;services/에서&amp;nbsp;관리하고,&amp;nbsp;Server&amp;nbsp;Action에서만&amp;nbsp;호출한다&lt;/b&gt;&lt;br /&gt;-&amp;nbsp;클라이언트가&amp;nbsp;직접&amp;nbsp;service를&amp;nbsp;건드리는&amp;nbsp;일은&amp;nbsp;없도록&amp;nbsp;분리&lt;br /&gt;-&amp;nbsp;서비스&amp;nbsp;로직은&amp;nbsp;항상&amp;nbsp;action&amp;nbsp;내부에서&amp;nbsp;호출되도록&amp;nbsp;규칙화하여&amp;nbsp;역할과&amp;nbsp;책임을&amp;nbsp;명확히&amp;nbsp;분리&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;액션 정의&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753101156939&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/actions/user.ts
'use server'

import { getUserByIdFromDB } from '@/services/user';

export async function getUserById(id: string) {
  const user = await getUserByIdFromDB(id);
  return { success: true, data: user };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버 컴포넌트 fetch&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753101170527&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { getUserById } from '@/actions/user';

const Page = async () =&amp;gt; {
  const res = await getUserById('123');
  if (!res.success) return &amp;lt;div&amp;gt;Error&amp;lt;/div&amp;gt;;
  return &amp;lt;div&amp;gt;{res.data.name}&amp;lt;/div&amp;gt;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라이언트 컴포넌트 fetch&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753101188546&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client';

import { getUserById } from '@/actions/user';

const ClientComp = () =&amp;gt; {
  const handleClick = async () =&amp;gt; {
    const res = await getUserById('123');
    console.log(res.data);
  };

  return &amp;lt;button onClick={handleClick}&amp;gt;불러오기&amp;lt;/button&amp;gt;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이러면 뭐가 좋지??&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;1.&amp;nbsp;요청&amp;nbsp;방식&amp;nbsp;일관성&lt;/b&gt;&lt;br /&gt;서버/클라이언트 구분 없이 동일한 방식으로 호출 가능하기 때문에 재사용이 가능 합니다.&lt;br /&gt;전에는&amp;nbsp;같은&amp;nbsp;기능이어도&amp;nbsp;클라이언트에서&amp;nbsp;쓰면&amp;nbsp;라우트&amp;nbsp;핸들러를&amp;nbsp;만들어야&amp;nbsp;했는데...하하..&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;디렉토리&amp;nbsp;일관성&lt;/b&gt;&lt;br /&gt;actions/ 디렉토리 중심으로 통일되므로 유지보수성이 올라갑니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3.타입&amp;nbsp;안정성&lt;/b&gt;&lt;br /&gt;라우트&amp;nbsp;핸들러와&amp;nbsp;달리&amp;nbsp;타입이&amp;nbsp;자동&amp;nbsp;추론&amp;nbsp;된다.&lt;br /&gt;다른 프로젝트에서 Trpc를 사용하는 입장에서 이건 아주 행복합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;근데&amp;nbsp;이렇게&amp;nbsp;해도&amp;nbsp;괜찮을까??&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&amp;nbsp;Server&amp;nbsp;Actions는&amp;nbsp;원래&amp;nbsp;mutation용으로&amp;nbsp;설계됨&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;next.js의 공식 문서의 server action를 읽어보면 form submission 또는 mutation 용이라고 되어 있습니다. 예제를 모두 보아도 fetch 용도로 사용하지 않습니다. 이것을 보면 제가 시도한 방식이 공식적으로 권장하는 방식은 아닌 것 같습니다.&lt;br /&gt;&lt;a href=&quot;https://nextjs.org/docs/app/guides/forms#programmatic-form-submission&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nextjs.org/docs/app/guides/forms#programmatic-form-submission&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;Server&amp;nbsp;Actions&amp;nbsp;perform&amp;nbsp;HTTP&amp;nbsp;POST&amp;nbsp;requests&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;모두 내부에서 사용하는 것들 대상이기 때문에 문제가 되지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쨋든 현재 상황에서는 문제가 되지 않아 보입니다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;솔직히 이게 맞는 방법인지는 잘 모르겠습니다.&lt;br /&gt;다만 우리 팀에게는 DX를 높여준 좋은 방식 입니다.&lt;br /&gt;&lt;br /&gt;전에는 무조건 공식 문서대로만 해야 된다고 생각했었는데 꼭 그렇지만은 않은 것 같습니다.&lt;br /&gt;어떤 기술을 사용하더라도 &lt;b&gt;현재 상황에 적합한 방법으로 사용하는 것이 중요&lt;/b&gt;하다는 것을 배웠습니다!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;참고자료&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://nextjs.org/docs/app/guides/forms#programmatic-form-submission&quot;&gt;https://nextjs.org/docs/app/guides/forms#programmatic-form-submission&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://www.robinwieruch.de/next-server-actions-fetch-data/&quot;&gt;https://www.robinwieruch.de/next-server-actions-fetch-data/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753101294875&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Data Fetching with Server Actions in Next.js&quot; data-og-description=&quot;Can I fetch data with Server Actions in Next.js? There are different ways to fetch data. Normally Server Actions are used to mutate data, but ...&quot; data-og-host=&quot;www.robinwieruch.de&quot; data-og-source-url=&quot;https://www.robinwieruch.de/next-server-actions-fetch-data/&quot; data-og-url=&quot;https://www.robinwieruch.de/next-server-actions-fetch-data/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/YoLhZ/hyZnfchRfy/S9YCjIkewm1PnReJWsjNQ0/img.jpg?width=900&amp;amp;height=599&amp;amp;face=0_0_900_599&quot;&gt;&lt;a href=&quot;https://www.robinwieruch.de/next-server-actions-fetch-data/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.robinwieruch.de/next-server-actions-fetch-data/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/YoLhZ/hyZnfchRfy/S9YCjIkewm1PnReJWsjNQ0/img.jpg?width=900&amp;amp;height=599&amp;amp;face=0_0_900_599');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Data Fetching with Server Actions in Next.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Can I fetch data with Server Actions in Next.js? There are different ways to fetch data. Normally Server Actions are used to mutate data, but ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.robinwieruch.de&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/96</guid>
      <comments>https://8156217.tistory.com/96#entry96comment</comments>
      <pubDate>Mon, 21 Jul 2025 21:39:27 +0900</pubDate>
    </item>
    <item>
      <title>Recoil를 대체할 전역 상태 관리 라이브러리(HIState) 제작기</title>
      <link>https://8156217.tistory.com/95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 프로젝트에서 클라이언트 애플리케이션 내의 &lt;span&gt;&lt;b&gt;모든 전역 상태를 Recoil로 통합 관리&lt;/b&gt;&lt;/span&gt;하고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 프로젝트의 구조가 점점 바뀌면서, &lt;/span&gt;&lt;b&gt;Recoil의 역할이 줄어들게 되었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;서버 상태는 React Query로 대체&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, React Query의 도입으로 서버 상태 관리 방식이 완전히 바뀌었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 fetching, 캐싱, 로딩 상태 관리 등을 React Query로 손 쉽게 처리하면서 &lt;b&gt;Recoil은 더 이상 서버 상태를 다루지 않게 되었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Recoil은 여전히 클라이언트 전역 상태(UI 상태, Role)를 관리하는 용도로 일부 사용되고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제한적인 역할만 수행하면서도 비교적 무거운 Recoil을 계속 유지하는 것&lt;/b&gt;&lt;span&gt;은 부담스럽다고 판단했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Context API는 ??&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;context API도 여러 장점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;React 내장 기능이므로 &lt;b&gt;추가 설치 없이 사용 가능&lt;/b&gt;하고 &lt;b&gt;props drilling&lt;/b&gt;을 해결 해줄 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나.. 두 가지 치명적인 단점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&amp;nbsp;불필요한&amp;nbsp;리렌더링&lt;/b&gt;&lt;br /&gt;Context의 value가 변경되면 해당 Context를 구독(useContext)하고 있는 모든 Consumer 컴포넌트가 강제로 리렌더링 됩니다.&lt;br /&gt;이는 개별 필드의 변경 여부와 무관하게 발생하며, 구체적인 구독 범위를 분리할 수 없어 성능 최적화에 취약합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MyProvider.tsx&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752502904042&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createContext, useContext, useMemo, useState } from 'react';

// Context
interface AppState {
  count: number;
  message: string;
}

const AppContext = createContext&amp;lt;AppState | null&amp;gt;(null);

// Provider
function AppProvider({ children }: { children: React.ReactNode }) {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState('hello');

  const value = useMemo(() =&amp;gt; ({ count, message }), [count, message]);

  return (
    &amp;lt;AppContext.Provider value={value}&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount((c) =&amp;gt; c + 1)}&amp;gt;count +&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setMessage((m) =&amp;gt; m + '!')}&amp;gt;message +&amp;lt;/button&amp;gt;
      {children}
    &amp;lt;/AppContext.Provider&amp;gt;
  );
}

// count만 사용하는 컴포넌트
function CountDisplay() {
  const { count } = useContext(AppContext)!;
  console.log('CountDisplay가 렌더링됨');
  return &amp;lt;div /&amp;gt;;
}

// message만 사용하는 컴포넌트
function MessageDisplay() {
  const { message } = useContext(AppContext)!;
  console.log('MessageDisplay가 렌더링됨');
  return &amp;lt;div /&amp;gt;;
}

// App
export default function App() {
  return (
    &amp;lt;AppProvider&amp;gt;
      &amp;lt;CountDisplay /&amp;gt;
      &amp;lt;MessageDisplay /&amp;gt;
    &amp;lt;/AppProvider&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt; 버튼을 누르면 &lt;/span&gt;&lt;b&gt;MessageDisplay도 함께 렌더링됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;message&lt;/span&gt;&lt;span&gt; 버튼을 누르면 &lt;/span&gt;&lt;b&gt;CountDisplay도 함께 렌더링됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는&amp;nbsp;&lt;span&gt;Context&lt;/span&gt;의 &lt;span&gt;value&lt;/span&gt; 전체 객체가 변경 되면서, 이를 사용하는 &lt;span&gt;&lt;b&gt;모든 Consumer가 리렌더링&lt;/b&gt;되기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2.&amp;nbsp;Provider-Consumer의&amp;nbsp;강결합&amp;nbsp;구조&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Consumer들은 반드시 해당 Context의 Provider 하위 트리 내에 존재해야 하며, 이는 컴포넌트 재사용성을 떨어뜨립니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;외부 스토어 + useSyncExternalStore를 활용하여 직접 만들자&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 외부에서 상태를 관리하고, 필요한 컴포넌트만 구독할 수 있는 &lt;span&gt;&lt;b&gt;외부 스토어 기반 상태 관리 도구&lt;/b&gt;&lt;/span&gt;를 직접 구현했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름은 서비스 이름인 HIStudy를 따서 &lt;b&gt;HIState&lt;/b&gt; 라고 명명했습니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조는 아래와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eqbe3z/btsPioc8I12/8BsFHu2ZK7DzK5Gro8KnmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eqbe3z/btsPioc8I12/8BsFHu2ZK7DzK5Gro8KnmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eqbe3z/btsPioc8I12/8BsFHu2ZK7DzK5Gro8KnmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feqbe3z%2FbtsPioc8I12%2F8BsFHu2ZK7DzK5Gro8KnmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1306&quot; height=&quot;480&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HIStateManager.ts&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752503972040&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export class HIStateManager&amp;lt;T&amp;gt; {
  private state: T;
  private listeners: StateListener[] = [];

  constructor(initialState: T) {
    this.state = initialState;
  }

  setState = (param: SetStateParam&amp;lt;T&amp;gt;) =&amp;gt; {
    if (param instanceof Function) {
      const newState = param(this.state);
      this.state = newState;
    } else {
      this.state = param;
    }
    this.emitChange();
  };

  getState = () =&amp;gt; {
    return this.state;
  };

  subscribe = (listener: StateListener) =&amp;gt; {
    this.listeners = [...this.listeners, listener];
    return () =&amp;gt; {
      this.listeners = this.listeners.filter((l) =&amp;gt; l !== listener);
    };
  };

  emitChange = () =&amp;gt; {
    for (let listener of this.listeners) {
      listener();
    }
  };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이&amp;nbsp;HIStateManager&amp;nbsp;클래스는&amp;nbsp;React&amp;nbsp;외부에서&amp;nbsp;상태를&amp;nbsp;관리하는&amp;nbsp;외부&amp;nbsp;스토어입니다.&lt;br /&gt;setState는&amp;nbsp;새로운&amp;nbsp;상태를&amp;nbsp;직접&amp;nbsp;전달하거나,&amp;nbsp;이전&amp;nbsp;상태를&amp;nbsp;기반으로&amp;nbsp;한&amp;nbsp;콜백&amp;nbsp;함수를&amp;nbsp;받아&amp;nbsp;상태를&amp;nbsp;업데이트할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;상태가&amp;nbsp;변경되면&amp;nbsp;등록된&amp;nbsp;listeners(예:&amp;nbsp;handleStoreChange&amp;nbsp;같은&amp;nbsp;구독&amp;nbsp;함수)들에게&amp;nbsp;emitChange를&amp;nbsp;통해&amp;nbsp;변화를&amp;nbsp;알림으로써,&amp;nbsp;React&amp;nbsp;컴포넌트가&amp;nbsp;이를&amp;nbsp;감지하고&amp;nbsp;리렌더링할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;hooks/HIState.ts&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752504037043&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Atom&amp;lt;T&amp;gt; {
  key: string;
  default: T;
}

interface GlobalStateMapValue&amp;lt;T&amp;gt; {
  atom: Atom&amp;lt;T&amp;gt;;
  stateManager: HIStateManager&amp;lt;T&amp;gt;;
}

type SetterOrUpdater&amp;lt;T&amp;gt; = (valOrUpdater: ((currVal: T) =&amp;gt; T) | T) =&amp;gt; void;

const globalStateMap = new Map&amp;lt;string, GlobalStateMapValue&amp;lt;any&amp;gt;&amp;gt;();


export function useHIState&amp;lt;T&amp;gt;(atom: Atom&amp;lt;T&amp;gt;): [T, SetterOrUpdater&amp;lt;T&amp;gt;] {
  const store = globalStateMap.get(atom.key)!.stateManager;

  const value = useSyncExternalStore(store.subscribe, store.getState);

  return [value, store.setState];
}

export function useHIStateValue&amp;lt;T&amp;gt;(atom: Atom&amp;lt;T&amp;gt;): T {
  const store = globalStateMap.get(atom.key)!.stateManager;

  const value = useSyncExternalStore(store.subscribe, store.getState);

  return value;
}

export function useSetHiState&amp;lt;T&amp;gt;(atom: Atom&amp;lt;T&amp;gt;): SetterOrUpdater&amp;lt;T&amp;gt; {
  const globalStateMapValue = globalStateMap.get(atom.key)!;
  return globalStateMapValue.stateManager.setState;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;이 훅들은 HIStateManager로 관리되는 외부 상태를 &lt;b&gt;React 컴포넌트와 안전하게 동기화(sync) 해주는&amp;nbsp;커스텀 훅&lt;/b&gt;들입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useSyncExternalStore(store.subscribe, store.getState)를 사용하여 외부 스토어의 현재 상태를 구독하고, 상태 변경 시 자동으로 컴포넌트를 리렌더링합니다. hook들은 recoil에서 제공하는 기능을 본따서 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752504174011&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function createHISAtom&amp;lt;T&amp;gt;(atom: Atom&amp;lt;T&amp;gt;): Atom&amp;lt;T&amp;gt; {
  if (globalStateMap.has(atom.key)) {
    console.warn(`[HIState] Duplicate key &quot;${atom.key}&quot; ignored.`);
    return globalStateMap.get(atom.key)!.atom;
  }

  const stateManager = new HIStateManager&amp;lt;T&amp;gt;(atom.default);

  globalStateMap.set(atom.key, {
    atom,
    stateManager,
  });
  return atom;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;외부&amp;nbsp;스토어를&amp;nbsp;생성하는&amp;nbsp;유틸&amp;nbsp;함수&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Page.tsx&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752504208896&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Page() {
	const [counter, setCounter] = useHIState(counterState);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;간단하게 쓸 수 있습니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Recoil 사용&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXF7hC/btsPhHdcmrq/2DLaKqoJrGvLopKI7KMS51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXF7hC/btsPhHdcmrq/2DLaKqoJrGvLopKI7KMS51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXF7hC/btsPhHdcmrq/2DLaKqoJrGvLopKI7KMS51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXF7hC%2FbtsPhHdcmrq%2F2DLaKqoJrGvLopKI7KMS51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;68&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제작 라이브러리 사용&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pqbGl/btsPhlamOTr/mQZcI46h7tbyBikXQxWZIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pqbGl/btsPhlamOTr/mQZcI46h7tbyBikXQxWZIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pqbGl/btsPhlamOTr/mQZcI46h7tbyBikXQxWZIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpqbGl%2FbtsPhlamOTr%2FmQZcI46h7tbyBikXQxWZIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;78&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gzip 기준&lt;b&gt; 718.76 KB &amp;rarr; 695.15 KB (약 3.28% 감소)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작지만 소중한 개선이 이루어졌습니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 PR에서 모든 코드를 확인하실 수 있습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/HandongSF/histudy-fe/pull/132&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/HandongSF/histudy-fe/pull/132&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752504728979&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Feat/131 global state lib by ohinhyuk &amp;middot; Pull Request #132 &amp;middot; HandongSF/histudy-fe&quot; data-og-description=&quot;작업 사항 Recoil 제거 전 Recoil 제거 후 gzip 기준 718.76 KB &amp;rarr; 695.15 KB &amp;rarr; 약 3.28% 감소 관련 이슈 close #131&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/HandongSF/histudy-fe/pull/132&quot; data-og-url=&quot;https://github.com/HandongSF/histudy-fe/pull/132&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/t9JnE/hyZja3AikW/nYMgcL1okoQgFZy66sSOr0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/cVKEDx/hyZnat9Car/FmOLojbrHwU8koeHJwlPBK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/HandongSF/histudy-fe/pull/132&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/HandongSF/histudy-fe/pull/132&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/t9JnE/hyZja3AikW/nYMgcL1okoQgFZy66sSOr0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/cVKEDx/hyZnat9Car/FmOLojbrHwU8koeHJwlPBK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Feat/131 global state lib by ohinhyuk &amp;middot; Pull Request #132 &amp;middot; HandongSF/histudy-fe&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;작업 사항 Recoil 제거 전 Recoil 제거 후 gzip 기준 718.76 KB &amp;rarr; 695.15 KB &amp;rarr; 약 3.28% 감소 관련 이슈 close #131&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>React</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/95</guid>
      <comments>https://8156217.tistory.com/95#entry95comment</comments>
      <pubDate>Mon, 14 Jul 2025 23:47:18 +0900</pubDate>
    </item>
    <item>
      <title>이미지 포맷 비교 분석 (JPG, PNG, WebP, HEIC, AVIF)</title>
      <link>https://8156217.tistory.com/94</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 웹 성능에 직접적인 영향을 줄 정도로 &lt;span&gt;&lt;b&gt;용량이 큰 리소스&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &lt;span&gt;우리 서비스는 사진 포함 콘텐츠가 중심이기 때문에, &lt;/span&gt;&lt;b&gt;웹에 사용할 이미지 포맷을 어떻게 선택하느냐가 성능에 직접적인 영향을 줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 대표적인 이미지 포맷인 JPG, PNG, WebP, HEIC, AVIF의 &lt;span&gt;&lt;b&gt;기술적 특징과 브라우저 호환성&lt;/b&gt;&lt;/span&gt;을 비교 분석하고, 어떤 포맷이 우리 서비스에 적합한지를 판단해봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가장 익숙한 포맷인 JPG와 PNG를 먼저 비교하기 전에 얘네한테 사용된 압축 기술에 대해서 먼저 알아봅시다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;압축(&lt;b&gt;Compression&lt;/b&gt;) 방식&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지에서 사용하는 압축 방식은 크게 두 가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 손실 압축 (Lossy Compression)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;압축률이 높아 파일 크기를 크게 줄일 수 있습니다.&lt;/li&gt;
&lt;li&gt;다만 파일 압축 시 이미지의 일부 데이터가 영구적으로 삭제 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예: JPG&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 무손실 압축 (Lossless Compression)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;압축 후에도 모든 이미지 데이터가 그대로 보존됩니다.&lt;/li&gt;
&lt;li&gt;주로 로고, UI, 그래픽, 그래프 등 디테일이 중요한 이미지에 적합합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예: PNG&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JPG vs PNG&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;1) JPG (JPEG)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPG는 1992년에 Joint Photographic Experts Group에서 개발한 이미지 포맷으로, &lt;span&gt;&lt;b&gt;손실 압축 방식&lt;/b&gt;&lt;/span&gt;을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장 큰 장점은 &lt;/span&gt;&lt;b&gt;파일 크기가 작고 웹 호환성이 매우 뛰어나며&lt;/b&gt;&lt;span&gt;, 특히 &lt;/span&gt;&lt;b&gt;사진과 같이 색상 변화가 많은 이미지에 적합&lt;/b&gt;&lt;span&gt;하다는 점입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 압축 과정에서 일부 이미지 정보가 손실되기 때문에 &lt;span&gt;&lt;b&gt;화질이 저하될 수 있고&lt;/b&gt;&lt;/span&gt;, &lt;span&gt;&lt;b&gt;투명 배경을 지원하지 않는다는 단점&lt;/b&gt;&lt;/span&gt;이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) PNG&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PNG는 1996년에 PNG Development Group에 의해 개발된 이미지 포맷으로, &lt;span&gt;&lt;b&gt;무손실 압축 방식&lt;/b&gt;&lt;/span&gt;을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미지 데이터를 손상시키지 않고 저장하므로 &lt;/span&gt;&lt;b&gt;화질이 유지되며&lt;/b&gt;&lt;span&gt;, &lt;/span&gt;&lt;b&gt;투명도(알파 채널)를 지원&lt;/b&gt;&lt;span&gt;하고 &lt;/span&gt;&lt;b&gt;픽셀 단위의 정밀한 표현이 가능&lt;/b&gt;&lt;span&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;span&gt;&lt;b&gt;파일 크기가 크고&lt;/b&gt;&lt;/span&gt;, 연속적인 색상 변화가 많은 &lt;span&gt;&lt;b&gt;일반 사진에는 비효율적&lt;/b&gt;&lt;/span&gt;이어서 주로 &lt;span&gt;&lt;b&gt;로고, 아이콘, UI 요소&lt;/b&gt;&lt;/span&gt; 등에 적합합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.adobe.com/kr/creativecloud/file-types/image/comparison/jpeg-vs-png.html&quot;&gt;Adobe 공식 JPG vs PNG 비교&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1751898172733&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;JPEG와 TIFF 파일의 용도 | Adobe&quot; data-og-description=&quot;JPEG와 PNG는 가장 널리 사용되는 이미지 파일 포맷입니다. 두 파일의 주요 특징과 차이점, 용도를 살펴보세요.&quot; data-og-host=&quot;www.adobe.com&quot; data-og-source-url=&quot;https://www.adobe.com/kr/creativecloud/file-types/image/comparison/jpeg-vs-png.html&quot; data-og-url=&quot;https://www.adobe.com/kr/creativecloud/file-types/image/comparison/jpeg-vs-png.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ccNebG/hyZjlJtpqV/1l84eqSYmr6mz4kaVc8hm0/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800,https://scrap.kakaocdn.net/dn/bs00Qa/hyZjsPnkgs/z0subkBU4GSQXILBYXWfok/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800,https://scrap.kakaocdn.net/dn/cKZptG/hyZfCzj2kP/ISEaHWwpQvZR0hTdNGzkdk/img.jpg?width=750&amp;amp;height=500&amp;amp;face=0_0_750_500&quot;&gt;&lt;a href=&quot;https://www.adobe.com/kr/creativecloud/file-types/image/comparison/jpeg-vs-png.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.adobe.com/kr/creativecloud/file-types/image/comparison/jpeg-vs-png.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ccNebG/hyZjlJtpqV/1l84eqSYmr6mz4kaVc8hm0/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800,https://scrap.kakaocdn.net/dn/bs00Qa/hyZjsPnkgs/z0subkBU4GSQXILBYXWfok/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800,https://scrap.kakaocdn.net/dn/cKZptG/hyZfCzj2kP/ISEaHWwpQvZR0hTdNGzkdk/img.jpg?width=750&amp;amp;height=500&amp;amp;face=0_0_750_500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;JPEG와 TIFF 파일의 용도 | Adobe&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JPEG와 PNG는 가장 널리 사용되는 이미지 파일 포맷입니다. 두 파일의 주요 특징과 차이점, 용도를 살펴보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.adobe.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 최적화를 위한 다른 차세대 확장자들을 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;WebP 이란??&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WebP는&lt;/b&gt; &lt;b&gt;2010년에 Google이 개발한, 손실과 무손실 압축을 모두 지원하는 웹 최적화 이미지 포맷&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;투명도와 애니메이션도 지원하며, &lt;span&gt;&lt;b&gt;동일 품질 대비 더 작은 파일 크기를 제공&lt;/b&gt;&lt;/span&gt;하는 것이 핵심입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파일 크기가 무려&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;JPG보다 &lt;span&gt;25~34% 더 작으며 &lt;/span&gt;PNG보다 &lt;span&gt;26% 더 작습니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;호환성은 어떨까&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2025년 기준 Can I use&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BiRVX/btsO7E8tVQt/WeMWiY4eBwKr0AOJikzPHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BiRVX/btsO7E8tVQt/WeMWiY4eBwKr0AOJikzPHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BiRVX/btsO7E8tVQt/WeMWiY4eBwKr0AOJikzPHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBiRVX%2FbtsO7E8tVQt%2FWeMWiY4eBwKr0AOJikzPHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;642&quot; height=&quot;385&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Chrome, Firefox, Safari, Edge 등 주요 브라우저 모두 지원&lt;/li&gt;
&lt;li&gt;IE(Internet Explorer)만 미지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;더 더 높은 압축률의 HEIC, AVIF&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HEIC (High Efficiency Image Container)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HEIC는 2015년 MPEG에서 만든 이미지 포맷으로, 애플이 iOS 11부터 기본으로 사용하고 있는 형식입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아이폰을 쓰신 분들은 많이 보셨을 확장자입니다 ㅎㅎ&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일반적인 JPG보다 &lt;/span&gt;&lt;b&gt;훨씬 적은 용량으로 고화질 이미지를 저장&lt;/b&gt;&lt;span&gt;할 수 있고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;HDR 효과&lt;/b&gt;&lt;/span&gt;, &lt;span&gt;&lt;b&gt;라이브 포토&lt;/b&gt;&lt;/span&gt;, &lt;span&gt;&lt;b&gt;심도 정보&lt;/b&gt;&lt;/span&gt;처럼 아이폰의 다양한 사진 기능을 담을 수 있다는 게 큰 장점이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;하지만 호환성이...&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;560&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vetqd/btsO8J2dz9F/t5tvKpOz36C5xONXG7tsQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vetqd/btsO8J2dz9F/t5tvKpOz36C5xONXG7tsQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vetqd/btsO8J2dz9F/t5tvKpOz36C5xONXG7tsQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvetqd%2FbtsO8J2dz9F%2Ft5tvKpOz36C5xONXG7tsQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;618&quot; height=&quot;383&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;560&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상 웹을 위한 이미지 포맷은 아닌 듯 하네요...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AVIF (AV1 Image File Format)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AVIF는 2019년에 Google, Netflix 같은 기업들이 참여한 &amp;lsquo;Alliance for Open Media&amp;rsquo;라는 단체에서 만든 이미지 포맷입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 저도 이번에 처음 알았는데, 기존의 WebP보다도 &lt;span&gt;&lt;b&gt;더 높은 압축률&lt;/b&gt;&lt;/span&gt;과 &lt;span&gt;&lt;b&gt;HDR, 무손실 압축, 투명도 지원&lt;/b&gt;&lt;/span&gt; 같은 &lt;span&gt;&lt;b&gt;고급 기능&lt;/b&gt;&lt;/span&gt;까지 갖춘 포맷이라고 합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;과연 이 친구의 호환성은?&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egvLs8/btsO8bE2Rym/INhKZROVJOkZW54ZKvqaJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egvLs8/btsO8bE2Rym/INhKZROVJOkZW54ZKvqaJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egvLs8/btsO8bE2Rym/INhKZROVJOkZW54ZKvqaJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FegvLs8%2FbtsO8bE2Rym%2FINhKZROVJOkZW54ZKvqaJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;565&quot; height=&quot;348&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;556&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직까지는&amp;nbsp;&lt;span&gt;&lt;b&gt;브라우저와 툴의 지원 범위가 제한적&lt;/b&gt;&lt;/span&gt;이며, 일반 이미지 뷰어에서도 미리보기가 안 되는 경우가 많다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;can i use에서도 webP에 비해 지원하는 버전이 적은 것을 확인하실 수 있습니다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fallback 전략 없이 단독으로 사용하긴 어려워 보이네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론:&amp;nbsp; &lt;/b&gt;&lt;b&gt;WebP 선택&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;WebP는&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;JPG, PNG 대비 용량이 작으면서도, HEIC와 AVIF와 달리 주요 브라우저에서도 안정적으로 지원&lt;/b&gt;&lt;span&gt;됩니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 GA(구글 애널리틱스)를 확인해본 결과, 우리 서비스에서는 &lt;span&gt;&lt;b&gt;Internet Explorer의 사용률이 0%이기 &lt;/b&gt;때문에&lt;/span&gt; WebP 도입에 문제가 없다고 판단했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;높은 압축률과 높은 호환성을 위해서 WebP를 택하게 되었습니다 :)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-07 오후 11.13.07.png&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQVGR1/btsO78BEwLh/c5Ekwss4EUbB1bB0zqDr8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQVGR1/btsO78BEwLh/c5Ekwss4EUbB1bB0zqDr8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQVGR1/btsO78BEwLh/c5Ekwss4EUbB1bB0zqDr8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQVGR1%2FbtsO78BEwLh%2Fc5Ekwss4EUbB1bB0zqDr8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;208&quot; data-filename=&quot;스크린샷 2025-07-07 오후 11.13.07.png&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/94</guid>
      <comments>https://8156217.tistory.com/94#entry94comment</comments>
      <pubDate>Mon, 7 Jul 2025 23:26:53 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Middleware를 활용한 인증 처리 통합</title>
      <link>https://8156217.tistory.com/93</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기존 인증 로직 관리 문제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트&amp;nbsp;내&amp;nbsp;&lt;b&gt;인증&amp;nbsp;및&amp;nbsp;권한&amp;nbsp;검사&amp;nbsp;로직이&amp;nbsp;각&amp;nbsp;페이지와&amp;nbsp;API&amp;nbsp;핸들러에&amp;nbsp;흩어져&amp;nbsp;있었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 페이지마다 인증/인가 처리를 하고 있으며,&lt;/li&gt;
&lt;li&gt;API 보호를 위해 각 handler 내부에 반복적으로 인증 검사를 호출하고 있었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 방식은 새 기능을 추가할 때마다 중복 로직이 추가되고, 또 로직이 흩어져 있어서 관리도 어렵습니다.&lt;br /&gt;&lt;br /&gt;그래서&amp;nbsp;요청이&amp;nbsp;들어오는&amp;nbsp;가장&amp;nbsp;앞단,&amp;nbsp;즉&amp;nbsp;&lt;b&gt;middleware에서&amp;nbsp;인증을&amp;nbsp;일괄&amp;nbsp;처리&lt;/b&gt;해보기로&amp;nbsp;했습니다.&lt;br /&gt;이렇게 하면 인증에 대한 처리를 각 페이지나 API에서 따로 신경 쓰지 않아도 되는 장점이 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;br /&gt;&lt;b&gt;Middleware으로&amp;nbsp;기존&amp;nbsp;로직&amp;nbsp;마이그레이션&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 기존의 접근 제어 로직을 middleware.ts에 그대로 옮겨 적용해봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;middleware.ts&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751805373231&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export async function middleware(request: NextRequest) {
  const token = request.cookies.get(&quot;token&quot;)?.value;

  if (!token) {
    return NextResponse.redirect(new URL(&quot;/logout&quot;, request.url));
  }

  try {
    const payload = await verifyToken(token);

    const hasPermission = checkPermission({
      path: request.nextUrl.pathname,
      role: payload.role,
      permissions: payload.permissions,
    });

    if (!hasPermission) {
      return NextResponse.redirect(new URL(&quot;/forbidden&quot;, request.url));
    }

    return NextResponse.next();
  } catch {
    return NextResponse.redirect(new URL(&quot;/logout&quot;, request.url));
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그러나 실행과 동시에 다음과 같은 에러가 발생했습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Error: The edge runtime does not support Node.js 'crypto' module.&amp;nbsp;&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때부터 뭔가 쉽지 않겠다는 생각이 들었습니다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열심히 알아보니 middleware에는 독특한 특징이 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Middleware는&lt;/span&gt; next 서버 (node runtime) 와는 다르게 &lt;b&gt;edge runtime&lt;/b&gt; 위에서 동작합니다.&lt;br /&gt;&lt;a href=&quot;https://nextjs.org/docs/app/api-reference/edge&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nextjs.org/docs/app/api-reference/edge&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Edge Runtime&lt;/b&gt;이란?&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Node.js가 아닌 &lt;b&gt;Web API 기반의 경량 실행 환경&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;빠르고 가볍지만, &lt;b&gt;Node 내장 모듈을 사용할 수 없고 사용 가능 API가 제한 적임&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 기존에 사용하던 MongoDB 클라이언트, node-cache, createHash 같은 기능을 지원하지 않습니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;*edge에서 지원하는 API들&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://nextjs.org/docs/app/api-reference/edge#reference&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nextjs.org/docs/app/api-reference/edge#reference&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 기존 로직을 그대로 사용하는 것은 어려워 보이는데 어떻게 해결할 수 있을까??&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;시도 1: Middleware를 Node.js 런타임으로 전환&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js의 canary 버전에서는 middleware의 runtime을 'nodejs'로 설정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;middleware.ts&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751805789454&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const config = {
  runtime: &quot;nodejs&quot;, // Canary 버전에서만 지원
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이렇게 하면 Node 전용 API를 사용할 수 있어 기존 로직으로 구현할 수 있습니다.&lt;br /&gt;그러나 &lt;b&gt;canary는 실험적이기 때문에 안정성이 떨어지고,&lt;/b&gt; &lt;b&gt;production에서는 사용이 권장되지 않아 보류하였습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;시도 2: Edge-safe 방식으로 구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;이슈 1) JWT 라이브러리 사용 제약&lt;/b&gt;&lt;br /&gt;많은&amp;nbsp;JWT&amp;nbsp;라이브러리(예:&amp;nbsp;jsonwebtoken)는&amp;nbsp;Node.js&amp;nbsp;전용&amp;nbsp;API에&amp;nbsp;의존하고&amp;nbsp;있어&amp;nbsp;Edge&amp;nbsp;Runtime에서&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없습니다.&lt;br /&gt;-&amp;gt; &lt;b&gt;그러나 다행히 현재 사용중인 jose는 Edge 환경에서도 지원됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;이슈 2) Node.js 내장 모듈 사용 불가 (node:crypto, node:cache 등)&lt;/b&gt;&lt;br /&gt;Edge&amp;nbsp;Runtime에서는&amp;nbsp;node:crypto&amp;nbsp;등&amp;nbsp;Node&amp;nbsp;고유&amp;nbsp;모듈을&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없습니다.&lt;br /&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;Web&amp;nbsp;Crypto&amp;nbsp;API를&amp;nbsp;사용하여&amp;nbsp;해시,&amp;nbsp;암호화&amp;nbsp;등의&amp;nbsp;기능을&amp;nbsp;대체할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751806789016&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const hashBuffer = await crypto.subtle.digest(
  &quot;SHA-256&quot;,
  new TextEncoder().encode(&quot;hello&quot;)
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이슈 3) MongoDB 클라이언트 사용 불가&lt;/b&gt;&lt;br /&gt;기존에는 JWT 검증을 위해 JWK 키를 MongoDB에서 가져오는 구조였지만, Edge 환경에서는 DB 클라이언트가 동작하지 않아 직접적인 DB 접근이 불가능합니다.&lt;br /&gt;-&amp;gt;&amp;nbsp;&lt;b&gt;JWK&amp;nbsp;키를&amp;nbsp;/api/jwks&amp;nbsp;같은&amp;nbsp;endpoint에&amp;nbsp;공개하고, middleware에서 fetch()를 통해 가져오는 방식으로 개선할 수 있습니다.&lt;/b&gt;&amp;nbsp;이는&amp;nbsp;엔터프라이즈&amp;nbsp;환경에서&amp;nbsp;JWK&amp;nbsp;키가&amp;nbsp;외부에&amp;nbsp;노출된다는&amp;nbsp;우려가&amp;nbsp;있긴&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;현 상황에서 Edge-safe 방식의 단점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 구현하면 Edge-safe 방식으로도 가능은 하지만,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;여러 인증 로직을 직접 Edge 환경에 맞게 재구현해야 하고,&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;middleware의 책임이 지나치게 커진다는 단점이 있습니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&amp;ldquo;어차피 fetch를 활용 할 거면, 로직 자체를 Route handler에 위임하는 게 더 낫지 않을까?&amp;rdquo;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;시도 3: 토큰 검증 로직을 Route handler로 위임 ✅&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;nbsp;middleware.ts:&lt;/b&gt; 토큰 유무 판단 및 리다이렉트 처리만 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Route Handler (/api/auth):&lt;/b&gt; JWT 서명 검증, 권한 검사 등 핵심 로직 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;middleware.ts&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751807190990&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export async function middleware(req: NextRequest) {
  const token = req.cookies.get(&quot;token&quot;)?.value;
  const pathname = req.nextUrl.pathname;

  if (!token) {
    return NextResponse.redirect(new URL(&quot;/logout&quot;, req.url));
  }

  const authResult = await fetch(`{NEXT_BASE_URL}/api/auth`, {
    method: &quot;POST&quot;,
    headers: {
      Cookie: token,
    },
    body: JSON.stringify({
      pathname,
    }),
  });

  if (authResult.status === 401) {
    return NextResponse.redirect(new URL(&quot;/logout&quot;, req.url));
  } else if (authResult.status === 403) {
    return NextResponse.redirect(new URL(&quot;/forbidden&quot;, req.url));
  }
  return response;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;middleware는 요청 흐름만 제어 &amp;rarr; 코드가 간단하고 가독성 높음&lt;/li&gt;
&lt;li&gt;인증 로직은 Node.js 환경에서 자유롭게 구현 가능&lt;/li&gt;
&lt;li&gt;JWK를 기존처럼 외부에 노출할 필요 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;최종 결정 및 요약&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 상황에서는 &lt;b&gt;토큰 검증 로직을 Route handler로 위임하는 방식이 가장 현실적이고 적합&lt;/b&gt;하다고 판단했습니다.&lt;br /&gt;&lt;b&gt;핵심&amp;nbsp;인증/권한&amp;nbsp;로직은&amp;nbsp;그대로&amp;nbsp;유지하면서도,&amp;nbsp;Edge&amp;nbsp;환경의&amp;nbsp;제약을&amp;nbsp;피할&amp;nbsp;수&amp;nbsp;있기&amp;nbsp;때문입니다.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Next.js&amp;nbsp;App&amp;nbsp;Router의&amp;nbsp;middleware는&amp;nbsp;인증&amp;nbsp;흐름을&amp;nbsp;통일하는&amp;nbsp;데&amp;nbsp;효과적인&amp;nbsp;도구입니다.&lt;br /&gt;하지만&amp;nbsp;Edge&amp;nbsp;Runtime이라는&amp;nbsp;제약&amp;nbsp;조건&amp;nbsp;때문에&amp;nbsp;Node.js&amp;nbsp;고유&amp;nbsp;기능들을&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없으므로,&amp;nbsp;모든&amp;nbsp;인증&amp;nbsp;로직을&amp;nbsp;middleware&amp;nbsp;내부에서&amp;nbsp;처리하기에는&amp;nbsp;한계가&amp;nbsp;있습니다.&lt;br /&gt;&lt;br /&gt;따라서&amp;nbsp;우리는&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;구조를&amp;nbsp;선택했습니다:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;bull;&amp;nbsp;middleware:&amp;nbsp;요청&amp;nbsp;흐름을&amp;nbsp;제어&amp;nbsp;(토큰&amp;nbsp;유무&amp;nbsp;판단,&amp;nbsp;리다이렉트&amp;nbsp;등)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;bull; Route handler (/api/auth): Node.js 환경에서 실제 토큰 검증 및 권한 판단 수행&lt;br /&gt;&lt;br /&gt;향후에&amp;nbsp;Next.js에서&amp;nbsp;정식&amp;nbsp;릴리즈에서&amp;nbsp;middleware의&amp;nbsp;Node.js&amp;nbsp;runtime&amp;nbsp;지원이&amp;nbsp;될&amp;nbsp;수&amp;nbsp;있다고&amp;nbsp;하니&amp;nbsp;지켜&amp;nbsp;봐야겠습니다&amp;nbsp;:)&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/93</guid>
      <comments>https://8156217.tistory.com/93#entry93comment</comments>
      <pubDate>Sun, 6 Jul 2025 22:10:04 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] pre-fetch를 통한 초기 렌더링 최적화</title>
      <link>https://8156217.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;현재 서비스에는 현재 생성 상태를 확인하기 위해 주기적인 &lt;b&gt;polling&lt;/b&gt;을 하거나, &lt;b&gt;사용자의&amp;nbsp;상호작용에&amp;nbsp;따라&amp;nbsp;데이터를&amp;nbsp;요청&lt;/b&gt;해야 하는 경우가 종종 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 경우, 클라이언트 컴포넌트에서 &lt;span&gt;&lt;b&gt;여러 번 fetch를 트리거해야 하며&lt;/b&gt;&lt;/span&gt;, 이를 효율적으로 관리하기 위해 &lt;span&gt;&lt;b&gt;useQuery를 적극 활용&lt;/b&gt;&lt;/span&gt;하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;useQuery&lt;/span&gt;를 사용하는 이유는 다음과 같은 처리를 간단하게 해결할 수 있기 때문입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;캐시 관리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;폴링 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;로딩 및 에러 상태 핸들링&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 이러한 요구사항을 가진 클라이언트 컴포넌트에서 &lt;b&gt;데이터 fetch를 어떻게 최적화했는지에 대한 경험을 공유&lt;/b&gt;&lt;span&gt;해보려고 합니다&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기존&amp;nbsp; 구조&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-05 오후 2.41.46.png&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9M4yJ/btsO5oSGiHf/we1fMzg6YQmIAKWpc8pWz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9M4yJ/btsO5oSGiHf/we1fMzg6YQmIAKWpc8pWz1/img.png&quot; data-alt=&quot;기존 요청 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9M4yJ/btsO5oSGiHf/we1fMzg6YQmIAKWpc8pWz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9M4yJ%2FbtsO5oSGiHf%2Fwe1fMzg6YQmIAKWpc8pWz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;660&quot; height=&quot;158&quot; data-filename=&quot;스크린샷 2025-07-05 오후 2.41.46.png&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기존 요청 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 관리 페이지는 다음과 같은 두 개의 요청을 처리합니다.&lt;br /&gt;1. 데이터&amp;nbsp;목록&amp;nbsp;조회&lt;br /&gt;2. 선택된&amp;nbsp;항목의&amp;nbsp;상세&amp;nbsp;분석&amp;nbsp;결과&amp;nbsp;조회&lt;br /&gt;&lt;br /&gt;사용자는&amp;nbsp;먼저&amp;nbsp;목록을&amp;nbsp;보고,&amp;nbsp;그&amp;nbsp;중&amp;nbsp;하나를&amp;nbsp;선택하면&amp;nbsp;분석&amp;nbsp;결과가&amp;nbsp;출력되는&amp;nbsp;구조입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 목록이 렌더링 되면 자동으로 첫 번째 데이터가 자동 선택되는 기능이 있습니다.&lt;br /&gt;이 구조에서 다음과 같은 두 가지 성능 문제가 존재했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제점&amp;nbsp;1:&amp;nbsp;초기&amp;nbsp;로딩&amp;nbsp;문제&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자는&amp;nbsp;페이지&amp;nbsp;진입&amp;nbsp;직후&amp;nbsp;상당한&amp;nbsp;시간&amp;nbsp;동안&amp;nbsp;로딩&amp;nbsp;UI를&amp;nbsp;봐야&amp;nbsp;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1MwTX/btsO6Bb5hL5/vp1Tw1yiJ5cVa9dAh3Khy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1MwTX/btsO6Bb5hL5/vp1Tw1yiJ5cVa9dAh3Khy0/img.png&quot; data-alt=&quot;로딩 예시 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1MwTX/btsO6Bb5hL5/vp1Tw1yiJ5cVa9dAh3Khy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1MwTX%2FbtsO6Bb5hL5%2Fvp1Tw1yiJ5cVa9dAh3Khy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;512&quot; height=&quot;250&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;로딩 예시 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ5WJI/btsO7e8yexc/xIKabtnQGmNfzoTvmvK5rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ5WJI/btsO7e8yexc/xIKabtnQGmNfzoTvmvK5rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ5WJI/btsO7e8yexc/xIKabtnQGmNfzoTvmvK5rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ5WJI%2FbtsO7e8yexc%2FxIKabtnQGmNfzoTvmvK5rk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;90&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 원인은 &lt;b&gt;클라이언트에서 렌더링 된 후 보내는 늦은 요청&lt;/b&gt; 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해 데이터를 &lt;b&gt;서버에서 미리 프리패치&lt;/b&gt;하여, 페이지 진입 시 즉시 콘텐츠가 렌더링되도록 개선했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app/data/page.tsx&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751690948813&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;export default async function Page() {
  
  const dataList = await extDataService.getDataList(); // pre-fetch
  
  return (
    &amp;lt;DataView dataList={dataList} /&amp;gt; // client component
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 컴포넌트에서 데이터를 먼저 가져와 클라이언트 컴포넌트에 props로 전달하는 구조입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 진입 시 데이터를 미리 프리패치함으로써, &lt;b&gt;클라이언트에서 별도 요청 없이 즉시 렌더링이 가능&lt;/b&gt;합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제점&amp;nbsp;2:&amp;nbsp;워터폴&amp;nbsp;요청&amp;nbsp;(Waterfall&amp;nbsp;Requests)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두&amp;nbsp;번째&amp;nbsp;문제는&amp;nbsp;데이터&amp;nbsp;간의&amp;nbsp;의존성으로&amp;nbsp;인해&amp;nbsp;발생하는&amp;nbsp;워터폴&amp;nbsp;요청입니다.&lt;br /&gt;목록&amp;nbsp;중&amp;nbsp;첫&amp;nbsp;번째&amp;nbsp;항목이&amp;nbsp;기본적으로&amp;nbsp;자동&amp;nbsp;선택되는&amp;nbsp;로직을&amp;nbsp;넣다&amp;nbsp;보니&amp;nbsp;목록을&amp;nbsp;가져온&amp;nbsp;후&amp;nbsp;상세&amp;nbsp;분석&amp;nbsp;데이터를&amp;nbsp;추가로&amp;nbsp;요청하게&amp;nbsp;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L4V0k/btsO45y4xEi/pEU1hmXOBsv6q6vV6OTrUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L4V0k/btsO45y4xEi/pEU1hmXOBsv6q6vV6OTrUk/img.png&quot; data-alt=&quot;get_series 워터폴 요청 발생&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L4V0k/btsO45y4xEi/pEU1hmXOBsv6q6vV6OTrUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL4V0k%2FbtsO45y4xEi%2FpEU1hmXOBsv6q6vV6OTrUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;94&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;get_series 워터폴 요청 발생&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;서버에서&amp;nbsp;목록을&amp;nbsp;가져올&amp;nbsp;때,&amp;nbsp;목록의&amp;nbsp;첫&amp;nbsp;번째&amp;nbsp;항목에&amp;nbsp;대한&amp;nbsp;상세&amp;nbsp;데이터도&amp;nbsp;함께&amp;nbsp;미리&amp;nbsp;요청합니다.&lt;br /&gt;이&amp;nbsp;데이터를&amp;nbsp;React&amp;nbsp;Query의&amp;nbsp;prefetchQuery로&amp;nbsp;캐시에&amp;nbsp;등록한&amp;nbsp;뒤,&lt;br /&gt;dehydrate를&amp;nbsp;사용해&amp;nbsp;클라이언트로&amp;nbsp;직렬화해&amp;nbsp;전달합니다.&lt;br /&gt;&lt;br /&gt;클라이언트에서는&amp;nbsp;useQuery로&amp;nbsp;동일한&amp;nbsp;key로&amp;nbsp;요청을&amp;nbsp;보내면,&lt;br /&gt;이미 캐시에 존재하는 값이 즉시 사용되므로 별도의 fetch가 발생하지 않습니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app/data/page.tsx&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751691528227&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default async function Page() {

  const dataList = await dataService.getDataList();
  const firstItem = dataList[0];

  const queryClient = new QueryClient();

  await queryClient.prefetchQuery({
    queryKey: [&quot;detailData&quot;, firstItem.id],
    queryFn: () =&amp;gt;
      fetchDetailData(firstItem.id),
  });

  return (
    &amp;lt;HydrationBoundary state={dehydrate(queryClient)}&amp;gt;
      &amp;lt;DataView dataList={dataList} defaultItem={firstItem} /&amp;gt;
    &amp;lt;/HydrationBoundary&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app/components/client-component/data-view.tsx&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751691636477&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client';

export default function DataView({
	dataList, 
	defaultItem
}){
	const [selectedItem, setSelectedItem] = useState(defaultItem)

	const { data } = useQuery({
		queryKey: [&quot;detailData&quot;, selectedItem.id],
		queryFn: () =&amp;gt; fetchDetailData(selectedItem.id),
		refetchOnWindowFocus: false,
	});
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prefetchQuery 이후 캐시가 생성된 것을 devtools에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;924&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGRDZv/btsO6MEuAHp/npD7rTHrOjJn7YhTZsaNEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGRDZv/btsO6MEuAHp/npD7rTHrOjJn7YhTZsaNEk/img.png&quot; data-alt=&quot;react query devtools에서 캐시 조회&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGRDZv/btsO6MEuAHp/npD7rTHrOjJn7YhTZsaNEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGRDZv%2FbtsO6MEuAHp%2FnpD7rTHrOjJn7YhTZsaNEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;924&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;924&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;react query devtools에서 캐시 조회&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;개선 된 결과&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uVUWz/btsO6ZKyUoE/FdWMWrCXUrzT7bLAOdV9LK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uVUWz/btsO6ZKyUoE/FdWMWrCXUrzT7bLAOdV9LK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uVUWz/btsO6ZKyUoE/FdWMWrCXUrzT7bLAOdV9LK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuVUWz%2FbtsO6ZKyUoE%2FFdWMWrCXUrzT7bLAOdV9LK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;92&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;html의 응답이 이전 보다 좀 늦어졌습니다. 서버에서 프리패치를 진행하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 덕분에 그 이후로 fetch 요청이 발생하지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;초기 로딩 문제와 워터풀 요청을 모두 해결한 것으로 확인하였습니다 :)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답 시간도&lt;b&gt; 개선 전 930ms -&amp;gt; 개선후 420 ms 로 &lt;/b&gt;&lt;b&gt;약 55% 개선 &lt;/b&gt;되었습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-05 오후 2.46.36.png&quot; data-origin-width=&quot;1688&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNGq4S/btsO7hc7OKn/wi0v3qNkA2UVn1M9apbBW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNGq4S/btsO7hc7OKn/wi0v3qNkA2UVn1M9apbBW1/img.png&quot; data-alt=&quot;개선된 시스템 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNGq4S/btsO7hc7OKn/wi0v3qNkA2UVn1M9apbBW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNGq4S%2FbtsO7hc7OKn%2Fwi0v3qNkA2UVn1M9apbBW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1688&quot; height=&quot;454&quot; data-filename=&quot;스크린샷 2025-07-05 오후 2.46.36.png&quot; data-origin-width=&quot;1688&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개선된 시스템 구조&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/92</guid>
      <comments>https://8156217.tistory.com/92#entry92comment</comments>
      <pubDate>Sat, 5 Jul 2025 15:04:18 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] timezone 불일치로 인한 Hydration Failed 이슈</title>
      <link>https://8156217.tistory.com/91</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-04 오후 4.27.29.png&quot; data-origin-width=&quot;2376&quot; data-origin-height=&quot;1232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDTB51/btsO4lWd0Nl/jHcMdvk8GW50xKgcYJBnw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDTB51/btsO4lWd0Nl/jHcMdvk8GW50xKgcYJBnw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDTB51/btsO4lWd0Nl/jHcMdvk8GW50xKgcYJBnw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDTB51%2FbtsO4lWd0Nl%2FjHcMdvk8GW50xKgcYJBnw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2376&quot; height=&quot;1232&quot; data-filename=&quot;스크린샷 2025-07-04 오후 4.27.29.png&quot; data-origin-width=&quot;2376&quot; data-origin-height=&quot;1232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;Hydration failed because the server rendered HTML didn&amp;rsquo;t match the client. &lt;br /&gt;This can happen if a SSR-ed Client Component is used.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;서버와 클라이언트 간의 HTML 불일치 &lt;/b&gt;때문에 해당 에러가 발생했습니다.&lt;/span&gt;&lt;br /&gt;어떤 상황에서 이 문제가 발생했는지, 그리고 어떻게 해결했는지를 공유합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기존 날짜 처리 방식&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 다음 Util을 사용해서 날짜 데이터를 처리 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b; text-align: start;&quot;&gt;utils/date-format.ts&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751622300715&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function getFormattedLocaleDateString(date: string | Date) {
  if (typeof date === &quot;string&quot;) {
    return new Date(date).toLocaleDateString();
  } else if (typeof date === &quot;object&quot;) {
    return date.toLocaleDateString();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;toLocaleDateString() 는 &lt;span&gt;Date&lt;/span&gt; 객체를 &lt;b&gt;현지 표준 시간대와 언어 설정에 맞춰 문자열로 변환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 사용자의 로컬 타임존에 따라 날짜를 다르게 포맷팅합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;그게 왜 문제가 될까??&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트 컴포넌트의 경우 getFormattedLocaleDateString()&lt;/span&gt; 함수는 &lt;b&gt;서버에서도 실행되고, hydration 시 클라이언트에서도 동일하게 실행&lt;/b&gt;됩니다. 이 때 불일치가 발생합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버는 UTC 타임존 기준으로 날짜를 포매팅합니다.&lt;/li&gt;
&lt;li&gt;그러나 클라이언트는 사용자의 로컬 타임존(KST 등) 을 기준으로 포매팅합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span&gt;new Date().toLocaleDateString()의&lt;/span&gt; 결과가 서버와 클라이언트에서 다르기 때문에 hydration 시 HTML mismatch가 발생한 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-05 오후 12.30.41.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SXd9P/btsO6dJulb9/54vW4wS1MgKcqzsjejhPXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SXd9P/btsO6dJulb9/54vW4wS1MgKcqzsjejhPXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SXd9P/btsO6dJulb9/54vW4wS1MgKcqzsjejhPXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSXd9P%2FbtsO6dJulb9%2F54vW4wS1MgKcqzsjejhPXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1358&quot; height=&quot;232&quot; data-filename=&quot;스크린샷 2025-07-05 오후 12.30.41.png&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버(UTC)에서는 2025. 1. 11.로 렌더링됨&lt;/li&gt;
&lt;li&gt;클라이언트(KST)에서는 2025. 1. 12.로 렌더링됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 서로 다른 날짜 문자열이 나와 hydration 에러가 발생한 것입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;근데 &lt;/b&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;왜 서버는 UTC 기준인가?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js의 서버는 Node.js 환경에서 실행되며, UTC 타임존을 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 UTC 기준으로 동작해야 하는 이유는 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글로벌 사용자 기준으로 표준화된 시간 관리가 가능&lt;/li&gt;
&lt;li&gt;데이터 저장/변경 시 타임존 이슈 없이 일관성 있는 처리&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;생각 해보면 당연한 얘기죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;해결 방법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인은 파악했으니 문제를 해결하려면 SSR과 CSR 간 &lt;span&gt;&lt;b&gt;시간 표현 기준을 통일&lt;/b&gt;&lt;/span&gt;해야 합니다. 방법은 크게 두 가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. UTC 기준으로 포맷 고정하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 심플한 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;options에 timeZone을 추가하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751686626648&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new Date().toLocaleString(&quot;ko-KR&quot;, {timeZone: &quot;UTC&quot;})&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실제로도 많은 회사들이 UTC를 기준으로 모든 시간대를 통일하여 사용합니다.&lt;br /&gt;글로벌 서비스인 Datadog, AWS 서비스도 기본적으로 UTC를 기준으로 하죠.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 날짜를 클라이언트에서만 포매팅한다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751687223622&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client';

export function LocalizedDate({ date }: { date: string }) {
  const [formatted, setFormatted] = useState('');

  useEffect(() =&amp;gt; {
    const d = new Date(date);
    setFormatted(d.toLocaleDateString());
  }, [date]);

  return &amp;lt;span&amp;gt;{formatted}&amp;lt;/span&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;Hydration mismatch 문제는&lt;/span&gt; 서버에서 렌더링 한 것과 클라이언트에서 렌더링 한것이 다르기 때문에 일어납니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그러므로 &lt;b&gt;useEffect&lt;/b&gt;를 활용하여 포매팅을 진행해서 보여주면 해결 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;useEffect는 &lt;/span&gt;브라우저가 HTML을 렌더링한 후 실행되는&lt;b&gt; side effect hook &lt;/b&gt;이기 때문이죠.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 이 훅은 참고로 클라이언트에서만 실행 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;결론&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;2번 useEffect&lt;/span&gt; 방식&lt;/b&gt;도 hydration mismatch를 충분히 방지할 수 있지만, 초기 렌더링 시 잠깐 값이 비어 있거나 깜빡이는 현상이 발생합니다. &lt;b&gt;또한 모든 날짜 표시를 클라이언트에서 처리해야 하므로, 개발 관점에서 로직이 분산되고 유지보수가 어려워지는 단점이 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 우리는 서버와 클라이언트 모두에서 일관되게 동작하도록 &lt;span&gt;&lt;b&gt;UTC 기준으로 날짜 포맷을 통일&lt;/b&gt;&lt;/span&gt;하기로 했습니다 :)&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/91</guid>
      <comments>https://8156217.tistory.com/91#entry91comment</comments>
      <pubDate>Sat, 5 Jul 2025 12:58:38 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] 서버 컴포넌트에서의 에러 처리와 ErrorBoundary</title>
      <link>https://8156217.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5yBPc/btsO2qB3m45/nqQTgVZN7bPE1BqOk9xBa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5yBPc/btsO2qB3m45/nqQTgVZN7bPE1BqOk9xBa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5yBPc/btsO2qB3m45/nqQTgVZN7bPE1BqOk9xBa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5yBPc%2FbtsO2qB3m45%2FnqQTgVZN7bPE1BqOk9xBa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;86&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 상황&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 에러 화면이 출력 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 단순한 인증 오류로 보였다. 그런데 CSS도 전혀 적용되지 않고, 페이지 렌더링도 중단된 듯하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버 컴포넌트 렌더링 자체&lt;/b&gt;가 실패한 것처럼 보였고, &lt;b&gt;에러 바운더리(error.tsx)&lt;/b&gt;가 이를 제대로 처리하지 못한 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;뭐가 문제일까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제가 발생한 페이지의 코드의 형식은 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1751467579491&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default async function Page() {
  const data = await dataService.getData(); // 이 부분에서 에러 발생

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;DataTable data={data} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;dataService.getData()&lt;/span&gt;에서 예외가 발생하여 throw Error를 하였고, 이를 명시적으로 &lt;span&gt;try-catch&lt;/span&gt;로 감싸지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러는 상위로 전파되며 결국 서버에서의 렌더링에 문제가 생긴 것으로 보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;그런데 분명 &lt;span&gt;app/error.tsx&lt;/span&gt; 파일이 있는데 왜 이 에러를 처리하지 못했을까?&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;error.tsx&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751467722029&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client' // Error boundaries must be Client Components
 
import { useEffect } from 'react'
 
export default function Error({
  error,
  reset,
}: {
  error: Error &amp;amp; { digest?: string }
  reset: () =&amp;gt; void
}) {
  useEffect(() =&amp;gt; {
    // Log the error to an error reporting service
    console.error(error)
  }, [error])
 
  return (
    &amp;lt;div&amp;gt;
      
      ...
 
      &amp;lt;Button variant=&quot;outline&quot; size=&quot;lg&quot; onClick={reset}&amp;gt;
            다시 시도하기
          &amp;lt;/Button&amp;gt;
      &amp;lt;Link href=&quot;/login&quot;&amp;gt;
        &amp;lt;Button variant=&quot;delete&quot; size=&quot;lg&quot; className=&quot;w-full&quot;&amp;gt;
              로그인 화면으로 이동하기
        &amp;lt;/Button&amp;gt;
       &amp;lt;/Link&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 컴포넌트로 잘 작성되어 있었다. 에러가 났던 화면에 코드에서의 버튼도 보이는 걸 보면 error.tsx가 렌더링 되긴 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 부실해보이지만..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;다만 서버의 서비스 단에서 던진 에러 메세지는&amp;nbsp;error.tsx까지 도달하지 않았다.&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;로컬에서 재연&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSNvuG/btsO0D3rf44/xb1p975khXCdyAgz5KSBlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSNvuG/btsO0D3rf44/xb1p975khXCdyAgz5KSBlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSNvuG/btsO0D3rf44/xb1p975khXCdyAgz5KSBlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSNvuG%2FbtsO0D3rf44%2Fxb1p975khXCdyAgz5KSBlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;514&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음?? 로컬에서는 에러 바운더리가 서버 에러를 잘 잡아낸다.&lt;br /&gt;그래서 검색을 해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서버 컴포넌트의 에러는 Error Boundary로 전달되지 않는다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js 공식 문서 및 관련 GitHub Discussions에 따르면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. &lt;/span&gt;서버 컴포넌트에서 렌더링 도중 잡지 못한 에러는 React의 Error Boundary(&lt;span&gt;error.tsx&lt;/span&gt;)로 전달되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. &lt;b&gt;그러나&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;개발 모드에서는 디버깅을 위해 서버의 에러 메세지를 그대로 전달하여 보여 준다.&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로덕션에서는 보안 상 이유 (DB connection 에러 정보 등)로 해당 에러 메시지를 클라이언트에 전달않고 단순화 해서 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;그럼 Error Boundary는 언제 동작하고, 언제 동작하지 않는가?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 &lt;span&gt;&lt;b&gt;Error Boundary&lt;/b&gt;&lt;/span&gt;는 컴포넌트 트리 내에서 발생하는 예외를 잡아내고, fallback UI를 렌더링할 수 있게 해주는 안전장치다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 그 역할과 한계를 명확히 이해하고 써야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;error-boundary.js&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751468136795&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  // 렌더링에 영향을 주는 상태 업데이트
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  // 실제 에러 로깅은 여기서 수행
  componentDidCatch(error, errorInfo) {
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return &amp;lt;h1&amp;gt;문제가 발생했습니다.&amp;lt;/h1&amp;gt;;
    }

    return this.props.children;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 핵심은 &lt;/span&gt;&lt;b&gt;componentDidCatch는 클래스 컴포넌트의 생명주기 메서드라는 점&lt;/b&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 컴포넌트에서는 메서드를 사용할 수 없기 때문에, Error Boundary는 반드시 클래스 컴포넌트로 작성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그런데 중요한 제약이 있다&lt;/b&gt;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;Error Boundary는 오직 &amp;ldquo;렌더링 중&amp;rdquo; 발생한 에러만 처리할 수 있다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;처리할 수 있는 상황&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- render()&lt;/span&gt; 중 터진 에러&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- 생명주기 메서드 (&lt;/span&gt;constructor&lt;span&gt;, &lt;/span&gt;render&lt;span&gt;, &lt;/span&gt;getDerivedStateFromProps&lt;span&gt; 등)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;처리할 수 없는 상황&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- async/await&lt;/span&gt;&lt;span&gt; 등 &lt;/span&gt;&lt;b&gt;비동기 함수에서 발생한 에러&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- useEffect&lt;/span&gt;, 이벤트 핸들러(onClick 등)처럼 &lt;span&gt;&lt;b&gt;마운트 이후에 발생하는 에러&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 서버 사이드 렌더링(SSR) 중 발생하는 에러 (특히 Next.js의 서버 컴포넌트)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1751468672968&quot; class=&quot;coffeescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  throw new Error(&quot;이 에러는 Error Boundary가 못 잡는다.&quot;);
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서버 컴포넌트의 에러는 왜 안 잡힐까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js에서는 서버 컴포넌트가 서버에서 렌더링되고, 클라이언트로 HTML이 전송된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 &lt;/span&gt;&lt;b&gt;서버에서 발생하는 에러는 React Error Boundary가 작동하기 전에 이미 렌더링이 중단되기 때문에&lt;/b&gt;&lt;span&gt;, 클라이언트에 전달되지 않는다. 그래서 브라우저에 망가진 HTML이 전달 되게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 경우에&amp;nbsp;&lt;/span&gt;&lt;b&gt;서버 컴포넌트에서 직접 try/catch로 처리하고,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;redirect() 해주거나&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt; fallback UI를 return&lt;/b&gt; 해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주저리 주저리 말이 길어졌는데 결국은 기존에 error boundary의 역할을 정확히 이해하지 못했던 게 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러가 개발 서버에서는 잘 잡아서 보여주다보니 착각을 했었던 것이다 ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 컴포넌트의 에러 핸들링에 대한 처리가 없어서 무방비한 상태였던 것이고, 이를 핸들링 해줌으로써 문제를 해결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/vercel/next.js/discussions/66999&quot;&gt;Vercel Discussion #66999&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://github.com/vercel/next.js/discussions/49426#discussioncomment-9565288&quot;&gt;Vercel Discussion #49426&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1;&quot; href=&quot;https://nextjs.org/docs/app/getting-started/error-handling#server-components&quot;&gt;공식 문서: Server Component에서의 에러 처리&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/error-boundaries.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;&amp;bull; https://ko.legacy.reactjs.org/docs/error-boundaries.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/90</guid>
      <comments>https://8156217.tistory.com/90#entry90comment</comments>
      <pubDate>Thu, 3 Jul 2025 00:26:57 +0900</pubDate>
    </item>
    <item>
      <title>Husky를 활용한 Git hooks 설정과 작동원리</title>
      <link>https://8156217.tistory.com/89</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;도입 배경&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;현재 개발 중인 우리 서비스는 배포를 진행할 때 github action을 통해 빌드를 진행 하는 데 그 때 불용 코드나 오류가 있으면 빌드가 실패한다. 그 이유는 코드 퀄리티를 위해 빌드 실행 시 함께 진행되는 타입스크립트 컴파일에서 linting을 진행하도록 설정했기 때문이다. 그래서 우리 개발팀은 배포 전에 반드시 &lt;b&gt;로컬에서&lt;/b&gt; &lt;b&gt;사전에 빌드 테스트를 해봐야 하는데 사람들이 이를 종종 까먹고 github에 업로드 하여 배포 때 계속 실패&lt;/b&gt;하게 되는 이슈가 있었다. 이를 해결하기 위해 husky를 도입 해보기로 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;husky&lt;/b&gt;란?&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Ultra-fast modern native git hooks Automatically lint your commit messages, code, and run tests upon committing or pushing.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게&amp;nbsp;말해서&amp;nbsp;&lt;b&gt;Git&amp;nbsp;Hooks를&amp;nbsp;사용하기&amp;nbsp;편하게&amp;nbsp;해주는&amp;nbsp;도구&lt;/b&gt;라고&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Git hooks&lt;/b&gt;는 무엇일까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;특정 이벤트가 발생했을 때 git에서 특정 스크립트를 실행하도록 하는 것&lt;/b&gt;이다. 쉽게 말해 커밋, 푸쉬, 머지 등이 발생했을 때 쉘이나 perl 스크립트와 같은 실행 가능 파일을 실행 시켜 특정 작업을 수행 하는 것이다.&lt;br /&gt;&amp;nbsp;참고로 기본 훅 디렉토리는 .git/hooks에 위치해 있고 관련 설정 파일은 .git/config 이다.&lt;br /&gt;설정을&amp;nbsp;추가하고&amp;nbsp;&lt;b&gt;원하는&amp;nbsp;훅을&amp;nbsp;형식에&amp;nbsp;맞게&amp;nbsp;작성하여&amp;nbsp;hooks&amp;nbsp;디렉터리&lt;/b&gt;에 넣어 훅을 트리거링 하여 사용하는 방식이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Git hooks 종류&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;git hooks에는&amp;nbsp;&lt;b&gt;클라이언트&amp;nbsp;훅&lt;/b&gt;과&amp;nbsp;&lt;b&gt;서버&amp;nbsp;훅&lt;/b&gt;이&amp;nbsp;있다.&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1)&amp;nbsp;클라이언트&amp;nbsp;훅&lt;/b&gt;&lt;br /&gt;commit,&amp;nbsp;rebase,&amp;nbsp;merge,&amp;nbsp;push&amp;nbsp;등&amp;nbsp;&lt;b&gt;작업자의&amp;nbsp;환경(로컬&amp;nbsp;환경)&lt;/b&gt;에서&amp;nbsp;발생하는&amp;nbsp;이벤트&amp;nbsp;전/후&amp;nbsp;실행&amp;nbsp;되는&amp;nbsp;훅이다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2)&amp;nbsp;서버&amp;nbsp;훅&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Git&amp;nbsp;Repository&amp;nbsp;측&lt;/b&gt;에서&amp;nbsp;발생하는&amp;nbsp;훅이다.&amp;nbsp;중앙&amp;nbsp;관리가&amp;nbsp;가능하므로&amp;nbsp;서버&amp;nbsp;관리자라면&amp;nbsp;서버&amp;nbsp;훅이&amp;nbsp;좀&amp;nbsp;더&amp;nbsp;유용하게&amp;nbsp;사용될&amp;nbsp;수&amp;nbsp;있다.&lt;br /&gt;&lt;br /&gt;우리는 git hooks 중&amp;nbsp;&lt;b&gt;클라이언트&amp;nbsp;훅&lt;/b&gt;을&amp;nbsp;사용하여&amp;nbsp;&lt;b&gt;빌드&amp;nbsp;테스트를&amp;nbsp;자동화&lt;/b&gt;하여&amp;nbsp;작업자의&amp;nbsp;실수를&amp;nbsp;줄이고자&amp;nbsp;했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그&amp;nbsp;과정에서&amp;nbsp;husky를&amp;nbsp;통해&amp;nbsp;간편하게&amp;nbsp;설정하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Husky&amp;nbsp;사용&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pnpm을 사용했기에 pnpm을 기준으로 작성하였다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1732807729649&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm add --save-dev husky&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 간편 설정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1732807745771&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm exec husky init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;3. 원하는 훅 설정&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;pre-commit과&amp;nbsp;pre-push&amp;nbsp;중&amp;nbsp;고민을&amp;nbsp;했었으나&amp;nbsp;pre-commit으로&amp;nbsp;하게&amp;nbsp;되면&amp;nbsp;불필요한&amp;nbsp;빌드&amp;nbsp;작동&amp;nbsp;때문에&amp;nbsp;생산성을&amp;nbsp;오히려&amp;nbsp;저하&amp;nbsp;시킬&amp;nbsp;것이라&amp;nbsp;판단되어&amp;nbsp;&lt;b&gt;pre-push&lt;/b&gt;를&amp;nbsp;선택하였음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;.husky/pre-push&lt;/p&gt;
&lt;pre id=&quot;code_1733490647514&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash
pnpm build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 설정이 끝났다! 예상대로 push 명령어를 실행하면 먼저 빌드가 자동 실행되고 실패 시 push가 진행 되지 않는다!&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Husky&amp;nbsp;작동원리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;사용하기 간편한 건 알겠는데 대체 어떻게 작동하는 걸까??&lt;br /&gt;&lt;br /&gt;앞서&amp;nbsp;말했듯이&amp;nbsp;&lt;b&gt;git&amp;nbsp;hooks를&amp;nbsp;사용하려면&amp;nbsp;.git/hooks에&amp;nbsp;훅을&amp;nbsp;추가&lt;/b&gt;해야&amp;nbsp;한다.&lt;br /&gt;근데&amp;nbsp;해당&amp;nbsp;디렉토리에는&amp;nbsp;추가된&amp;nbsp;훅이&amp;nbsp;없는&amp;nbsp;데&amp;nbsp;왜&amp;nbsp;작동을&amp;nbsp;하는&amp;nbsp;걸까??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;아래의&amp;nbsp;명령어&amp;nbsp;때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1732807868376&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pnpm exec husky init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;해당 init을 진행하면 다음과 같은 일들이 일어난다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;husky init (recommended) The init command simplifies setting up husky in a project. It creates a pre-commit script in .husky/ and updates the prepare script in package.json. Modifications can be made later to suit your workflow.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;husky init을 실행하면 .husky 폴더가 생기고 스크립트 샘플들이 나타난다. 이곳에서 스크립트를 정의하여 사용한다. 그리고 &lt;b&gt;.husky 폴더를 git hooks 폴더로 인식하기 위해 git hooks 설정 파일인 .git/config에 코드가 추가&lt;/b&gt; 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732807985383&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
        hooksPath = .husky/_ -&amp;gt; 추가 됨&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;husky 폴더를 git hooks 관련 디렉토리로 인지&lt;/b&gt;할 수 있게 된 것이다.&lt;br /&gt;&lt;br /&gt;근데&amp;nbsp;알다시피&amp;nbsp;.git/config는&amp;nbsp;git에&amp;nbsp;무시되서&amp;nbsp;깃허브에&amp;nbsp;올라가지&amp;nbsp;않는다.&lt;br /&gt;그럼&amp;nbsp;다른&amp;nbsp;협업&amp;nbsp;개발자들도&amp;nbsp;husky를&amp;nbsp;사용하려면&amp;nbsp;husky&amp;nbsp;init&amp;nbsp;명령어를&amp;nbsp;해줘야&amp;nbsp;하는&amp;nbsp;걸까??&lt;br /&gt;&lt;br /&gt;그렇지&amp;nbsp;않다.&lt;br /&gt;&lt;br /&gt;그것은&amp;nbsp;&lt;b&gt;prepare&amp;nbsp;script&lt;/b&gt;&amp;nbsp;때문이다.&lt;br /&gt;위의&amp;nbsp;설명에&amp;nbsp;따르면&amp;nbsp;&lt;b&gt;husky&amp;nbsp;init&amp;nbsp;후&amp;nbsp;package.json에&amp;nbsp;prepare&amp;nbsp;script도&amp;nbsp;추가&lt;/b&gt;된다.&lt;/p&gt;
&lt;pre id=&quot;code_1732808045701&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; &quot;scripts&quot;: {
    ...
    &quot;prepare&quot;: &quot;husky&quot; -&amp;gt; 추가 됨
  },&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;npm 공식문서&lt;/b&gt;&lt;br /&gt;&lt;a href=&quot;https://docs.npmjs.com/cli/v8/using-npm/scripts&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.npmjs.com/cli/v8/using-npm/scripts&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;npm&amp;nbsp;공식&amp;nbsp;문서에&amp;nbsp;따르면&amp;nbsp;&lt;b&gt;prepare 스크립트는 로컬에서의 npm insall이 발생하면&amp;nbsp;작동&lt;/b&gt;한다.&lt;br /&gt;&lt;br /&gt;즉, 다른 사람들은 그저 허스키가 설치된 레포지토리를 받고 npm install을 해주면 관련 라이브러리 설치 이후 &lt;b&gt;prepare에 설정된 husky가 작동&lt;/b&gt;하고 이를 통해 &lt;b&gt;본인 로컬 환경의 .git/config에 hooksPath&amp;nbsp;=&amp;nbsp;.husky/_&amp;nbsp;가&amp;nbsp;자동으로&amp;nbsp;추가&lt;/b&gt;되는&amp;nbsp;것이다.&lt;br /&gt;&lt;br /&gt;그렇기&amp;nbsp;때문에&amp;nbsp;협업하는&amp;nbsp;사람들은&amp;nbsp;git&amp;nbsp;hooks를&amp;nbsp;따로&amp;nbsp;추가하지&amp;nbsp;않더라도&amp;nbsp;husky가&amp;nbsp;알아서&amp;nbsp;다&amp;nbsp;설정해주기&amp;nbsp;때문에&amp;nbsp;git&amp;nbsp;hooks를&amp;nbsp;간편하게&amp;nbsp;사용이&amp;nbsp;가능한&amp;nbsp;것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&amp;nbsp;husky는 간편해서 어떤 식으로 작동하는 지 몰라도 쉽게 사용할 수 있다. 그렇지만 작동 원리를 공부하면서 git hooks에 대해 더 깊게 알 수 있었기에 공유를 위해 포스팅을 남긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 환경 설정</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/89</guid>
      <comments>https://8156217.tistory.com/89#entry89comment</comments>
      <pubDate>Fri, 29 Nov 2024 00:36:05 +0900</pubDate>
    </item>
    <item>
      <title>[NextJS] Next.js 프로젝트에서 CSS 프레임 워크 결정 하기</title>
      <link>https://8156217.tistory.com/88</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mIyZR/btsF2RnZuHF/aQymKY70NDtKURanhiPJt0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mIyZR/btsF2RnZuHF/aQymKY70NDtKURanhiPJt0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mIyZR/btsF2RnZuHF/aQymKY70NDtKURanhiPJt0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmIyZR%2FbtsF2RnZuHF%2FaQymKY70NDtKURanhiPJt0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;230&quot; height=&quot;230&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Next.js를 사용하여 프로젝트를 진행하기로 하였다. &lt;b&gt;현재 상황&lt;/b&gt;과 &lt;b&gt;Next.js의 호환성&lt;/b&gt;을 고려하여 css Framework를 선정하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 현재 상황&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;디자이너가 없다&lt;/b&gt;. 능력 있는 디자이너와 함께 협업을 했더라면 tailwind css 하나만 사용해도 괜찮았을 것 같다. 하지만 모달, 사이드 바 등등 컴포넌트들을 직접 만들어야 하는 상황이 있어서 &lt;b&gt;컴포넌트를 제공해주는 무언가가 필요&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Next.js 의 호환성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에서는 UI가 큰 비중을 차지 하지는 않아서 최대한 Next.js의 장점을 살려서 &lt;b&gt;서버 사이드를 최대한 활용&lt;/b&gt; 하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 클라이언트 사이드에서 많이들 사용하는 CSS-In-JS..! 예쁜 UI 컴포넌트들을 많이 제공해주지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js의 서버 컴포넌트는 CSS-In-JS와는 호환성이 떨어진다. 아래 글에 정리를 해두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://8156217.tistory.com/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2024.03.21 - [Next.js] - [Next.js] Next.js와 호환되는 css와 그렇지 못한 css에 대한 고찰&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1711292587499&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Next.js] Next.js와 호환되는 css와 그렇지 못한 css에 대한 고찰&quot; data-og-description=&quot;Next.js로 프로젝트를 하면서 드는 의문이 있다. 왜 MUI 같은 라이브러리들은 자꾸 호환이 안된다고 하는 걸까?? tailwind는 왜 되는걸까?? 공식 문서를 보면 다음과 같이 나와 있다. Next.js와 호환이 잘&quot; data-og-host=&quot;8156217.tistory.com&quot; data-og-source-url=&quot;https://8156217.tistory.com/86&quot; data-og-url=&quot;https://8156217.tistory.com/86&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gRjqI/hyVDuRYeFq/6E7kX7GdrakOThD6g3qqvK/img.png?width=800&amp;amp;height=599&amp;amp;face=0_0_800_599,https://scrap.kakaocdn.net/dn/ZGbmy/hyVDxnD4Yv/EB3Qhibg8fhrkKgd6p82Z0/img.png?width=800&amp;amp;height=599&amp;amp;face=0_0_800_599,https://scrap.kakaocdn.net/dn/yS6xe/hyVDvJ6JAy/Z1inDQdMdhuNW60pK2q1a0/img.jpg?width=1002&amp;amp;height=1334&amp;amp;face=429_343_664_599&quot;&gt;&lt;a href=&quot;https://8156217.tistory.com/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://8156217.tistory.com/86&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gRjqI/hyVDuRYeFq/6E7kX7GdrakOThD6g3qqvK/img.png?width=800&amp;amp;height=599&amp;amp;face=0_0_800_599,https://scrap.kakaocdn.net/dn/ZGbmy/hyVDxnD4Yv/EB3Qhibg8fhrkKgd6p82Z0/img.png?width=800&amp;amp;height=599&amp;amp;face=0_0_800_599,https://scrap.kakaocdn.net/dn/yS6xe/hyVDvJ6JAy/Z1inDQdMdhuNW60pK2q1a0/img.jpg?width=1002&amp;amp;height=1334&amp;amp;face=429_343_664_599');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Next.js] Next.js와 호환되는 css와 그렇지 못한 css에 대한 고찰&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Next.js로 프로젝트를 하면서 드는 의문이 있다. 왜 MUI 같은 라이브러리들은 자꾸 호환이 안된다고 하는 걸까?? tailwind는 왜 되는걸까?? 공식 문서를 보면 다음과 같이 나와 있다. Next.js와 호환이 잘&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;8156217.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 tailwind css를 사용하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀원들이 tailwind css에 대한 사용 경험도 있으며, Next.js도 tailwind css와의 높은 호환성을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;공식 문서 내용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711292685629&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Tailwind CSS is a utility-first CSS framework that works exceptionally well with Next.js.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨌든 Tailwind Css를 가져가기로 했고, 앞서 말했듯이 &lt;b&gt;컴포넌트가 필요&lt;/b&gt;했다. 그래서 &lt;b&gt;Tailwind Css 기반 컴포넌트&lt;/b&gt; &lt;b&gt;라이브러리&lt;/b&gt;들을 찾아보았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) Flowbite ( 결정 )&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711292756342&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Flowbite - Tailwind CSS component library
Get started with the most popular open-source library of interactive UI components built with the utility classes from Tailwind CSS&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flowbite는 &lt;b&gt;tailwind css 기반&lt;/b&gt;이기 때문에 &lt;b&gt;호환이 괜찮다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그리고&lt;/span&gt; 다른 라이브러리들에 비해 &lt;b&gt;UI들을 &lt;b&gt;그나마&lt;/b&gt; 다양하게 제공&lt;/b&gt; 해줘서 결정하게 되었다.&lt;/span&gt; &lt;s&gt;그래도 부족하지만..&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 next.js에서 이 라이브러리를 사용하려면 flowbite-react와 함께 사용하여야 한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) daisy UI&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711293056250&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;The most popular component library for Tailwind CSS&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;daisy UI는 호환성이 정말 좋다. 처음에는 호환성 때문에 사용하려 했으나 제공하는 컴포넌트가 너무 적었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 컴포넌트가 너무 심플해서 많은 커스텀을 필요하기 때문에 사용을 안하기로 마음 먹었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) Next UI&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 tailwind css 기반은 아니었지만 그냥 이름부터 뭔가 Next.js와 호환 될 것 같아서 사용하려고 해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711293345042&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;App Directory Setup
Next.js 13 introduces a new app/ directory structure. 
By default it uses Server Components. 
As NextUI components use React hooks, we added the use client; at build time, 
so you can import them directly in your React Server Components (RSC).&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 공식 문서에서 리액트 훅을 사용하기 때문에 서버 컴포넌트와 호환성이 떨어진다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 클라이언트 컴포넌트로 전환 시켜야 사용이 가능하다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 이름은 Next UI 일까..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론은 &lt;b&gt;Tailwind Css와 flowbite ( + flowbite-react )&lt;/b&gt;를 함께 사용하기로 마음 먹었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 &lt;b&gt;호환성, 그리고 다양한 컴포넌트의 필요성&lt;/b&gt;&amp;nbsp;때문이라고 요약할 수 있겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 좋은 라이브러리가 있다면 댓글로 남겨 주시면 너무 감사할 것 같습니다!&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/88</guid>
      <comments>https://8156217.tistory.com/88#entry88comment</comments>
      <pubDate>Mon, 25 Mar 2024 00:25:38 +0900</pubDate>
    </item>
    <item>
      <title>[React] 클래스 인스턴스의 효율적인 렌더링과 접근 범위 제어 방법</title>
      <link>https://8156217.tistory.com/87</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7a16F/btsF2RnYvAi/DKx7fDGZ6Q4tGujKjaWKdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7a16F/btsF2RnYvAi/DKx7fDGZ6Q4tGujKjaWKdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7a16F/btsF2RnYvAi/DKx7fDGZ6Q4tGujKjaWKdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7a16F%2FbtsF2RnYvAi%2FDKx7fDGZ6Q4tGujKjaWKdk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;451&quot; height=&quot;237&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;리액트에서 &lt;b&gt;클래스를 설계&lt;/b&gt;하고 컴포넌트 내에서 &lt;b&gt;클래스 인스턴스를 활용&lt;/b&gt;하는 코드를 작성하였는데, 더 효율적으로 관리하는 방법을 배우게 되어 공유하고 싶은 마음에 글을 작성하게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;두 가지에 초점을 맞췄습니다&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;1) 인스턴스의 불필요한 재렌더링 방지&lt;br /&gt;2) 인스턴스의 전역적인 접근 막기 ( 사이드 이펙트 방지 차원 )&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 처음 작성했던 클래스 방식 ( 예시 코드 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;calculator.js&lt;/p&gt;
&lt;pre id=&quot;code_1711288474817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export class Calculator {

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

  multiply(a, b) {
    return a * b;
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;page.jsx&lt;/p&gt;
&lt;pre id=&quot;code_1711288689814&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Page(){

    const [first , setFirst] = useState(1);
    const [second , setSecond] = useState(2);
    const [result , setResult] = useState(0);
    const calculator = new Calculator();
    
    useEffect( () =&amp;gt; {
        setResult(calculator.add(1+2));
    } , [first , second])

    return (
        &amp;lt;&amp;gt;
            {result}
        &amp;lt;/&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;page가 재랜더링 될 때마다 calculator의 인스턴스가 새로 생성되게 된다. &lt;b&gt;(불필요한 재렌더링)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. &lt;span&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;싱글톤 클래스 사용&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;싱글톤을 사용하여 하나의 인스턴스만 활용하여 메모리 누수를 방지&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;calculator.js&lt;/p&gt;
&lt;pre id=&quot;code_1711289108295&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export class Calculator {
  static instance = null;

  constructor() {
    if (Calculator.instance) {
      return Calculator.instance;
    }
    Calculator.instance = this;
  }

  static getInstance() {
    if (!Calculator.instance) {
      Calculator.instance = new Calculator();
    }
    return Calculator.instance;
  }

  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제점&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 instance는 전역적으로 접근이 가능하다. &lt;b&gt;( 사이드 이펙트 위험 가능성 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다른 페이지에서 다른 인스턴스를 사용하고 싶어도 그럴 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;독립적인 인스턴스 사용이 불가능하다 ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 컨텍스트의 활용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텍스트를 활용해서 접근 범위를 제한 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Context API에 인스턴스 주입&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711290449476&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const calculatorInstance = new Calculator();

const CalculatorContext = createContext(calculatorInstance);

export const CalculatorProvider = ({ children }) =&amp;gt; {
  return (
    &amp;lt;CalculatorContext.Provider value={calculatorInstance}&amp;gt;
      {children}
    &amp;lt;/CalculatorContext.Provider&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;페이지 내에서 활용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1711289744613&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import { useCalculator } from './CalculatorContext';


export default function Page() {

	const calculator = useCalculator(); // 컨텍스트에서 Calculator 인스턴스를 가져온다.

    const [first , setFirst] = useState(1);
    const [second , setSecond] = useState(2);
    const [result , setResult] = useState(0);

    
    useEffect( () =&amp;gt; {
        setResult(calculator.add(1+2));
    } , [first , second])
  
    return(
        &amp;lt;&amp;gt;
                {result}
        &amp;lt;/&amp;gt;
    )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;효과&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;불필요한 재렌더링이 방지되고 해당 인스턴스에 Context 내부에서만 접근이 가능합니다. &lt;b&gt;( 두 가지 이슈 해결 )&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;리액트가 상태 변경을 추적할 필요가 없어서 관련된 &lt;b&gt;오버헤드가 줄어듭니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;다만 &lt;b&gt;코드가 조금 길고 신경써야할 Context가 하나 더 추가&lt;/b&gt; 되었네요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;4. useState 활용 ( 현재 사용 중 )&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1711290722135&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Page() {

	const [calculator] = useState(() =&amp;gt; new Calculator());
  
    const [first , setFirst] = useState(1);
    const [second , setSecond] = useState(2);
    const [result , setResult] = useState(0);

    
    useEffect( () =&amp;gt; {
        setResult(calculator.add(1+2));
    } , [first , second])
  
	return(
    	&amp;lt;&amp;gt;
            {result}
     	&amp;lt;/&amp;gt;
	)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;이게 끝입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;인스턴스를 State에 주입 시켜주고 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;효과&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;State이기 때문에 직접적인 변경이 없을 시에는 렌더링이 일어나지 않죠. &lt;b&gt;( 불필요한 재렌더링 방지 )&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;그리고 상위에서는 접근이 불가능합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;( 접근 범위 제한 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;하위 컴포넌트에서 접근하고 싶다면 prop으로 내려주면 사용 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;여러 곳에서 내려줘야 한다면 코드가 더러워 질 수 있겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;하지만 저의 경우 많이 내려주지 않아서 관련 이슈는 없었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;상황에 맞게 잘 사용하시면 되겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하나의 인스턴스를 전역적으로 사용&lt;/b&gt;하고 싶다면 &lt;b&gt;싱글톤&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;불필요한 추적 없이 싫거나 클래스를 다양한 하위 컴포넌트에서 사용&lt;/b&gt;한다 싶으면 &lt;b&gt;Context&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;짧은 코드로 깔끔하게 사용&lt;/b&gt;하고 싶다면&lt;b&gt; useState&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;저는 코드가 짧고 간결하면서 요구 사항을 모두 만족 시킬 수 있어서 useState가 좋았습니다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>React</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/87</guid>
      <comments>https://8156217.tistory.com/87#entry87comment</comments>
      <pubDate>Sun, 24 Mar 2024 23:49:12 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Next.js와 호환되는 css와 그렇지 못한 css에 대한 고찰</title>
      <link>https://8156217.tistory.com/86</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;959&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ra3su/btsFVUe3H6o/R1J9a8yKh1Uv0QaMgsOqb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ra3su/btsFVUe3H6o/R1J9a8yKh1Uv0QaMgsOqb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ra3su/btsFVUe3H6o/R1J9a8yKh1Uv0QaMgsOqb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRa3su%2FbtsFVUe3H6o%2FR1J9a8yKh1Uv0QaMgsOqb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;541&quot; height=&quot;405&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;959&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Next.js로 프로젝트를 하면서 드는 의문이 있다.&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;왜 MUI 같은 라이브러리들은 자꾸 호환이 안된다고 하는 걸까??&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;tailwind는 왜 되는걸까??&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;공식 문서를 보면 다음과 같이 나와 있다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Next.js와 호환이 잘되는 것들&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. CSS Modules&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. tailwind CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Sass&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Next.js와 호환이 잘 안되는 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS-in-JS&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #171717; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://chakra-ui.com/getting-started/nextjs-app-guide&quot;&gt;chakra-ui&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://kuma-ui.com/&quot;&gt;kuma-ui&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://mui.com/material-ui/guides/next-js-app-router/&quot;&gt;@mui/material&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://mui.com/joy-ui/integrations/next-js-app-router/&quot;&gt;@mui/joy&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://panda-css.com/&quot;&gt;pandacss&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://nextjs.org/docs/app/building-your-application/styling/css-in-js#styled-jsx&quot;&gt;styled-jsx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://nextjs.org/docs/app/building-your-application/styling/css-in-js#styled-components&quot;&gt;styled-components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://stylexjs.com/&quot;&gt;stylex&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://tamagui.dev/docs/guides/next-js#server-components&quot;&gt;tamagui&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://tss-react.dev/&quot;&gt;tss-react&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://vanilla-extract.style/&quot;&gt;vanilla-extract&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;근데 또 emotion은 이제 지원한다고 한다.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CSS-in-JS가 지원이 안되는 이유는??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 다음과 같이 나타나 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1710949801703&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Warning: CSS-in-JS libraries which require runtime JavaScript are not currently supported in Server Components.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Next.js에서 Server Components(RSC)를 활용하면, 서버 측에서 pre-render 단계에서 미리 HTML과 CSS를 클라이언트에 전달합니다. 그리고 클라이언트가 이를 받아서 화면에 보여주게 됩니다. 따라서, Next.js의 서버 컴포넌트(RSC)를 활용하려면 빌드 시에 CSS 파일이 사전에 준비되어야 합니다. 반대로 런타임에 JavaScript를 사용해 CSS를 동적으로 생성하는 접근법 ( 이를테면 CSS-In-JS )은 Next.js의 RSC에 호환되지 않고 주로 클라이언트 컴포넌트에서 활용됩니다. 이는 서버 측에서 처리되는 RSC가 HTML과 함께 최적화된 CSS를 미리 클라이언트에 전달하는 특성 때문입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 어떤 방식들이 빌드 타임에 css 파일을 만들 수 있어서 Next.js의 RSC와 호환이 되고 어떤 방식들이 그러지 못할까??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;

&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-testid=&quot;conversation-turn-11&quot;&gt;
&lt;div&gt;
&lt;div data-message-id=&quot;cf3779c3-371f-40f9-afcd-03e8e02a0716&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;1. Vanilla CSS (순수 CSS)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순수 CSS는 별도의 라이브러리나 프레임워크 없이 웹 브라우저가 직접 해석할 수 있는 원시 CSS 코드를 사용하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순수 Css는 별 다른 처리가 필요하지 않아 &lt;b&gt;서버 컴포넌트(RSC)에서 호환 문제가 발생하지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;2. CSS Preprocessors (CSS 전처리기)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sass, Less, Postcss 를 포함하는 CSS 전처리기는 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;&lt;b&gt;빌드 타임에 순수 CSS로 컴파일&lt;/b&gt; 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 역시 호환 문제가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;3. CSS Modules&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;CSS 클래스 이름을 고유하게 만들어 스타일 충돌을 방지하는 방식.&lt;/span&gt; &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;b&gt;빌드 시점&lt;/b&gt;에 이미 스타일이 처리되어 최종 CSS 파일이 생성하기 때문에&lt;/span&gt; 서버 사이드 렌더링과 문제없이 호환 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;4. Utility-First CSS&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Tailwind css 가 포함된다. &lt;b&gt;빌드 타임&lt;/b&gt;에 유의미하게 사용되는 유틸리티 클래스만을 포함하는 최적화된 CSS 파일을 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성된 CSS 파일은 서버 사이드에서 HTML에 직접 적용되므로, JavaScript의 실행 없이도 최종 사용자에게 스타일이 적용된 페이지를 제공할 수  있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;4. CSS-in-JS&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Styled-components, MUI 등을 포함하고 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;JavaScript를 사용하여 스타일을 정의한다. 그래서 &lt;b&gt;런타임에 동적으로 스타일이 적용&lt;/b&gt;된다. &lt;s&gt;일부 라이브러리는 추가 작업을 통해 서버 사이드 렌더링을 지원한다.(ex. Emotion)&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어쨌든 빌드 타임에 css가 완성되냐 , 런타임에서 JS를 통해 동적으로 css가 렌더링 되냐가 Next.js의 서버 컴포넌트와의 호환성을 결정해 준다고 결론을 내렸다!&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/86</guid>
      <comments>https://8156217.tistory.com/86#entry86comment</comments>
      <pubDate>Thu, 21 Mar 2024 00:50:24 +0900</pubDate>
    </item>
    <item>
      <title>[React] useSyncExternalStore 사용 방법과 사용 이유</title>
      <link>https://8156217.tistory.com/85</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5fYw1/btsFMKoXVkC/CSmqkkzKOVYY9f0x3zjioK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5fYw1/btsFMKoXVkC/CSmqkkzKOVYY9f0x3zjioK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5fYw1/btsFMKoXVkC/CSmqkkzKOVYY9f0x3zjioK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5fYw1%2FbtsFMKoXVkC%2FCSmqkkzKOVYY9f0x3zjioK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;630&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;리액트 공식 문서에 따르면 useSyncExternalStore는 '외부 스토어를 구독할 수 있는 React 훅' 이라고 나와있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;외부 스토어가 뭘까요??&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 외부 스토어가 아닌 경우에 대해서 먼저 생각해보면 이해하기가 수월합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 우리는 구독할 데이터를 useState나 useContext 등의 리액트 훅을 이용하여 state에 저 장 하고 사용합니다. setState로 값을 수정하면 자동으로 리렌더링이 일어나죠. 하지만 이것들은 리액트 내부에서 사용될 때만 가능합니다. 리액트 훅이니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 리액트 내부에서 이용하지 않는 경우는 뭐가 있을 까요??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class를 사용하거나 function 으로 만들어 외부 저장소를 만드는 경우를 들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;counter.js 클래스 형태&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710343271368&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Counter {
  constructor() {
    this.count = 0;
  }

  increment() {
    this.count += 1;
  }

  decrement() {
    this.count -= 1;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;counter.js 함수 형태&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710343307267&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function createCounter() {
  let count = 0;

  function increment() {
    count += 1;
  }

  function decrement() {
    count -= 1;
  }

  return { increment, decrement };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 만들 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 방식은 인스턴스를 생성해서 메서드를 호출하는 식으로 되겠죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 '&lt;b&gt;데이터가 외부&lt;/b&gt;'에서 관리되고 있을 때 '&lt;b&gt;리액트 내부에서 구독'&lt;/b&gt;하려고 하면 어떻게 해야할까요??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 &lt;b&gt;useSyncExternalStore 리액트 훅&lt;/b&gt;을 통해 쉽게 구독할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1710343793426&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CounterStore {
  constructor() {
    this.count = 0;
    this.listeners = [];
  }

  increment() {
    this.count++;
    this.emitChange();
  }

  decrement() {
    this.count--;
    this.emitChange();
  }

  subscribe(listener) {
    listeners = [...listeners, listener];
    return () =&amp;gt; {
      listeners = listeners.filter(l =&amp;gt; l !== listener);
    };
  },

  getSnapshot() {
    return this.count;
  }

  emitChange() {
    for (let listener of listeners) {
    	listener();
 	}
  }
}

// 싱글톤 인스턴스 생성
export const counterStore = new CounterStore();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1710343965189&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from 'react';
import { useSyncExternalStore } from 'react';
import { counterStore } from './path/to/CounterStore';

function CounterComponent() {
  // useSyncExternalStore로 카운터의 상태를 구독
  const count = useSyncExternalStore(
    counterStore.subscribe,
    counterStore.getSnapshot
  );

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{count}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; counterStore.increment()}&amp;gt;Increment&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; counterStore.decrement()}&amp;gt;Decrement&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default CounterComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스너들을 관리할 리스트를 추가하고 구독 (subscribe) 과 값 반환(getSnapshot) 메서드를 이용하여 구독을 진행합니다. 변화 알림 (emitChange) 메서드를 만들고 변화를 알려야 하는 곳에 사용합니다. 위에서는 카운터가 증가하거나 감소하였을 때 변화를 리스너들에게 알릴 수 있도록 emitChange를 호출하게 하였습니다. 필요한 곳에 emitChange를 호출하도록 커스텀 하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;사용 중에 회고를 해보았다.&lt;br /&gt;&lt;br /&gt;그냥 진작에 리액트 내부에서 state로 관리하면 되는거 아닌가??&lt;br /&gt;&lt;/span&gt;쓰는 게 맞는 선택이었나??&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 회사의 요구 사항이 다음과 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 프론트엔드와 백엔드 모두에서 접근할 수 있는 형태 ( 리액트 , node.js 를 pnpm으로 한 워크 스페이스에서 관리 중 이었음 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 클래스를 사용하여 관련 변수들을 클래스 프로퍼티로 관리하고 다양한 연산 과정을 클래스 메서드로 관리할 수 있도록.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 가지 요구 사항을 충족 하기 위해 클래스를 사용하였고 클래스는 리액트의 외부 스토어로 관리 되기 때문에 useSyncExternalStore가 적절한 선택이었다고 스스로 결론을 내렸다.&lt;/p&gt;</description>
      <category>React</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/85</guid>
      <comments>https://8156217.tistory.com/85#entry85comment</comments>
      <pubDate>Thu, 14 Mar 2024 00:46:01 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 가상 환경 설정 및 프로젝트 관리 관련 커맨드 (pyenv , poetry)</title>
      <link>https://8156217.tistory.com/84</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;사내에서 파이썬 AI 모델을 다룰 일이 있어서 파이썬 가상 환경 설정 방법을 공부하면서 커맨드를 정리하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;내가 사용하기 위해 정리 한 것이라 다소 정리가 되어 있지 않을 수 있다.... &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;글로벌 파이썬 버전 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1709653997901&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python --version&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Pyenv 사용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 컴퓨터에 설치된 모든 파이썬 버전 확인&lt;/p&gt;
&lt;pre id=&quot;code_1709654022019&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pyenv versions&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 Python 버전을 pyenv를 통해 설치합니다&lt;/p&gt;
&lt;pre id=&quot;code_1709654713011&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pyenv install 3.8.6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌 파이썬 버전 변경&lt;/p&gt;
&lt;pre id=&quot;code_1709654720460&quot; class=&quot;apache&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;pyenv global [파이썬 버전]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;설치한 Python 버전으로 가상 환경을 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1709654713011&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;pyenv virtualenv 3.8.6 my-virtual-env-3.8.6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;생성한 가상 환경을 활성화합니다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1709654713012&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;pyenv activate my-virtual-env-3.8.6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업이 끝났다면, 가상 환경을 비활성화합니다&lt;/p&gt;
&lt;pre id=&quot;code_1709654713012&quot; class=&quot;ebnf&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;pyenv deactivate&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 위치 확인&lt;/p&gt;
&lt;pre id=&quot;code_1709654226679&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pyenv which python3
/Users/oinhyuk/.pyenv/versions/3.10.13/bin/python3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;poetry 사용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;poetry 설치 전 가상환경 프로젝트 내부에 설치되도록 설정&lt;/p&gt;
&lt;pre id=&quot;code_1709654365800&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;poetry config virtualenvs.in-project true --local&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;poetry 적용된 프로젝트에서 가상환경 생성 및 의존성 설치&lt;/p&gt;
&lt;pre id=&quot;code_1709654299868&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;poetry install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 설정 시 toml 파일 생성&lt;/p&gt;
&lt;pre id=&quot;code_1709654383223&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;poetry init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 환경 생성 및 실행&lt;/p&gt;
&lt;pre id=&quot;code_1709654434410&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;poetry shell&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요 패키지 설치&lt;/p&gt;
&lt;pre id=&quot;code_1709654491829&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;poetry add&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상환경 나가기&lt;/p&gt;
&lt;pre id=&quot;code_1709654518665&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;deactivate&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/84</guid>
      <comments>https://8156217.tistory.com/84#entry84comment</comments>
      <pubDate>Wed, 6 Mar 2024 01:10:12 +0900</pubDate>
    </item>
    <item>
      <title>[HTTP] Resource , URI , URL , URN 에 대해 알아보자</title>
      <link>https://8156217.tistory.com/83</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l7EdW/btsEEZBAwya/zJRuieQYHTbb6gtZvI8Zm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l7EdW/btsEEZBAwya/zJRuieQYHTbb6gtZvI8Zm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l7EdW/btsEEZBAwya/zJRuieQYHTbb6gtZvI8Zm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl7EdW%2FbtsEEZBAwya%2FzJRuieQYHTbb6gtZvI8Zm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;340&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;HTTP를 공부하다가&lt;b&gt; Resource, URI , URL , URN&lt;/b&gt; 의 개념에 대해 공부하게 되었습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;겹치는 부분이 많다 보니 제대로 공부하지 않으면 굉장히 헷갈리는 개념입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 오늘 이것들에 대해 정리를 해보기로 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. Resource&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인터넷 상의 Resource 란 &lt;b&gt;URI(Uniform Resource Identifier)를 통해 유일하게 식별되고 접근할 수 있는 모든 형태의 디지털 자산 또는 서비스를 의미&lt;/b&gt;합니다. 이는 웹 페이지, 이미지 파일, 비디오, API 엔드포인트, 문서, 소프트웨어 컴포넌트 등 인터넷을 통해 제공되고 사용될 수 있는 데이터나 기능을 포함합니다. 물론 html, css 파일도 이곳에 포함됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이것들을 식별할 수 있도록 도와주는 것에는 URI, URL , URN 등이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. URI (Uniform Resource Identifier)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;URI는 &lt;b&gt;인터넷 상의 Resource를 식별하기 위한 고유한 문자열&lt;/b&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Uniform : Resource를 식별하는 방식이 통일 되어 있다.&lt;br /&gt;Resource : 위에서 정의한 모든 형태의 디지털 자산과 서비스.&lt;br /&gt;Identifier : 다른 리소스와의 구별을 위한 고유한 식별자.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;URI 안에는 URL과 URN이 있습니다. 즉 URI가 더 큰 개념으로 URL과 URN을 포괄하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. U&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: left;&quot;&gt;RL (Uniform Resource Locator)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;URL은 &lt;b&gt;웹 상에서의 리소스의 위치를 나타내는 문자열&lt;/b&gt;입니다. &lt;b&gt;웹 주소&lt;/b&gt; 라고도 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;웹 브라우징, 하이퍼링크 , API 호출 등에서 주로 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예시&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;http://www.example.com
ftp://ftp.example.com/downloads/file.zip&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. &lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;URN ( Uniform Resource Name )&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인터넷 상의 리소스를 식별하기 위한 &lt;b&gt;유니크한 이름을 제공&lt;/b&gt;하는 URI의 한 형태&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주로 사용 되는 곳&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;디지털 객체 식별: 학술 문서, 연구 보고서, 정부 문서와 같은 디지털 콘텐츠에 대해 식별자 제공&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;네임스페이스 관리: 소프트웨어 개발, XML 문서, 네트워크 프로토콜 설정 등에서 특정 네임스페이스 내의 요소에 대해 식별자 제공&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예시&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;urn:isbn:0451450523

urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이렇게 URI와 URL과 URN을 구별해보았습니다.&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;웹 개발에서 URI 보다는 URL이라고 말하는게 좀 더 정확한 표현일 수 있겠다는 생각이 드네요. &lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 웹 개발자라면 URN 보다는 URL에 대해 잘 알고 있어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그렇기에 URL의 문법에 대해서 알아보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;5.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;URL 문법&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;http://www.samplewebsite.com:8080/resources/article.html?query=search&amp;amp;sort=ascending#section2&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1) 스키마 (Schema) or 프로토콜 (Protocol)&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;http://
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;브라우저가 사용해야 하는 프로토콜을 나타냅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;http , https , maileto , ssh , ftp 등 다양한 종류가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2) 호스트 (Host) or 도메인 이름 (Domain name)&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;www.samplewebsite.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리소스가 호스팅 되고 있는 서버의 도메인 이름입니다. IP 주소로 대체 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3) 포트 ( Port )&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;:8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서버 상에서 리소스에 접근하기 위한 기술적인 게이트 번호입니다. http 프로토콜의 표준 포트( HTTP - 80 , HTTPS - 443)의 경우엔 포트 생략이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4) 경로 ( Path )&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;/resources/article.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서버 내에서 특정 리소스의 위치를 나타냅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5) 쿼리 ( Query )&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;?query=search&amp;amp;sort=ascending
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;리소스에 대한 추가 정보를 나타냅니다. 검색 , 정렬 등의 정보를 파라미터로 전달합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;6) 프래그먼트 ( Fragment )&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;#section2
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;리소스 내에서 특정 부분을 직접 가르킵니다. 문서내의 section2라는 앵커 부분을 가리킵니다. 주로 문서 내의 특정 위치로 바로 이동할 때 사용됩니다.&lt;/span&gt;&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/83</guid>
      <comments>https://8156217.tistory.com/83#entry83comment</comments>
      <pubDate>Fri, 9 Feb 2024 16:54:16 +0900</pubDate>
    </item>
    <item>
      <title>[Node JS] JS 의존성 주입 라이브러리 - tsyringe</title>
      <link>https://8156217.tistory.com/82</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/23naY/btsEBmQpMFK/JdCLsRbvP1gKuA1jKA5bs0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/23naY/btsEBmQpMFK/JdCLsRbvP1gKuA1jKA5bs0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/23naY/btsEBmQpMFK/JdCLsRbvP1gKuA1jKA5bs0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F23naY%2FbtsEBmQpMFK%2FJdCLsRbvP1gKuA1jKA5bs0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;310&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;JS로 벡엔드를 개발할 때 DI를 어떻게 설계 해야할 지 고민이 될 것이다. 이 때 &lt;b&gt;tsyringe&lt;/b&gt;는 좋은 선택이다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;JS 의존성 주입 라이브러리로 tsyringe는 코드 관리에 아주 좋다. 왜냐하면 다른 라이브러리에 비해 코드의 양이 매우 짧다. 그 이유는 이 라이브러리는 의존성을 데코레이터 기반으로 Container에 등록 해주는 방식인데 클래스에 데코레이터가 붙어있으면 자동 으로 container에 등록해주기 때문에 코드의 양이 줄어든다. ( 마치 스프링 같다. )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 사용하는 방법에 대해 코드로 알아보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1) 설치 방법&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;// npm
npm install --save tsyringe

// pnpm
pnpm add tsyringe

// yarn
yarn add tsyringe
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2) tsconfig.json 설정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;데코레이터 관련 설정을 tsconfig.json 에 추가 해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;experimentalDecorators&quot;: true,
    &quot;emitDecoratorMetadata&quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3) reflect-metadata 전역 설정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;한 번만 설정해주면 된다. index.ts에 설정해주자.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;// index.ts
import &quot;reflect-metadata&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4) 데이터 베이스 설정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;DBConfig를 Container에 등록한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;@singleton
export class DBConfig implements Disposable {
	
	// db 관련 변수

  constructor() {
		// db 연결  
	}
	
	get db(){
    // db 관련 변수 getter
	}

	dispose() {
	  // dispose 로직
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5) 의존성 주입: Foo &amp;lt;- DBConfig&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;추가적으로 Foo도 container에 등록되어서 resolve를 통해 Foo에 접근할 수있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;import {injectable} from &quot;tsyringe&quot;;

@singleton
class Foo {
  constructor(private database: DBConfig) {}
}

// some other file
import &quot;reflect-metadata&quot;;
import {container} from &quot;tsyringe&quot;;
import {Foo} from &quot;./foo&quot;;

const instance = container.resolve(Foo);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이런 방식으로 사용하면 된다. 아주 간단하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;더 다양한 활용은 공식 문서를 참고하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Reference&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://github.com/microsoft/tsyringe&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/microsoft/tsyringe&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707319662485&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - microsoft/tsyringe: Lightweight dependency injection container for JavaScript/TypeScript&quot; data-og-description=&quot;Lightweight dependency injection container for JavaScript/TypeScript - GitHub - microsoft/tsyringe: Lightweight dependency injection container for JavaScript/TypeScript&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/microsoft/tsyringe&quot; data-og-url=&quot;https://github.com/microsoft/tsyringe&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bEBdTG/hyVjm6qQp5/IHfZeScDm87BiDy6JVKuCk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/microsoft/tsyringe&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/microsoft/tsyringe&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bEBdTG/hyVjm6qQp5/IHfZeScDm87BiDy6JVKuCk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - microsoft/tsyringe: Lightweight dependency injection container for JavaScript/TypeScript&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Lightweight dependency injection container for JavaScript/TypeScript - GitHub - microsoft/tsyringe: Lightweight dependency injection container for JavaScript/TypeScript&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Node.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/82</guid>
      <comments>https://8156217.tistory.com/82#entry82comment</comments>
      <pubDate>Thu, 8 Feb 2024 00:27:46 +0900</pubDate>
    </item>
    <item>
      <title>[Nods.JS] fastify/awilix 을 이용한 DI 설계 (JS DI 라이브러리)</title>
      <link>https://8156217.tistory.com/81</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nqs1m/btsEA3KjdAm/Cpvsl5nc3kBiR7T0RUG6LK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nqs1m/btsEA3KjdAm/Cpvsl5nc3kBiR7T0RUG6LK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nqs1m/btsEA3KjdAm/Cpvsl5nc3kBiR7T0RUG6LK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNqs1m%2FbtsEA3KjdAm%2FCpvsl5nc3kBiR7T0RUG6LK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;414&quot; height=&quot;414&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;개발팀 내에서 빠른 생산성을 위해 fastify를 사용하기로 하였고 개발 도중 &lt;b&gt;의존성 주입&lt;/b&gt;에 필요성을 느끼게 되어 awilix를 도입하고자 하였다. 이에 따라 오늘은 &lt;b&gt;fastify에서 awilix를 어떻게 사용하는&lt;/b&gt; &lt;b&gt;지&lt;/b&gt;에 대해서 알아보자.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;nbsp;자바스크립트로 의존성 주입을 설계 하다보면 해당 클래스나 함수에 필요한 의존성들을 미리 등록해 두어야 한다. 이를 Awilix에서는 &lt;b&gt;container&lt;/b&gt;로 관리한다. &lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;필요한 의존성들은 미리 container에 &lt;b&gt;등록(register)&lt;/b&gt; 해두고 필요한 곳에서 &lt;b&gt;꺼내서(resolve)&lt;/b&gt; 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1) 설치&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;npm i @fastify/awilix awilix
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2) 플러그인 연결&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;fastify와 awilix를 연결해 주는 작업을 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const { fastifyAwilixPlugin } = require('@fastify/awilix')
const fastify = require('fastify')

app = fastify({ logger: true })
app.register(fastifyAwilixPlugin, { disposeOnClose: true, disposeOnResponse: true })
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3) 컨테이너에 등록&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너에 의존성 클래스들을 등록한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const { diContainer } = require('@fastify/awilix')
const { asClass, asFunction, Lifetime } = require('awilix')

// Code from the previous example goes here

diContainer.register({
  userRepository: asClass(UserRepository, {
    lifetime: Lifetime.SINGLETON,
    dispose: (module) =&amp;gt; module.dispose(),
  }),
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3-2) 클래스를 사용하여 등록&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클래스를 사용하면 구조화 시켜 관리하기 편하다. 아래 예시는 싱글톤으로 설정하여 한 번만 생성되고 이후에 호출 될 경우 생성된 인스턴스를 사용하게 끔 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class UserService {
  constructor({ userRepository }) {
    this.userRepository = userRepository
  }

  dispose() {
    // Disposal logic goes here
  }
}

class UserRepository {
  constructor() {
    // Constructor logic goes here
  }

  dispose() {
    // Disposal logic goes here
  }
}

diContainer.register({
  userService: asClass(UserRepository, {
    lifetime: Lifetime.SINGLETON,
    dispose: (module) =&amp;gt; module.dispose(),
  }),
  userRepository: asClass(UserRepository, {
    lifetime: Lifetime.SINGLETON,
    dispose: (module) =&amp;gt; module.dispose(),
  }),
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4) 컨테이너에서 꺼내서 사용&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;resolve를 이용하면 간단하게 꺼낼 수있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;app.post('/', async (req, res) =&amp;gt; {
  const userRepositoryForApp = app.diContainer.resolve('userRepository') // This returns exact same result as the previous line

  res.send({
    status: 'OK',
  })
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/fastify/fastify-awilix&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/fastify/fastify-awilix&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1707319370242&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - fastify/fastify-awilix: Dependency injection support for fastify&quot; data-og-description=&quot;Dependency injection support for fastify. Contribute to fastify/fastify-awilix development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/fastify/fastify-awilix&quot; data-og-url=&quot;https://github.com/fastify/fastify-awilix&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lyCE0/hyVjiwbF3v/uKFb5ZD54HaKG9rhJxl5E1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/fastify/fastify-awilix&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/fastify/fastify-awilix&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lyCE0/hyVjiwbF3v/uKFb5ZD54HaKG9rhJxl5E1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - fastify/fastify-awilix: Dependency injection support for fastify&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Dependency injection support for fastify. Contribute to fastify/fastify-awilix development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Node.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/81</guid>
      <comments>https://8156217.tistory.com/81#entry81comment</comments>
      <pubDate>Thu, 8 Feb 2024 00:22:52 +0900</pubDate>
    </item>
    <item>
      <title>[DI] 의존성 주입 (Dependency Injection)이란?</title>
      <link>https://8156217.tistory.com/80</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbQNVW/btsEytDfq3V/Ibv7T0KssmtQaRlWm26Vak/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbQNVW/btsEytDfq3V/Ibv7T0KssmtQaRlWm26Vak/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbQNVW/btsEytDfq3V/Ibv7T0KssmtQaRlWm26Vak/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbQNVW%2FbtsEytDfq3V%2FIbv7T0KssmtQaRlWm26Vak%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;364&quot; height=&quot;363&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;624&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;벡엔드를 공부 하다보면 한 번쯤 &lt;b&gt;의존성 주입&lt;/b&gt;에 대해 들어본 적 있을 것이다. 중요하다는 건 알겠는데 대체 무엇일까??&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;의존성 주입은 의존성(Dependency)과 주입(Injection)이 합쳐진 말이다. 그래서 의존성에 대해서 먼저 이해해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코드와 함께 보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예시 1)&amp;nbsp; 의존성 X&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;class Person {
    driveCar() {
        console.log(&quot;차를 운전합니다.&quot;);
    }
}

const driver = new Person();
driver.driveCar(); // 차를 운전합니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Person 클래스에서 driveCar 메서드를 실행 시키는 단순한 구조이다. Person 클래스는 현재 다른 클래스와 어떤 의존성도 가지고 있지 않은 독립적인 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예시 2) 강한 결합 ( 높은 의존성 )&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Car {
    start() {
        console.log(&quot;차가 출발합니다.&quot;);
    }
}

class Person {
    private car: Car;

    constructor() {
        this.car = new Car(); // 강한 결합: Person이 Car를 직접 생성
    }

    driveCar() {
        this.car.start();
    }
}

const driver = new Person();
driver.driveCar(); // 차가 출발합니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Person 클래스가 생성될 때마다 Car 클래스가 생성된다. Person 은 Car 클래스와 강한 결합을 하고 있다. 이는 유연성이 떨어지고, &lt;b&gt;Car&lt;/b&gt; 클래스의 변경이 &lt;b&gt;Person&lt;/b&gt; 클래스에도 영향을 미칠 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 의존성 이다. 그렇다면 어떻게 코드를 더 유연하게 만들 수 있을까??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예시 3) 유연한 결합 ( 의존성 주입 )&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Car {
    start() {
        console.log(&quot;차가 출발합니다.&quot;);
    }
}

class ElectricCar extends Car {
    start() {
        console.log(&quot;전기차가 조용히 출발합니다.&quot;);
    }
}

class Person {
    private car: Car;

    constructor(car: Car) { // 의존성 주입
        this.car = car;
    }

    driveCar() {
        this.car.start();
    }
}

const myCar = new Car();
const myElectricCar = new ElectricCar();

const driver1 = new Person(myCar);
driver1.driveCar(); // 차가 출발합니다.

const driver2 = new Person(myElectricCar);
driver2.driveCar(); // 전기차가 조용히 출발합니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예시에서는 &lt;b&gt;Car&lt;/b&gt; 클래스를 상속받는 &lt;b&gt;ElectricCar&lt;/b&gt; 클래스를 추가하고, &lt;b&gt;Person&lt;/b&gt; 클래스는 생성자를 통해 어떠한 &lt;b&gt;Car&lt;/b&gt; 타입의 인스턴스도 받을 수 있게 되었다. 이는 &lt;b&gt;Person&lt;/b&gt; 클래스가 다양한 종류의 차량에 대해 유연하게 대응할 수 있게 하며, 코드의 재사용성과 확장성을 향상 되었음을 알 수있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 의존성 주입을 통해 클래스 간의 결합도를 낮추고, 유연성과 재사용성을 높일 수 있다. 또한, 코드를 더 쉽게 테스트할 수 있게 되며, 유지 보수성도 개선된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/80</guid>
      <comments>https://8156217.tistory.com/80#entry80comment</comments>
      <pubDate>Thu, 8 Feb 2024 00:16:20 +0900</pubDate>
    </item>
    <item>
      <title>[Vite] Vite가 나타나게 된 계기 ( feat. 번들러의 역사 )</title>
      <link>https://8156217.tistory.com/79</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0JZfA/btsEmWdTmow/2KoueCE8Yc4gkXKBKk5KQ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0JZfA/btsEmWdTmow/2KoueCE8Yc4gkXKBKk5KQ0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0JZfA/btsEmWdTmow/2KoueCE8Yc4gkXKBKk5KQ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0JZfA%2FbtsEmWdTmow%2F2KoueCE8Yc4gkXKBKk5KQ0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;204&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;744&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Vite가 엄청 떠오르고 있습니다. 최신 번들러 들 중 가장 빠르다고 하는데 대체 왜 빠른 걸까요??&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. &amp;nbsp;번들러가 나오게 된 계기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;ES6가 나타나면서 자바스크립트에서 ESM (ES Modules)를 지원합니다. ESM은 간단하게 말하면 자바스크립트가 모듈화를 할 수 있도록 export / import 기능을 지원하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;script&amp;gt;&amp;nbsp;간 모듈을 내보낼 수 있게 된 것입니다. ESM이 지원되면서 웹 브라우저에서 더 많은 기능들과 많은 활동들이 나타났고 관리해야 하는 소스 코드나 라이브러리들이 늘어나게 되었습니다. 그래서 더 효율 적인 관리 툴이 필요하게 되었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. WebPack의 등장&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;WebPack은 여러 파일과 에셋들을 번들로 합치고 최적화하여 브라우저에서 사용할 수 있게 제공합니다. 압축의 개념으로 볼 수 있습니다. 이를 통해 효율적으로 코드를 관리합니다. 특히 SPA 들에서 큰 빛을 발휘하였습니다. 추가적으로 웹팩은 소스 코드의 변화가 새로고침 없이 브라우저에 바로 반영될 수 있게 하는 &lt;b&gt;HMR &lt;/b&gt;기능과 코드를 여러 개의 번들 파일로 나누어 필요한 시점에 로드할 수 있도록 하는 기능 &lt;b&gt;Code Splitting&lt;/b&gt; 등을 지원합니다. 이 장점들 때문에 웹팩이 필수가 되었다고 해도 무방할 정도로 대부분의 프론트엔드 개발에서 사용하게 되었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. WebPack보다 100배 빠른 ES build의 등장&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;웹팩보다 훨씬 빠르고 효율적인 녀석이 나타났습니다.&amp;nbsp;&lt;b&gt;ES Build&lt;/b&gt;는 웹팩보다 빌드 타임이 100배 가량 빠릅니다. 그 이유는 다음과 같습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네이티브 코드로 컴파일되는 Go 언어로 작성&amp;nbsp;&lt;/li&gt;
&lt;li&gt;파싱, 링크 , 코드 생성 모두를 병렬 처리 (CPU 활용도 최대)&lt;/li&gt;
&lt;li&gt;효율적인 메모리 사용&lt;/li&gt;
&lt;li&gt;불필요한 데이터 변환 / 할당 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. 가장 빠르고 효율적인 Vite&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Vite는 위에 나타난 번들링 툴들의 단점들을 보완합니다. 그래서 왜 Vite가 빠르고 요즘 많이 사용하는 걸까요??&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 이유는 다음과 같습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ES build 사용 - &amp;ldquo;pre-bundling&amp;rdquo; 작업을 WebPack보다 훨씬 빠른 ES build를 바탕으로 진행한다.&lt;/li&gt;
&lt;li&gt;Native ESM 사용 - 코드 수정이 있을 때 브라우저에서 변경 된 부분을 먼저 요청하고 교체된 부분만 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 프로젝트를 하게 된다면 모듈 번들러로 Vite를 선택하는 것을 추천드립니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/79</guid>
      <comments>https://8156217.tistory.com/79#entry79comment</comments>
      <pubDate>Sun, 4 Feb 2024 00:12:52 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 도커에 몽고 DB를 설치하고 실행 시키기</title>
      <link>https://8156217.tistory.com/78</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYHcce/btsEmrdRcAa/rFSrRggmhVFym9DnKIJ5k0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYHcce/btsEmrdRcAa/rFSrRggmhVFym9DnKIJ5k0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYHcce/btsEmrdRcAa/rFSrRggmhVFym9DnKIJ5k0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYHcce%2FbtsEmrdRcAa%2FrFSrRggmhVFym9DnKIJ5k0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;549&quot; height=&quot;549&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;몽고 디비를 로컬에 직접 설치하지 않고&lt;b&gt; 도커 컨테이너 안에 설치하여 접속하여 사용&lt;/b&gt;해보는 방법을 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 도커 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커 공식홈페이지에서 도커를 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.docker.com/get-started/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.docker.com/get-started/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706943247292&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Get Started | Docker&quot; data-og-description=&quot;Get started with Docker Desktop and join millions of developers in faster, more secure app development using containers and beyond.&quot; data-og-host=&quot;www.docker.com&quot; data-og-source-url=&quot;https://www.docker.com/get-started/&quot; data-og-url=&quot;https://www.docker.com/get-started/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bGFd8Z/hyVb7XTiDT/TPXq5xCfTDOZ9ndjXwxVY1/img.png?width=1200&amp;amp;height=627&amp;amp;face=0_0_1200_627,https://scrap.kakaocdn.net/dn/IhXmT/hyVb0YKlaF/dugaoxsLaC9E3srfiGTL2K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/O9aw2/hyVf1PeoCZ/Yosvb55RP8XIzZALWMkLkk/img.png?width=1200&amp;amp;height=627&amp;amp;face=0_0_1200_627&quot;&gt;&lt;a href=&quot;https://www.docker.com/get-started/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.docker.com/get-started/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bGFd8Z/hyVb7XTiDT/TPXq5xCfTDOZ9ndjXwxVY1/img.png?width=1200&amp;amp;height=627&amp;amp;face=0_0_1200_627,https://scrap.kakaocdn.net/dn/IhXmT/hyVb0YKlaF/dugaoxsLaC9E3srfiGTL2K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/O9aw2/hyVf1PeoCZ/Yosvb55RP8XIzZALWMkLkk/img.png?width=1200&amp;amp;height=627&amp;amp;face=0_0_1200_627');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Get Started | Docker&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Get started with Docker Desktop and join millions of developers in faster, more secure app development using containers and beyond.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706943483455&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;~ docker -v
Docker version 24.0.7, build afdd53b&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 몽고 디비 이미지를 Docker Hub로 부터 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706945032089&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker pull mongo&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이미지 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706945090741&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;~ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
mongo        latest    545fe6e3d65b   4 weeks ago   721MB&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 도커 컨테이너 생성 / 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컨테이너 실행&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706945303891&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run --name container_name -d -p 27017:27017 mongo&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--name : 컨테이너 이름 지정&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;-d : 백 그라운드 실행&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;-p : 포트를 연결해준다. ( 27017:27017 -&amp;gt; 로컬의 27017 포트와 컨테이너의 27017포트를 연결 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실행 중인 컨테이너 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706945535438&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;~ docker ps
CONTAINER ID   IMAGE     COMMAND                   CREATED         STATUS         PORTS                      NAMES
ca17f96a34cd   mongo     &quot;docker-entrypoint.s&amp;hellip;&quot;   8 minutes ago   Up 8 minutes   0.0.0.0:27017-&amp;gt;27017/tcp   mongo-container&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;‼ 참고로 모든 컨테이너 (종료된 컨테이너 포함) 를 보려면 ps에 -a를 붙여 주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1706945821795&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; -a, --all             Show all containers (default shows just running)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. 컨테이너에 접속&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) bash로 접속&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;-it : 대화형 상호 작용을 위한 옵션으로, 터미널 입력 및 출력을 활성화하여 사용자가 컨테이너 내부의 명령어를 실행하고 상호 작용할 수 있게 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706946380334&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;~ docker exec -it mongo-container bash
root@ca17f96a34cd:/ ls
bin   data  docker-entrypoint-initdb.d	home	    lib    mnt	proc  run   srv  tmp  var
boot  dev   etc				js-yaml.js  media  opt	root  sbin  sys  usr&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) mongosh로 접속&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706946527656&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;~ docker exec -it mongo-container mongosh
Current Mongosh Log ID:	65bdefd8c8aebdd642b2972e
Connecting to:		mongodb://127.0.0.1:27017/?directConnection=true&amp;amp;serverSelectionTimeoutMS=2000&amp;amp;appName=mongosh+2.1.1
Using MongoDB:		7.0.5
Using Mongosh:		2.1.1

For mongosh info see: https://docs.mongodb.com/mongodb-shell/

------
   The server generated these startup warnings when booting
   2024-02-03T07:23:00.248+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
   2024-02-03T07:23:00.674+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
   2024-02-03T07:23:00.674+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
   2024-02-03T07:23:00.675+00:00: vm.max_map_count is too low
------&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너 실행할 때 -p로 포트 매핑을 했었다면 로컬에서&lt;/p&gt;
&lt;pre id=&quot;code_1706946561304&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;~ mongosh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만쳐도 접속 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 로컬과 포트 매핑 까지 해두면 개발할 때 로컬 환경에서 도커의 몽고 디비를 연결해서 사용할 수 있다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/78</guid>
      <comments>https://8156217.tistory.com/78#entry78comment</comments>
      <pubDate>Sat, 3 Feb 2024 16:52:51 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] AWS의 Cloud Front 서비스에 대해 알아보자 ( feat. 캐싱 )</title>
      <link>https://8156217.tistory.com/77</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;173&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JQgUN/btsD4junIdb/7vgiSBQuGEZYCuQOy9i7o0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JQgUN/btsD4junIdb/7vgiSBQuGEZYCuQOy9i7o0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JQgUN/btsD4junIdb/7vgiSBQuGEZYCuQOy9i7o0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJQgUN%2FbtsD4junIdb%2F7vgiSBQuGEZYCuQOy9i7o0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;291&quot; height=&quot;173&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;173&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;개발자들은 데이터를 사용자들에게 더 빠르게 전달하기 위해 &lt;b&gt;캐싱&lt;/b&gt;을 이용한다.&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;캐싱이란 사용자에게 데이터에 더 &lt;b&gt;빠르게&lt;/b&gt; 도달할 수 있도록 접근성이 더 좋은 &lt;b&gt;임시 저장 위치&lt;/b&gt;에 &lt;b&gt;데이터 복사본&lt;/b&gt;을 미리 저장해 두는 것이다.&amp;nbsp; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;그렇다면 사용자에게 프론트엔드의 화면 단&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;을 사용자에게 더 빠르게 보여주려면 어떤 방법이 있을까?? &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;바로 AWS의 &lt;b&gt;Cloud Front 서비스&lt;/b&gt;를 이용하는 방법이 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&amp;nbsp;AWS Cloud Front 서비스는 사용자가 화면 단을 더 빠르게 제공 받을 수 있도록&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&lt;b&gt;엣지 로케이션(Edge Location)&lt;/b&gt; 이라는 임시 저장 위치에 &lt;b&gt;오리진 서버(Origin)&lt;/b&gt;의 원본 데이터인&amp;nbsp;&lt;b&gt;.&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&lt;b&gt;html, .css, .js 및 이미지 파일과 같은 정적 및 동적 웹 콘텐츠 &lt;/b&gt;복사본을 미리 저장해 둔다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #16191f; text-align: start;&quot;&gt;여기서 잠깐 용어 정리...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;엣지 로케이션 (Edge Location) : 다양하게 분포해 있는 임시 저장 공간&lt;br /&gt;오리진 서버 (Origin) : EC2 서버나 S3 버킷과 같은 화면의 원본 데이터를 가지고 있는 서버&lt;br /&gt;지연 시간(Latency) : 네트워크를 통해 데이터를 전송하는 데 걸리는 시간&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;S3나 EC2 서버의 데이터를 여러 개의 엣지 로케이션에 복사해 두고 요청이 왔을 때 사용자에게 &lt;b&gt;제일 지연 시간이 낮은 엣지 로케이션에서 데이터를 제공&lt;/b&gt;해준다. 이 방식은 사용자에게 지연 시간을 단축 시켜주기 때문에 더 나은 사용자 경험을 제공할 수 있다. 이 때 지연 시간이 낮다는 것은 &lt;b&gt;물리적 거리나 트래픽 상황&lt;/b&gt;에 따라 결정 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;만약 S3나 EC2의 서버의 원본 데이터가 &lt;b&gt;변경&lt;/b&gt; 되었다면 사용자의 요청이 엣지 로케이션으로 왔을 때 바로 제공하지 않고 S3나 EC2로 가서 변경된 데이터를 가지고 와서 엣지 로케이션의 데이터를 &lt;b&gt;업데이트&lt;/b&gt; &lt;b&gt;해준 뒤 사용자에게 제공&lt;/b&gt; 한다. 일종의 &lt;b&gt;CDN&lt;/b&gt; &lt;b&gt;(content Delivery Network)&lt;/b&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;앞으로 토이 프로젝트 할 일이 있다면 직접 꼭 적용 해봐야 겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706546504391&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Amazon CloudFront란 무엇입니까? - Amazon CloudFront&quot; data-og-description=&quot;Amazon CloudFront란 무엇입니까? Amazon CloudFront는 .html, .css, .js 및 이미지 파일과 같은 정적 및 동적 웹 콘텐츠를 사용자에게 더 빨리 배포하도록 지원하는 웹 서비스입니다. CloudFront는 엣지 로케이션&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MWbWN/hyVb8By6iP/AN7mKVPocxKZlkZTvokUKK/img.png?width=598&amp;amp;height=500&amp;amp;face=0_0_598_500&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MWbWN/hyVb8By6iP/AN7mKVPocxKZlkZTvokUKK/img.png?width=598&amp;amp;height=500&amp;amp;face=0_0_598_500');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Amazon CloudFront란 무엇입니까? - Amazon CloudFront&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Amazon CloudFront란 무엇입니까? Amazon CloudFront는 .html, .css, .js 및 이미지 파일과 같은 정적 및 동적 웹 콘텐츠를 사용자에게 더 빨리 배포하도록 지원하는 웹 서비스입니다. CloudFront는 엣지 로케이션&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AWS</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/77</guid>
      <comments>https://8156217.tistory.com/77#entry77comment</comments>
      <pubDate>Tue, 30 Jan 2024 01:48:42 +0900</pubDate>
    </item>
    <item>
      <title>[Apache] 웹서버 리버스 프록시 설정 ( Feat. Next.js 프로젝트 )</title>
      <link>https://8156217.tistory.com/76</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUWRf1/btsD6wS9Axn/9KjYCZ8rNo987lQLWkSAak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUWRf1/btsD6wS9Axn/9KjYCZ8rNo987lQLWkSAak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUWRf1/btsD6wS9Axn/9KjYCZ8rNo987lQLWkSAak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUWRf1%2FbtsD6wS9Axn%2F9KjYCZ8rNo987lQLWkSAak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;364&quot; height=&quot;138&quot; data-origin-width=&quot;364&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;아파치 웹 서버에 배포한 Next.JS 프로젝트를 위해서 웹서버에 리버스 프록시를 설정하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;저의 Next.JS 프로젝트를 서버에서 실행 시키면 포트는 &lt;b&gt;3031&lt;/b&gt; 이고 경로는 &lt;b&gt;루트(/)&lt;/b&gt;로 열리게 됩니다. 그럼&lt;span&gt;&amp;nbsp;&lt;b&gt;{도메인}&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;a style=&quot;color: #000000; text-align: start;&quot; href=&quot;http://walab.handong.edu:3031/&quot; data-token-index=&quot;1&quot;&gt;&lt;span&gt;:3031&lt;/span&gt;&lt;/a&gt;/&lt;/b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 접속하면 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Next.JS 프로젝트&lt;/span&gt;에 접속할 수 있었습니다. 근데 이 서버에는 여러 가지 프로젝트들이 많이 있었습니다.&lt;br /&gt;&lt;span&gt;그래서 웹 서버 관리자가 루트 경로가 아닌 &lt;b&gt;{도메인}&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;a style=&quot;color: #000000; text-align: start;&quot; href=&quot;http://walab.handong.edu/sw-mileage-admin&quot; data-token-index=&quot;3&quot;&gt;&lt;span&gt;/sw-mileage-admin&lt;/span&gt;&lt;/a&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;으로 접속 할 수 있기를 원했습니다. 포트는 &lt;b&gt;80&lt;/b&gt; 이고 경로는 &lt;b&gt;/sw-mileage-admin&lt;/b&gt; 임을 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Why 리버스 프록시?? &lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포워드 프록시 : 클라이언트 &amp;rarr; 인터넷 으로 나가는 요청을 중개한다. 리다이렉션이 가능 하지만 나가는 요청을 리다이렉트하는 것이기에 적절하지 않다.&lt;/li&gt;
&lt;li&gt;포트 포워딩 : 들어오는 요청의 IP와 포트를 변경 시킬 수 있으나 경로를 변경하기에는 적절하지 않음&lt;/li&gt;
&lt;li&gt;리버스 프록시 :&amp;nbsp;외부의 요청 -&amp;gt; 내부 서버(들)로 전달. 들어오는 요청의 포트와 경로를 변경할 수 있으며, 여러 서버에 대한 요청을 효율적으로 관리할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;웹 서버에 설정 파일에 코드를 추가하면 된다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 세 가지만 해주면 된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;클라이언트 접근 권한 허용&lt;br /&gt;요청 경로 설정&lt;br /&gt;정적 파일 경로 설정&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;/etc/apache2/sites-available/000-default.conf&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706463023767&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;

				
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html

        # 해당 주소로의 모든 클라이언트들의 접근을 허용
        &amp;lt;Proxy &quot;http://localhost:3031&quot;&amp;gt;
         Require all granted
        &amp;lt;/Proxy&amp;gt;

         # /sw-mileage 경로로 들어오는 요청을 localhost:3031로 리디렉션
         ProxyPass /sw-mileage-admin http://localhost:3031
         ProxyPassReverse /sw-mileage-admin http://localhost:3031
		
         # 정적 파일 Alias 설정 (_next)
         Alias &quot;/_next&quot; &quot;/home/sw_mileage/SW-Milege-Front/.next&quot;
		    &amp;lt;Directory &quot;/home/sw_mileage/SW-Milege-Front/.next&quot;&amp;gt;
		        Options FollowSymLinks
		        AllowOverride All
		        Require all granted
		    &amp;lt;/Directory&amp;gt;


        # 정적 파일 Alias 설정 (assets)
        Alias &quot;/assets&quot; &quot;/home/sw_mileage/SW-Milege-Front/public/assets&quot;
        &amp;lt;Directory &quot;/home/sw_mileage/SW-Milege-Front/public/assets&quot;&amp;gt;
            Options FollowSymLinks
            AllowOverride All
            Require all granted
        &amp;lt;/Directory&amp;gt;
		
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
		
&amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성 후 아래 커맨드를 통해 웹 서버를 재시작 하면 적용이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1706463309773&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo systemctl restart apache2&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/76</guid>
      <comments>https://8156217.tistory.com/76#entry76comment</comments>
      <pubDate>Mon, 29 Jan 2024 02:35:35 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] getServerSideProps 에서 403 인증 에러 캐치 후 로그인 페이지로 리다이렉션 시키기</title>
      <link>https://8156217.tistory.com/75</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MDBam/btsD3JeHtcG/bL7BjKOYm01eO374ObU5SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MDBam/btsD3JeHtcG/bL7BjKOYm01eO374ObU5SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MDBam/btsD3JeHtcG/bL7BjKOYm01eO374ObU5SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMDBam%2FbtsD3JeHtcG%2FbL7BjKOYm01eO374ObU5SK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Next JS 프로젝트에서 인증 되지 않은 사용자가 페이지를 사용할 때는 로그인 페이지로 리다이렉션 시키는 로직을 추가하고자 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;플로우는 다음과 같다&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;getServerSideProps를 사용하여 서버 사이드에서 인증 토큰을 헤더에 넣어 GET 요청을 보낸다.&lt;br /&gt;백앤드에서 토큰이 유효 하지 않음을 파악하고 403 에러를 반환한다.&lt;br /&gt;403 에러를 캐치하여 페이지 렌더링 시 리다이렉션 시키는 로직을 추가한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;getServerSideProps&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706428740695&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 서버 사이드 요청
const getServerSidePropsFunction: GetServerSideProps&amp;lt;{
  fetchData: IGetMileageCategory[];
}&amp;gt; = async (context) =&amp;gt; {
  setServerSideCookie(context);        // 요청에 토큰 추가
  const res = await axiosInstance.get('/api/mileage/categories');
  const fetchData = res.data;

  return { props: { fetchData } };
};


// 에러 캐치 템플릿 적용
export const getServerSideProps = withTryCatchForSSR(getServerSidePropsFunction);


// requireLogin , error 전달
export default function MileageCategory({
  fetchData,
  requireLogin,
  error,
}: InferGetServerSidePropsType&amp;lt;typeof getServerSideProps&amp;gt;) {
  if (requireLogin) {
    handleServerAuth403Error(error);
    return;
  }
  
  
  return (
   
   &amp;lt;&amp;gt;
   	...
   &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;403TryCatchTemplate&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706429404910&quot; class=&quot;typescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;import { GetServerSideProps } from 'next';
import axios, { AxiosError } from 'axios';

export const withTryCatchForSSR = &amp;lt;P&amp;gt;(
  getServerSidePropsFunction: GetServerSideProps&amp;lt;P&amp;gt;
): GetServerSideProps&amp;lt;P&amp;gt; =&amp;gt; {
  return async (context) =&amp;gt; {
    try {
      return await getServerSidePropsFunction(context);
    } catch (error) {
      const axiosError = error as AxiosError;

      if (axiosError.isAxiosError &amp;amp;&amp;amp; axiosError.response?.status === 403) {
        return {
          props: {
            requireLogin: true,      // 로그인 필요함을 나타내는 플래그
            error: '로그인이 필요합니다',
            permanent: false,
          } as unknown as P,
        };
      } else {
        console.error('Error:', axiosError.message);
        return {
          props: {
            fetchData: null,
            error: axiosError.message || 'An error occurred',
          } as unknown as P,
        };
      }
    }
  };
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;handle403AuthError&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706429394178&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 쿠키 제거 및 로그인 페이지 리다이렉션
export const handleServerAuth403Error = async (errorMessage) =&amp;gt; {
  setSession(null);   // 쿠키 제거
  window.location.href = '/auth/login';
  alert(errorMessage); 
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/75</guid>
      <comments>https://8156217.tistory.com/75#entry75comment</comments>
      <pubDate>Sun, 28 Jan 2024 17:04:48 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] GetServerSideProps 헤더에 인증 토큰 추가 하는 방법 (쿠키 사용)</title>
      <link>https://8156217.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mdNj4/btsD3IUpzeo/nH0qgsxUxwuwLz0ntdw20K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mdNj4/btsD3IUpzeo/nH0qgsxUxwuwLz0ntdw20K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mdNj4/btsD3IUpzeo/nH0qgsxUxwuwLz0ntdw20K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmdNj4%2FbtsD3IUpzeo%2FnH0qgsxUxwuwLz0ntdw20K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;Next.js에서는 클라이언트에서 API 요청을 보내는 방법이 있고 GetServerSideProps 함수 처럼 서버 사이드에서 API 요청을 보내는 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;클라이언트 사이드에서 요청 시&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 사이드에서는 보통 브라우저의 JavaScript를 통해 API 요청을 보낸다.&lt;/li&gt;
&lt;li&gt;JWT 엑세스 토큰과 같은 인증 정보를 로컬 스토리지, 세션 스토리지, 쿠키 등에 저장할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;서버 사이드에서 요청 시&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 사이드에서는 Next.js의 렌더링 과정 중에 API 요청을 처리한다.&lt;/li&gt;
&lt;li&gt;서버 사이드에서는&amp;nbsp;클라이언트 사이드의 로컬 스토리지나 세션 스토리지에 접근할 수 없기 때문에, 대신 HTTP 요청의 쿠키를 통해 인증 정보를 관리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;우리 개발 팀에서는 인가를 위해 Jwt 엑세스 토큰 사용하였기에 브라우저 어딘가에 저장하였다가 API 요청 시 요청 헤더에 토큰을 붙여 줘야 했다. 이 때 로컬 스토리지에 토큰을 저장한다면 서버 사이드에서 요청을 보낼 때 접근이 불가해서 값을 가져올 수 없었다. 그래서 쿠키를 이용했다. getServerSideProps의 context 객체에서 쿠키를 꺼내어 요청 헤더에 토큰을 붙여 줘야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;getServerSideProps&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 내에서 제공하는 context 객체를 받아서 cookie를 꺼내고 요청 헤더에 입력한다.&lt;/p&gt;
&lt;pre id=&quot;code_1706427390403&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const getServerSidePropsFunction: GetServerSideProps&amp;lt;{
  fetchData: IGetData;
}&amp;gt; = async (context) =&amp;gt; {
  setServerSideCookie(context);   // 쿠키 꺼내고 요청 헤더에 입력
  
  const res = await axiosInstance.get('/api/mileage/admins');
  const fetchData = res.data;

  return { props: { fetchData } };
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;쿠키 설정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706427157124&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export function setServerSideCookie(context) {
  let { cookie } = context.req.headers;

  cookie = getKeyFromPairString(cookie, 'accessToken');

  if (cookie !== '') {
    axiosInstance.defaults.headers.common.Authorization = `Bearer ${cookie}`;
  }
}

export function getKeyFromPairString(cookie, key) {
  const pairArr = cookie ? cookie?.split(';').map((pair) =&amp;gt; pair.trim()) : [];

  for (const pair of pairArr) {
    const [pairKey, pairValue] = pair.split('=').map((c) =&amp;gt; c.trim());

    if (pairKey === key) {
      return pairValue;
    }
  }

  return '';
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/74</guid>
      <comments>https://8156217.tistory.com/74#entry74comment</comments>
      <pubDate>Sun, 28 Jan 2024 16:41:10 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] 쉘 스크립트를 통한 배포 자동화</title>
      <link>https://8156217.tistory.com/73</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPdQYJ/btsD4tbtDCR/RtZY4EkILcKcus6JukB2EK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPdQYJ/btsD4tbtDCR/RtZY4EkILcKcus6JukB2EK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPdQYJ/btsD4tbtDCR/RtZY4EkILcKcus6JukB2EK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPdQYJ%2FbtsD4tbtDCR%2FRtZY4EkILcKcus6JukB2EK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;교수님의 서버에 배포한 서비스를 자동화 시키고 싶은데 깃허브 액션과 젠킨스 사용이 방화벽 이슈로 어려웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그래서 생각한 방안이 배포 자동화 쉘 스크립트이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;미리 작성한 쉘 스크립트를 실행 시키기만 하면 배포를 자동으로 해주는..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;서버에 필요한 것&lt;br /&gt;&lt;br /&gt;1. Node.js&lt;br /&gt;&lt;/span&gt;2. pm2 (백 그라운드 실행)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;이것만 있으면 됩니다.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;쉘 스크립트 내용&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;중간 중간 ~/log/front-manager-deploy.log 파일에 로그를 찍습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706423899345&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

# 마일리지 관리자 페이지 프론트앤드 pull -&amp;gt; build -&amp;gt; execute (pm2) 자동화

logFile=&quot;$HOME/log/front-manager-deploy.log&quot;
SourceDir=&quot;SW-Milege-Front&quot;


# 현재 날짜와 시간을 로그 파일에 기록
echo &quot;Deployment 시작 시간: $(date)&quot; &amp;gt; $logFile

cd ~


# 기존 레파지토리 삭제
echo &quot;SW-Milege-Front 파일이 삭제됩니다...&quot; &amp;amp;&amp;amp; echo &quot;SW-Milege-Front 파일이 삭제
됩니다...&quot; &amp;gt;&amp;gt; $logFile
rm -rf $HOME/$SourceDir &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1


# 레파지토리 다시 clone
echo &quot;새로운 깃레포를 가져옵니다...&quot; &amp;amp;&amp;amp; echo &quot;새로운 깃레포를 가져옵니다...&quot; &amp;gt;&amp;gt; $logFile
git clone https://github.com/HGU-WALAB/SW-Milege-Front.git &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1


# 미리 작성해둔 환경 변수 파일 복사
echo &quot;환경 변수를 추가합니다...&quot; &amp;amp;&amp;amp; echo &quot;환경 변수를 추가합니다...&quot; &amp;gt;&amp;gt; $logFile
cp $HOME/secret/manager/.env $HOME/secret/manager/.env.local $HOME/secret/manager/.env.production $HOME/$SourceDir &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1


cd $HOME/$SourceDir


# clone해 온 레파지토리의 패키지 설치
echo &quot;패키지를 설치합니다...&quot; &amp;amp;&amp;amp; echo &quot;패키지를 설치합니다...&quot; &amp;gt;&amp;gt; $logFile
npm install --force &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1


# 레파지토리 빌드
echo &quot;빌드 합니다...&quot; &amp;amp;&amp;amp; echo &quot;빌드 합니다...&quot; &amp;gt;&amp;gt; $logFile
npm run build &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1


# 현재 돌아 가고 있는 서버 종료 (pm2 delete)
echo &quot;기존 서버를 끕니다...&quot;  &amp;amp;&amp;amp; echo &quot;기존 서버를 끕니다...&quot; &amp;gt;&amp;gt; $logFile
pm2 delete &quot;sw-mileage-admin&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1


# pm2로 nextJS 백그라운드 실행
echo &quot;새로운 서버를 시작합니다...&quot; &amp;amp;&amp;amp; echo &quot;새로운 서버를 시작합니다...&quot; &amp;gt;&amp;gt; $logFile
pm2 start &quot;npm run start&quot; --name &quot;sw-mileage-admin&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1

pm2 ps &amp;amp;&amp;amp; pm2 ps &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1

echo &quot;마일리지 관리자 프론트앤드 배포 스크립트 완료...&quot; &amp;amp;&amp;amp; echo &quot;마일리지 관리자
 프론트앤드 배포 스크립트 완료...&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;진행 순서&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;기존 레파지 토리 삭제&lt;br /&gt;-&amp;gt; 레파지토리 클론&lt;br /&gt;-&amp;gt; 미리 작성해둔 환경 변수 파일 복사&lt;br /&gt;-&amp;gt; npm install (패키지 설치)&lt;br /&gt;-&amp;gt; npm build (빌드)&lt;br /&gt;-&amp;gt; pm2 delete (기존 서비스 종료)&lt;br /&gt;-&amp;gt; pm2로 next.js 백그라운드 실행&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 작성을 완료했으니 실행만 시키면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;실행 방법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1) 서버의 Host , Username , Password 를 이용해 ssh로 접속&lt;/p&gt;
&lt;pre id=&quot;code_1706424637670&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ssh username@host

-&amp;gt; password 입력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2) 스크립트 실행 권한 부여&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 실행할 스크립트로 이동합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 ~/sw_mileage/sh-script 에 위치 시켜 두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;front-manager-deploy.sh가 위의 스크립트 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-01-28 오후 3.52.31.png&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FDc05/btsD2tp9I4R/3VNNJONaJvyMW6lo7YJg21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FDc05/btsD2tp9I4R/3VNNJONaJvyMW6lo7YJg21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FDc05/btsD2tp9I4R/3VNNJONaJvyMW6lo7YJg21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFDc05%2FbtsD2tp9I4R%2F3VNNJONaJvyMW6lo7YJg21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;606&quot; height=&quot;114&quot; data-filename=&quot;스크린샷 2024-01-28 오후 3.52.31.png&quot; data-origin-width=&quot;606&quot; data-origin-height=&quot;114&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706424817127&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chmod 750 front-manager-deploy.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-01-28 오후 3.54.21.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;84&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tOL9G/btsD3lLSAlC/7p4yxIeRwllDElxzvokbJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tOL9G/btsD3lLSAlC/7p4yxIeRwllDElxzvokbJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tOL9G/btsD3lLSAlC/7p4yxIeRwllDElxzvokbJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtOL9G%2FbtsD3lLSAlC%2F7p4yxIeRwllDElxzvokbJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;84&quot; data-filename=&quot;스크린샷 2024-01-28 오후 3.54.21.png&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;84&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 권한이 생겼습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3) 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706424895817&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./front-manager-deploy.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;+ 추가로 리액트 배포를 위한 쉘 스크립트도 작성한 것이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리액트의 경우는 정적 배포를 진행 했기에 node.js, pm2가 필요하지 않습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;~/sh-script/front-student-deploy.sh&lt;/p&gt;
&lt;pre id=&quot;code_1706425328979&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;                                                                                              1,1          모두
#!/bin/bash

# 마일리지 학생 시스템 프론트앤드 배포 자동화 스크립트

logFile=&quot;$HOME/log/front-student-deploy.log&quot;
SourceDir=&quot;SW-Mileage-Student-Front&quot;

cd ~

# 현재 날짜와 시간을 로그 파일에 기록
echo &quot;Deployment 시작 시간: $(date)&quot; &amp;gt; $logFile

echo &quot;SW-Mileage-Student-Front 폴더를 삭제합니다...&quot; &amp;amp;&amp;amp; echo &quot;SW-Mileage-Student-Front 폴더를 삭제합니다...&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
rm -rf $HOME/$SourceDir &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1

echo &quot;새로운 깃레포를 가져옵니다...&quot; &amp;amp;&amp;amp; echo &quot;새로운 깃레포를 가져옵니다...&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
git clone https://github.com/HGU-WALAB/SW-Mileage-Student-Front.git &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1

echo &quot;환경 변수를 가져옵니다...&quot; &amp;amp;&amp;amp; echo &quot;환경 변수를 가져옵니다...&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
cp $HOME/secret/student/.env $HOME/$SourceDir &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1

cd $HOME/$SourceDir

echo &quot;패키지를 가져옵니다...&quot; &amp;amp;&amp;amp; echo &quot;패키지를 가져옵니다...&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
npm install &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1

echo &quot;빌드를 진행합니다...&quot; &amp;amp;&amp;amp; echo &quot;빌드를 진행합니다...&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
npm run build &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1

echo &quot;빌드 파일을 html 폴더로 옮깁니다...&quot; &amp;amp;&amp;amp; echo &quot;빌드 파일을 html 폴더로 옮깁니다...&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
rm -rf $HOME/html/* &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
cp -R $HOME/$SourceDir/build/* $HOME/html &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1
echo &quot;&quot; &amp;amp;&amp;amp; echo &quot;&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1

echo &quot;학생 시스템 스크립트 실행 완료...&quot; &amp;amp;&amp;amp; echo &quot;학생 시스템 스크립트 실행 완료...&quot; &amp;gt;&amp;gt; $logFile 2&amp;gt;&amp;amp;1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 방법은 Next.js와 같습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Next.js</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/73</guid>
      <comments>https://8156217.tistory.com/73#entry73comment</comments>
      <pubDate>Sun, 28 Jan 2024 15:56:31 +0900</pubDate>
    </item>
    <item>
      <title>[Data Frame] 많이 사용하는 함수 모음 ( DataFrame 생성 ,  Columns , head , tail , iloc  , set_option  등 )</title>
      <link>https://8156217.tistory.com/71</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DgYeE/btsD1caWRyT/TgyaYy0FyxPrxTKkr4TiB0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DgYeE/btsD1caWRyT/TgyaYy0FyxPrxTKkr4TiB0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DgYeE/btsD1caWRyT/TgyaYy0FyxPrxTKkr4TiB0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDgYeE%2FbtsD1caWRyT%2FTgyaYy0FyxPrxTKkr4TiB0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;350&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;오늘은 파이썬 데이터 분석 라이브러리인 Pandas의 &lt;b&gt;&quot;Data Frame&quot;&amp;nbsp;&lt;/b&gt;에서 많이 사용되는 함수에 대해 알아보겠습니다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;0. Import&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1706338786416&quot; class=&quot;elm&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;import pandas as pd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1. DataFrame 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;1) Dictionary로 Data Frame 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706338859615&quot; class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;d = {'col1': [1, 2], 'col2': [3, 4]}
df = pd.DataFrame(data=d)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;2) Array로 Data Frame 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706339287494&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;d = [['Hayoon', 165, 53], ['Orim', 182, 64], ['Minsu', 172, 82]]
people_info = pd.DataFrame(data=d, columns = ['name', 'cm', 'kg'])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;3) numpy 의 array로 Data Frame 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706339365872&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; df2 = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]),
                    columns=['a', 'b', 'c'])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. columns&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열의 이름 (헤더 정보) 가져 오기&lt;/p&gt;
&lt;pre id=&quot;code_1706339477434&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})

// 열 헤더 출력
df.columns
Index(['A', 'B'], dtype='object')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3. head()&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;처음 ~ 지정된 값( 기본값: 5 )만큼의 갯수의 행을 보여 줌&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706339600404&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df = pd.DataFrame({'A': [1, 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ]})

# 첫 5개의 행 출력
df.head()

   A
0  1
1  2
2  3
3  4
4  5

# 첫 3개의 행 출력
df.head(3)

   A
0  1
1  2
2  3

# 끝의 2개 제외한 모든 행 출력
 df.head(-2)
   A
0  1
1  2
2  3
3  4
4  5
5  6
6  7
7  8&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;4. tail()&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;끝부터 지정된 값( 기본값: 5 )만큼의 갯수의 행을 보여 줌&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706340206101&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df = pd.DataFrame({'A': [1, 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ]})

# 마지막 5개의 행 출력
df.tail()

	A
5   6
6   7
7   8
8   9
9  10

# 마지막 3개의 행 출력
df.tail(3)
    A
7   8
8   9
9  10

# 첫 2개 제외 한 모든 행 출력

df.tail(-2)
    A
2   3
3   4
4   5
5   6
6   7
7   8
8   9
9  10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;5.&amp;nbsp;iloc&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Data Frame 자르기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[행 , 열]을 기준으로 자른다.&lt;/p&gt;
&lt;pre id=&quot;code_1706340888659&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mydict = [{'a': 1, 'b': 2, 'c': 3, 'd': 4},
           {'a': 100, 'b': 200, 'c': 300, 'd': 400},
           {'a': 1000, 'b': 2000, 'c': 3000, 'd': 4000}]
df = pd.DataFrame(mydict)
df
      a     b     c     d
0     1     2     3     4
1   100   200   300   400
2  1000  2000  3000  4000



// 0 번째 행 뽑아 내기
&amp;gt;&amp;gt;&amp;gt; df.iloc[0]
a    1
b    2
c    3
d    4
Name: 0, dtype: int64

// 1 행(Row) , 2 열(Column) 뽑아 내기
df.iloc[1,2]
300

// 2행 ~ , 3열 ~ 뽑아내기

df.iloc[1: , 2:]
      c     d
1   300   400
2  3000  4000


// ~ 1행 , ~ 2열 뽑아내기

 df.iloc[:1, :2]
   a  b
0  1  2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;6. set_option&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;set_option로 pandas의 옵션을 변경할 수 있습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;저는 모든 행과 열을 볼 수 있게 하는데 주로 사용합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706341309850&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df = pd.DataFrame({'x': range(30)})

# 중간 행이 .. 으로 짤려서 출력
df
     x
0    0
1    1
2    2
3    3
4    4
..  ..
25  25
26  26
27  27
28  28
29  29&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;2) 모든&amp;nbsp;Row를&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해줌&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706341481631&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pd.set_option('display.max_rows',None)

df

# 모든 열 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;2) 모든&amp;nbsp;열을&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있게&amp;nbsp;해줌&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1706341591788&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pd.set_option('display.max_columns', None)

df

# 모든 행 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pandas.pydata.org/docs/reference/frame.html&quot;&gt;https://pandas.pydata.org/docs/reference/frame.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1706342558203&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;DataFrame &amp;mdash; pandas 2.2.0 documentation&quot; data-og-description=&quot;Warning DataFrame.attrs is considered experimental and may change without warning.&quot; data-og-host=&quot;pandas.pydata.org&quot; data-og-source-url=&quot;https://pandas.pydata.org/docs/reference/frame.html&quot; data-og-url=&quot;https://pandas.pydata.org/docs/reference/frame.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://pandas.pydata.org/docs/reference/frame.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pandas.pydata.org/docs/reference/frame.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;DataFrame &amp;mdash; pandas 2.2.0 documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Warning DataFrame.attrs is considered experimental and may change without warning.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pandas.pydata.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/71</guid>
      <comments>https://8156217.tistory.com/71#entry71comment</comments>
      <pubDate>Sat, 27 Jan 2024 16:49:24 +0900</pubDate>
    </item>
    <item>
      <title>[Spring-boot] spring-boot 프로젝트 터미널에서 빌드하는 방법 (gradle)</title>
      <link>https://8156217.tistory.com/70</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdcEnE/btrVamolfWW/ZFKeNKH19Hdj2rl3SwZxjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdcEnE/btrVamolfWW/ZFKeNKH19Hdj2rl3SwZxjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdcEnE/btrVamolfWW/ZFKeNKH19Hdj2rl3SwZxjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdcEnE%2FbtrVamolfWW%2FZFKeNKH19Hdj2rl3SwZxjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;315&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;터미널을 키고 프로젝트 파일로 이동한다&lt;span&gt;.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfS5WR/btrVebUaDIV/BT0EK74N5tzD7QhgAuv7yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfS5WR/btrVebUaDIV/BT0EK74N5tzD7QhgAuv7yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfS5WR/btrVebUaDIV/BT0EK74N5tzD7QhgAuv7yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfS5WR%2FbtrVebUaDIV%2FBT0EK74N5tzD7QhgAuv7yk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;488&quot; height=&quot;315&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672725364295&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./gradlew build&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1oHkx/btrVfrCaoJP/9MePSbuxIi98TgTEVzC6tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1oHkx/btrVfrCaoJP/9MePSbuxIi98TgTEVzC6tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1oHkx/btrVfrCaoJP/9MePSbuxIi98TgTEVzC6tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1oHkx%2FbtrVfrCaoJP%2F9MePSbuxIi98TgTEVzC6tk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;451&quot; height=&quot;249&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672725377270&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd build/libs
java -jar jar파일이름&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clsNA3/btrVfiSOFPt/1T2DdDpK3Eu8IBlbKAfzV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clsNA3/btrVfiSOFPt/1T2DdDpK3Eu8IBlbKAfzV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clsNA3/btrVfiSOFPt/1T2DdDpK3Eu8IBlbKAfzV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclsNA3%2FbtrVfiSOFPt%2F1T2DdDpK3Eu8IBlbKAfzV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;452&quot; height=&quot;373&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빌드완료&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;Localhost:8080&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/waNEY/btrVcNzbDeO/EqT7x0trBLe5LpeyFTj6fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/waNEY/btrVcNzbDeO/EqT7x0trBLe5LpeyFTj6fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/waNEY/btrVcNzbDeO/EqT7x0trBLe5LpeyFTj6fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwaNEY%2FbtrVcNzbDeO%2FEqT7x0trBLe5LpeyFTj6fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;451&quot; height=&quot;350&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;350&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;build&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;를 지우고 다시 생성하고 싶다면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;gradlew&lt;/span&gt;가 있는 파일로 다시가서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672725410263&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./gradle clean
./gradle clean build&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wun4H/btrVjm09qBS/7oucGkrHU2WQl2mRGD9qDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wun4H/btrVjm09qBS/7oucGkrHU2WQl2mRGD9qDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wun4H/btrVjm09qBS/7oucGkrHU2WQl2mRGD9qDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwun4H%2FbtrVjm09qBS%2F7oucGkrHU2WQl2mRGD9qDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;451&quot; height=&quot;373&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Build&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;파일이 삭제된 것을 볼 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후에 다시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;./gradlew build&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하면 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Java Spring</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/70</guid>
      <comments>https://8156217.tistory.com/70#entry70comment</comments>
      <pubDate>Tue, 3 Jan 2023 14:57:07 +0900</pubDate>
    </item>
    <item>
      <title>[Spring-boot] 스프링 부트 간단한 페이지 만들기 (Welcome page , Controller)</title>
      <link>https://8156217.tistory.com/69</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-03 오후 2.35.07.png&quot; data-origin-width=&quot;1462&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSLGx/btrVjQARyop/c7id2bMPExCS7CN8Ol5rt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSLGx/btrVjQARyop/c7id2bMPExCS7CN8Ol5rt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSLGx/btrVjQARyop/c7id2bMPExCS7CN8Ol5rt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSLGx%2FbtrVjQARyop%2Fc7id2bMPExCS7CN8Ol5rt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1462&quot; height=&quot;444&quot; data-filename=&quot;스크린샷 2023-01-03 오후 2.35.07.png&quot; data-origin-width=&quot;1462&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;오늘은 갓 만든 프로젝트를 가지고 간단한 페이지를 만들어 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;먼저 처음 실행시키면 뜨게 되는 Welcome page (index.html)을 만들어보고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;Controller를 이용하여 아주 간단한 hello.html 페이지도 만들어보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;Welcome Page&amp;nbsp;만들기&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;src / main / resources / static&amp;nbsp;경로에&amp;nbsp;index.html&amp;nbsp;파일 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;377&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2UUek/btrVf7wDfqO/px37RtQ47Qfu6xh3EizHWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2UUek/btrVf7wDfqO/px37RtQ47Qfu6xh3EizHWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2UUek/btrVf7wDfqO/px37RtQ47Qfu6xh3EizHWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2UUek%2FbtrVf7wDfqO%2Fpx37RtQ47Qfu6xh3EizHWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;377&quot; height=&quot;312&quot; data-origin-width=&quot;377&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;index.html&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
	&amp;lt;head&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 	&amp;lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html&quot; charset=&quot;UTF-8&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 	&amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
	&amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
    	&amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;URL - &amp;nbsp;localhost:8080&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;793&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lKzZd/btrValpnu5p/gR4Eo8ecXPjmreErJUB9Wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lKzZd/btrValpnu5p/gR4Eo8ecXPjmreErJUB9Wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lKzZd/btrValpnu5p/gR4Eo8ecXPjmreErJUB9Wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlKzZd%2FbtrValpnu5p%2FgR4Eo8ecXPjmreErJUB9Wk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;515&quot; height=&quot;262&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;793&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;Controller&amp;nbsp;이용해서 간단한 동작하는 페이지 만들어 보기&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;Src/main/java/hello.hellospring&amp;nbsp;경로에&amp;nbsp;controller&amp;nbsp;폴더와 그 안에&amp;nbsp;HelloController&amp;nbsp;컨트롤러 파일 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wP8Xs/btrVhSFZzFy/wH5qTwKKj7IpckXq8T62e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wP8Xs/btrVhSFZzFy/wH5qTwKKj7IpckXq8T62e1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wP8Xs/btrVhSFZzFy/wH5qTwKKj7IpckXq8T62e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwP8Xs%2FbtrVhSFZzFy%2FwH5qTwKKj7IpckXq8T62e1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;315&quot; height=&quot;304&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;HelloController.java&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package hello.hellospring.controller;



import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {

&amp;nbsp;&amp;nbsp;&amp;nbsp; @GetMapping(&quot;hello&quot;)

&amp;nbsp;&amp;nbsp;&amp;nbsp; public String hello(Model model){
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; model.addAttribute(&quot;data&quot;,&quot;hello&quot;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return &quot;hello&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #456771;&quot;&gt;Src/main/resources/templates&amp;nbsp;경로에&amp;nbsp;hello.html&amp;nbsp;만들기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p0s3t/btrVcMAcwZf/f0knn0GG9GYjn8K5MZAv3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p0s3t/btrVcMAcwZf/f0knn0GG9GYjn8K5MZAv3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p0s3t/btrVcMAcwZf/f0knn0GG9GYjn8K5MZAv3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp0s3t%2FbtrVcMAcwZf%2Ff0knn0GG9GYjn8K5MZAv3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;349&quot; height=&quot;137&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;hello.html&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;
&amp;lt;head&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;meta name=&quot;viewport&quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; content=&quot;width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html&quot; charset=&quot;UTF-8&quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
	    &amp;lt;p th:text=&quot;'안녕하세요. ' + ${data}&quot;&amp;gt;안녕하세요 손님&amp;lt;/p&amp;gt;
    &amp;lt;/body&amp;gt;	
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;localhost:8080/hello&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1573&quot; data-origin-height=&quot;795&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czOB1D/btrVfkQxKZw/hfIT3djk1fW0bHFkjSXLOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czOB1D/btrVfkQxKZw/hfIT3djk1fW0bHFkjSXLOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czOB1D/btrVfkQxKZw/hfIT3djk1fW0bHFkjSXLOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczOB1D%2FbtrVfkQxKZw%2FhfIT3djk1fW0bHFkjSXLOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;451&quot; height=&quot;228&quot; data-origin-width=&quot;1573&quot; data-origin-height=&quot;795&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #456771;&quot;&gt;&lt;b&gt;감사합니다...!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Java Spring</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/69</guid>
      <comments>https://8156217.tistory.com/69#entry69comment</comments>
      <pubDate>Tue, 3 Jan 2023 14:44:00 +0900</pubDate>
    </item>
    <item>
      <title>[Spring-Boot] Spring-boot 프로젝트 생성 / 빌드 / 실행</title>
      <link>https://8156217.tistory.com/68</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qxFWE/btrVgji47sE/Ilc09gvCuO8V24yDnOCkeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qxFWE/btrVgji47sE/Ilc09gvCuO8V24yDnOCkeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qxFWE/btrVgji47sE/Ilc09gvCuO8V24yDnOCkeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqxFWE%2FbtrVgji47sE%2FIlc09gvCuO8V24yDnOCkeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;315&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;오늘은 스프링 부트(Spring Boot) 프로젝트를 만드는 법에 대해서 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;스프링 부트(Spring Boot)&lt;span style=&quot;background-color: #ffffff;&quot;&gt;는&amp;nbsp;&lt;/span&gt;스프링(Spring)을 더 쉽게 이용할 수 있게 도와주는 툴입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1b711d;&quot;&gt;스프링은 세팅해야 할 것들이 정말 많습니다. 그래서 초보개발자 분들은 스프링 사용에 어려움을 많이 겪습니다. 스프링 부트는 매우 간단하게 프로젝트를 설정할 수 있게 도와줍니다. 이를 통해 Spring 개발을 더 원활하고 쉽게 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #1b711d;&quot;&gt;사전 개발 환경 세팅&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Required&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #1b711d;&quot;&gt;1) JAVA 11&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #1b711d;&quot;&gt;2) IntelliJ Idea&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;프로젝트 만들기&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;스프링 부트 스타터 사이트&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;이곳에서 스프링 프로젝트를 생성할 수 있습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;a style=&quot;color: #1b711d;&quot; href=&quot;https://start.spring.io&quot;&gt;https://start.spring.io&lt;/a&gt;&amp;nbsp; &amp;nbsp;&amp;lt;- 링크&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-03 오후 1.57.46.png&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUX0At/btrVcNMvg9T/y8VtCV9FVAO1UavkrFwFFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUX0At/btrVcNMvg9T/y8VtCV9FVAO1UavkrFwFFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUX0At/btrVcNMvg9T/y8VtCV9FVAO1UavkrFwFFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUX0At%2FbtrVcNMvg9T%2Fy8VtCV9FVAO1UavkrFwFFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;620&quot; height=&quot;403&quot; data-filename=&quot;스크린샷 2023-01-03 오후 1.57.46.png&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1) Gradle Project&amp;nbsp;선택&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;필요한 라이브러리들을 모두 땡겨 오고&amp;nbsp;build하는 싸이클을 관리해 주는 툴&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Gradle로 많이 넘어가는 추세&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2) Java language&amp;nbsp;선택&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;자바를 사용할 것이기에 자바를 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;3) Spring Boot 2.3.x&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;SNAPSHOT은 아직 만들고 있는 버전이라는 뜻&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;M1는 정식&amp;nbsp;released&amp;nbsp;된 것이 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;그러므로 그 외의 것들 중 가장 버전이 높은 것 선택&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;4) Project Metadata&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Group :&amp;nbsp;회사명&amp;nbsp;(&amp;nbsp;없으면 아무거나&amp;nbsp;.&amp;nbsp;저는&amp;nbsp;Hello&amp;nbsp;라고 했습니다.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Artifact :&amp;nbsp;프로젝트 명&amp;nbsp;(저는&amp;nbsp;HelloSpring이라고 했습니다.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Name : Artifact와 동일&amp;nbsp;(저는&amp;nbsp;HelloSpring이라고 했습니다.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Description :&amp;nbsp;유지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Package name :&amp;nbsp;자동 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Packaging : Jar&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Java : 11&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;War jar&amp;nbsp;이란?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;JAVA&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;의&amp;nbsp;jar&amp;nbsp;툴을 이용하여 생성된 압축(아카이브)&amp;nbsp;파일이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;어플리케이션을 쉽게 배포하고&amp;nbsp;동작시킬&amp;nbsp;수 있도록 있도록 관련 파일들을 패키징해주는 역할을 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;JAR(Java Archive)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Java&amp;nbsp;프로젝트를 압축한 파일&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JRE( JAVA Runtime Environment)&amp;nbsp;만 있어도 실행 가능하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;War (Web Application Archive)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;웹 어플리케이션 압축파일 포맷&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;별도의 웹서버(WEB) or&amp;nbsp;웹컨테이너(WAS)&amp;nbsp;필요&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;War는 외장&amp;nbsp;WAS를 사용해야 하기 때문에 우리는&amp;nbsp;War말고&amp;nbsp;Jar를 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;왜냐하면 스프링 부트에는&amp;nbsp;WAS&amp;nbsp;톰캣이 내장되어 있어 있기 때문에 외장&amp;nbsp;WAS를 사용하지 않는 것이 표준이기 때문이다.&amp;nbsp;즉&amp;nbsp;,&amp;nbsp;스프링 부트는&amp;nbsp;Jar로 더 편리하게 배포하고 동작할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;5) Dependencies&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Spring Web&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;Thymeleaf ( html&amp;nbsp;템플릿 엔진&amp;nbsp;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;6) Generate&amp;nbsp;버튼 누르고 다운로드&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;다운로드 한 것을 원하는 경로에 둔다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #1b711d;&quot;&gt;&lt;b&gt;Intellij 에서 빌드 및 실행&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;1) 빌드 및 열기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;먼저 Intellij 를 연다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rDBax/btrVfts08QI/kmPSAY9X1NJBSQjKZUyhlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rDBax/btrVfts08QI/kmPSAY9X1NJBSQjKZUyhlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rDBax/btrVfts08QI/kmPSAY9X1NJBSQjKZUyhlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrDBax%2FbtrVfts08QI%2FkmPSAY9X1NJBSQjKZUyhlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;627&quot; height=&quot;538&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;open or import를 누른다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D5TAX/btrVjSeiquk/KKyav7MKyXdhpG5jvusD3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D5TAX/btrVjSeiquk/KKyav7MKyXdhpG5jvusD3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D5TAX/btrVjSeiquk/KKyav7MKyXdhpG5jvusD3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD5TAX%2FbtrVjSeiquk%2FKKyav7MKyXdhpG5jvusD3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;504&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;아까 다운로드 받은 프로젝트안에 build.gradle을 연다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;무슨 창이 뜨는데 open as project를 누른다..!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;빌드 완료&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wn031/btrVf65s2PH/4Op10elZLHLChmbDLxWRM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wn031/btrVf65s2PH/4Op10elZLHLChmbDLxWRM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wn031/btrVf65s2PH/4Op10elZLHLChmbDLxWRM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWn031%2FbtrVf65s2PH%2F4Op10elZLHLChmbDLxWRM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;588&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;2) 실행&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;HelloSpringApplication의 main에서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXSZX9/btrVgjDIdZP/tkXwLabNLzJLlRAVD8kpqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXSZX9/btrVgjDIdZP/tkXwLabNLzJLlRAVD8kpqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXSZX9/btrVgjDIdZP/tkXwLabNLzJLlRAVD8kpqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXSZX9%2FbtrVgjDIdZP%2FtkXwLabNLzJLlRAVD8kpqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;692&quot; height=&quot;44&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;왼쪽에 초록색 화살표 누르시고 실행 누르시면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1379&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kXTVw/btrVexbFd9w/uJatbgVfJA5o1YmbuymZCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kXTVw/btrVexbFd9w/uJatbgVfJA5o1YmbuymZCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kXTVw/btrVexbFd9w/uJatbgVfJA5o1YmbuymZCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkXTVw%2FbtrVexbFd9w%2FuJatbgVfJA5o1YmbuymZCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;568&quot; height=&quot;98&quot; data-origin-width=&quot;1379&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;빌드가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;크롬 키시고&amp;nbsp;localhost:8080&amp;nbsp;입력하시면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kk4yu/btrVgiLAK4m/VRgp2WOJ3BO7fz8zAZ9ii0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kk4yu/btrVgiLAK4m/VRgp2WOJ3BO7fz8zAZ9ii0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kk4yu/btrVgiLAK4m/VRgp2WOJ3BO7fz8zAZ9ii0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKk4yu%2FbtrVgiLAK4m%2FVRgp2WOJ3BO7fz8zAZ9ii0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;451&quot; height=&quot;517&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;이 화면 뜨면 성공 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;3) gradle&amp;nbsp;설정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;상단에&amp;nbsp;intellij IDEA &amp;ndash; Preferences&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o0OzW/btrVfkiC6IF/0CXtSPn7lSvCjzRictCis0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o0OzW/btrVfkiC6IF/0CXtSPn7lSvCjzRictCis0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o0OzW/btrVfkiC6IF/0CXtSPn7lSvCjzRictCis0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo0OzW%2FbtrVfkiC6IF%2F0CXtSPn7lSvCjzRictCis0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;391&quot; height=&quot;348&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;gradle&amp;nbsp;검색&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HoaRp/btrVjRTZVjY/BDiSFlfKBlXi6y9DOoSKT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HoaRp/btrVjRTZVjY/BDiSFlfKBlXi6y9DOoSKT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HoaRp/btrVjRTZVjY/BDiSFlfKBlXi6y9DOoSKT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHoaRp%2FbtrVjRTZVjY%2FBDiSFlfKBlXi6y9DOoSKT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;746&quot; height=&quot;536&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;빌드 및 실행&amp;nbsp;둘 다&amp;nbsp;intellij idea&amp;nbsp;로 변경하고 확인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;654&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XGnH4/btrVaSm4078/zBBvhLGINx2oXRIKxzXfIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XGnH4/btrVaSm4078/zBBvhLGINx2oXRIKxzXfIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XGnH4/btrVaSm4078/zBBvhLGINx2oXRIKxzXfIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXGnH4%2FbtrVaSm4078%2FzBBvhLGINx2oXRIKxzXfIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;625&quot; height=&quot;452&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvygdS/btrVgirgwDO/EfCUwcUKaDNyJvD8dBVvq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvygdS/btrVgirgwDO/EfCUwcUKaDNyJvD8dBVvq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvygdS/btrVgirgwDO/EfCUwcUKaDNyJvD8dBVvq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvygdS%2FbtrVgirgwDO%2FEfCUwcUKaDNyJvD8dBVvq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;346&quot; height=&quot;262&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;이 설정을 해주는 이유는&amp;nbsp;gradle을 통해서 자바를 실행 시키는 대신&amp;nbsp;intellij에서 바로 자바를 실행 시키게 해주어서 속도가 훨씬 빨라지게 하기 위함입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;&lt;span style=&quot;caret-color: #1b711d;&quot;&gt;감사합니다..!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java Spring</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/68</guid>
      <comments>https://8156217.tistory.com/68#entry68comment</comments>
      <pubDate>Tue, 3 Jan 2023 13:59:00 +0900</pubDate>
    </item>
    <item>
      <title>[JS] 자바스크립트 querySelector 함수 사용법 및 예제</title>
      <link>https://8156217.tistory.com/67</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cP00es/btrU7HSRFFk/ZAykQ3nRzcChTa5gsqkIbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cP00es/btrU7HSRFFk/ZAykQ3nRzcChTa5gsqkIbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cP00es/btrU7HSRFFk/ZAykQ3nRzcChTa5gsqkIbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcP00es%2FbtrU7HSRFFk%2FZAykQ3nRzcChTa5gsqkIbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;오늘은 자바스크립트를 통해 html 태그를 다룰 수 있게 도와주는 함수인 querySelector 함수에 대해서 알아볼 것입니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;querySelector는 getElementby~ 함수들과 비슷합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;하지만 id , class , 복합 태그 모두 가져올 수 있기 때문에 더 강력합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;querySelector()&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;괄호 속에 제공한 선택자와 일치하는 문서 내 &lt;b&gt;첫 번째 Element를 반환&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;일치하는 요소가 없다면 &lt;b&gt;null 반환&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;사용 예시&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672640408387&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// javascript

const selected = document.querySelector(&quot;h1&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;문서 내의 첫 번째 h1 태그를 찾아 selected에 반환해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;사용 방법 4가지&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;1) 태그 select&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;2) 클래스 select&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;3) id select&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;4) 복합 select&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;이렇게 4 가지에 대해서 알아 볼텐데&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;아래 html을 예제로 함께 확인 해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672640324028&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// html

&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;h1&amp;lt;/h1&amp;gt;
    &amp;lt;h2 class=&quot;h2&quot;&amp;gt;h2&amp;lt;/h2&amp;gt;
    &amp;lt;h3 id=&quot;h3&quot;&amp;gt;h3&amp;lt;/h3&amp;gt;
    &amp;lt;h3&amp;gt;h3_2&amp;lt;/h3&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;span&amp;gt;Span1&amp;lt;/span&amp;gt;
        &amp;lt;span&amp;gt;Span2&amp;lt;/span&amp;gt;
    &amp;lt;/div&amp;gt;
    
    &amp;lt;script src=&quot;app.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.27.32.png&quot; data-origin-width=&quot;261&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tfX6B/btrVeyAAfbP/4xDSHuwpak4diGLrcaTDW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tfX6B/btrVeyAAfbP/4xDSHuwpak4diGLrcaTDW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tfX6B/btrVeyAAfbP/4xDSHuwpak4diGLrcaTDW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtfX6B%2FbtrVeyAAfbP%2F4xDSHuwpak4diGLrcaTDW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;261&quot; height=&quot;216&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.27.32.png&quot; data-origin-width=&quot;261&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;1) 태그 select&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;괄호 속에 &lt;b&gt;태그이름&lt;/b&gt;을 쓰면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672640987920&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// javascript

const selected = document.querySelector(&quot;h1&quot;);
selected.style.color = &quot;red&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.29.53.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YCX4M/btrVaTSOEnY/mJO3YwvhDECrKq4zET8pAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YCX4M/btrVaTSOEnY/mJO3YwvhDECrKq4zET8pAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YCX4M/btrVaTSOEnY/mJO3YwvhDECrKq4zET8pAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYCX4M%2FbtrVaTSOEnY%2FmJO3YwvhDECrKq4zET8pAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;270&quot; height=&quot;235&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.29.53.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;2) 클래스 select&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;괄호 속에 &lt;b&gt;.클래스이름&lt;/b&gt;을 쓰면된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672641096802&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// javascript

const selected = document.querySelector(&quot;.h2&quot;);
selected.style.color = &quot;red&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.31.42.png&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHTYpn/btrU2LodF7R/zjsdGgPgLh9sSlu84xuRv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHTYpn/btrU2LodF7R/zjsdGgPgLh9sSlu84xuRv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHTYpn/btrU2LodF7R/zjsdGgPgLh9sSlu84xuRv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHTYpn%2FbtrU2LodF7R%2FzjsdGgPgLh9sSlu84xuRv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;271&quot; height=&quot;224&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.31.42.png&quot; data-origin-width=&quot;271&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;3) id select&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;괄호 속에&lt;b&gt; #id이름&lt;/b&gt;을 쓰면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672641190732&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// javascript

const selected = document.querySelector(&quot;#h3&quot;);
selected.style.color = &quot;red&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.33.22.png&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd5DRK/btrVcNksQBz/S41N0zJh7vu4LD4BZrOP3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd5DRK/btrVcNksQBz/S41N0zJh7vu4LD4BZrOP3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd5DRK/btrVcNksQBz/S41N0zJh7vu4LD4BZrOP3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd5DRK%2FbtrVcNksQBz%2FS41N0zJh7vu4LD4BZrOP3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;292&quot; height=&quot;230&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.33.22.png&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;4) 복합 select&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;괄호 속에 &lt;b&gt;복합태그이름&lt;/b&gt;을 쓰면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672641248237&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const selected = document.querySelector(&quot;div span&quot;);
selected.style.color = &quot;red&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.34.15.png&quot; data-origin-width=&quot;247&quot; data-origin-height=&quot;229&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDy57s/btrVfkPqVzk/qvazgU05nCE0YSc63NpD11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDy57s/btrVfkPqVzk/qvazgU05nCE0YSc63NpD11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDy57s/btrVfkPqVzk/qvazgU05nCE0YSc63NpD11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDy57s%2FbtrVfkPqVzk%2FqvazgU05nCE0YSc63NpD11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;247&quot; height=&quot;229&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.34.15.png&quot; data-origin-width=&quot;247&quot; data-origin-height=&quot;229&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;보는 것처럼 잘 작동한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;다만 앞에서 말했 듯이 첫 번째 element만 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;뒤쪽 span에 접근하려면 어떻게 해야 할까??&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;4-2) nth-child&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;이렇게 한 태그 안에 여러 개의 태그들이 들어 있을 때는 &lt;b&gt;first-child , last-child , nth-child&lt;/b&gt;를 이용하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;first-child&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672641490920&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//javascript

const selected = document.querySelector(&quot;div span:first-child&quot;);
selected.style.color = &quot;red&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.38.20.png&quot; data-origin-width=&quot;286&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5ETeg/btrU55l9DSo/kAx616K1WA4rPqUltoKkok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5ETeg/btrU55l9DSo/kAx616K1WA4rPqUltoKkok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5ETeg/btrU55l9DSo/kAx616K1WA4rPqUltoKkok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5ETeg%2FbtrU55l9DSo%2FkAx616K1WA4rPqUltoKkok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;286&quot; height=&quot;245&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.38.20.png&quot; data-origin-width=&quot;286&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;nth-child() , last-child&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672641520202&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//javascript

//const selected = document.querySelector(&quot;div span:last-child&quot;); 마지막 child 선택
const selected = document.querySelector(&quot;div span:nth-child(2)&quot;);
selected.style.color = &quot;red&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.38.53.png&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7wstT/btrU2KJB6YE/C4midtsgx9cSqQSjkDh2ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7wstT/btrU2KJB6YE/C4midtsgx9cSqQSjkDh2ik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7wstT/btrU2KJB6YE/C4midtsgx9cSqQSjkDh2ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7wstT%2FbtrU2KJB6YE%2FC4midtsgx9cSqQSjkDh2ik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;264&quot; height=&quot;219&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.38.53.png&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;감사합니다..!&lt;/span&gt;&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/67</guid>
      <comments>https://8156217.tistory.com/67#entry67comment</comments>
      <pubDate>Mon, 2 Jan 2023 15:45:32 +0900</pubDate>
    </item>
    <item>
      <title>[CSS] css 선택자 (selector) 정리</title>
      <link>https://8156217.tistory.com/66</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1693&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bk1lZ/btrVecRN0ZX/QK0km4WDUA5cPbbfs4pFJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bk1lZ/btrVecRN0ZX/QK0km4WDUA5cPbbfs4pFJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bk1lZ/btrVecRN0ZX/QK0km4WDUA5cPbbfs4pFJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBk1lZ%2FbtrVecRN0ZX%2FQK0km4WDUA5cPbbfs4pFJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;206&quot; height=&quot;291&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1693&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;Css는 html에 스타일을 주기 위해서 사용 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;특정 html 태그에 원하는 스타일을 주기 위해서는 &lt;b&gt;css 선택자&lt;/b&gt;를 이용 하여야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;CSS 선택자 (Selector)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1672637940445&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;h1{
	color : blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;이 코드를 보시면 h1 태그에 글자색을 파란색으로 바꾸라는 css 문법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;h1이 바로 css 선택자입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;글자 색상을 바꾼 것처럼 스타일을 줄 건데 &lt;b&gt;어떤 태그&lt;/b&gt;에 적용 해야 하는 지를 알려 주는 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Selector 종류&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1) 전체 선택자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2) 태그 선택자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;3) 클래스 선택자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;4) id 선택자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;5) 복합 선택자&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;이 html을 예시로 보여드리겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672638705705&quot; class=&quot;angelscript&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;
    &amp;lt;h2 class=&quot;h2&quot;&amp;gt;Hello&amp;lt;/h2&amp;gt;
    &amp;lt;h3 id=&quot;h3&quot;&amp;gt;Hello&amp;lt;/h3&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;h3&amp;gt;Hello&amp;lt;/h3&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.52.12.png&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GL7EE/btrVclBxlHG/s6EjBfD08rGAGpywA0WTK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GL7EE/btrVclBxlHG/s6EjBfD08rGAGpywA0WTK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GL7EE/btrVclBxlHG/s6EjBfD08rGAGpywA0WTK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGL7EE%2FbtrVclBxlHG%2Fs6EjBfD08rGAGpywA0WTK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;556&quot; height=&quot;285&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.52.12.png&quot; data-origin-width=&quot;1040&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1) 전체 선택자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;표기 : &amp;nbsp;* { }&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;모든 태그에 css를 적용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672638569071&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;*{
	color : blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.53.28.png&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0cmso/btrVeWOLaUg/y4bnKyaa889YxY1NtVNAMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0cmso/btrVeWOLaUg/y4bnKyaa889YxY1NtVNAMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0cmso/btrVeWOLaUg/y4bnKyaa889YxY1NtVNAMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0cmso%2FbtrVeWOLaUg%2Fy4bnKyaa889YxY1NtVNAMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;485&quot; height=&quot;504&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.53.28.png&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2) 태그 선택자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;표기 : 태그이름{ }&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;해당 태그에 해당하는 모든 태그에 css를 적용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672638672659&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;h1{
	color:blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.54.00.png&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m0CeM/btrVaR1GLKL/FJ3cXyVfTkjHpRRFEHGzXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m0CeM/btrVaR1GLKL/FJ3cXyVfTkjHpRRFEHGzXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m0CeM/btrVaR1GLKL/FJ3cXyVfTkjHpRRFEHGzXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm0CeM%2FbtrVaR1GLKL%2FFJ3cXyVfTkjHpRRFEHGzXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;488&quot; height=&quot;538&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.54.00.png&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;3) 클래스 선택자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;표기 : .클래스이름{ }&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;해당 클래스에 속하는 모든 태그에 css를 적용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672638983360&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.h2{
    color: blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.56.56.png&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HRGEt/btrVfj31kc6/JgTNMJUKxG2jGSQOe8BXAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HRGEt/btrVfj31kc6/JgTNMJUKxG2jGSQOe8BXAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HRGEt/btrVfj31kc6/JgTNMJUKxG2jGSQOe8BXAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHRGEt%2FbtrVfj31kc6%2FJgTNMJUKxG2jGSQOe8BXAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;345&quot; height=&quot;207&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.56.56.png&quot; data-origin-width=&quot;345&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;4) id 선택자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;표기 : #id이름{ }&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;해당 id를 가진 모든 태그에 css를 적용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672639092413&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#h3{
    color: blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.59.32.png&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZS2ff/btrVebMa4DZ/jcI92lt2eiTr8UAKXeXL0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZS2ff/btrVebMa4DZ/jcI92lt2eiTr8UAKXeXL0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZS2ff/btrVebMa4DZ/jcI92lt2eiTr8UAKXeXL0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZS2ff%2FbtrVebMa4DZ%2FjcI92lt2eiTr8UAKXeXL0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;315&quot; height=&quot;203&quot; data-filename=&quot;스크린샷 2023-01-02 오후 2.59.32.png&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;5) 복합 선택자&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;표기 :&lt;/b&gt; &lt;b&gt;바깥쪽태그이름 안쪽 태그이름{ }&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;태그 속의 태그를 선택할 때 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672639261110&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;div h3{
    color: blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.01.05.png&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvL9pX/btrVamgoUf1/kmXNgJGBj83iWTP4zHqSe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvL9pX/btrVamgoUf1/kmXNgJGBj83iWTP4zHqSe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvL9pX/btrVamgoUf1/kmXNgJGBj83iWTP4zHqSe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvL9pX%2FbtrVamgoUf1%2FkmXNgJGBj83iWTP4zHqSe1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;341&quot; height=&quot;208&quot; data-filename=&quot;스크린샷 2023-01-02 오후 3.01.05.png&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;! div 속 h3를 선택하였기에 3번째 hello는 선택 되지 않았습니다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;감사합니다..!&lt;/span&gt;&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/66</guid>
      <comments>https://8156217.tistory.com/66#entry66comment</comments>
      <pubDate>Mon, 2 Jan 2023 15:03:58 +0900</pubDate>
    </item>
    <item>
      <title>[HTML] &amp;lt;a&amp;gt; 태그 사용법</title>
      <link>https://8156217.tistory.com/65</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo53X4/btrUV93dxYC/AtxeCIIvFdlAvUM29AVJVK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo53X4/btrUV93dxYC/AtxeCIIvFdlAvUM29AVJVK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo53X4/btrUV93dxYC/AtxeCIIvFdlAvUM29AVJVK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo53X4%2FbtrUV93dxYC%2FAtxeCIIvFdlAvUM29AVJVK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;280&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;오늘은 html에서 많이 사용되는 태그 중 하나인 &amp;lt;a&amp;gt; 태그에 대해서 알아보려고 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span&gt;&lt;b&gt;href&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;하이퍼링크 기능&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) 절대 경로&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672418740000&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;a href=&quot;http://www.naver.com&quot;&amp;gt;A태그&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOSaUd/btrU1qCWc8p/dJesKpXwaWBdatqWoqVTI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOSaUd/btrU1qCWc8p/dJesKpXwaWBdatqWoqVTI0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;346&quot; data-filename=&quot;스크린샷 2022-12-31 오전 1.48.30.png&quot; width=&quot;467&quot; height=&quot;204&quot; style=&quot;width: 58.0464%; margin-right: 10px;&quot; data-widthpercent=&quot;58.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOSaUd/btrU1qCWc8p/dJesKpXwaWBdatqWoqVTI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOSaUd%2FbtrU1qCWc8p%2FdJesKpXwaWBdatqWoqVTI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;792&quot; height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMRiHn/btrU1M6Wf8F/tKZVwM2rRAOR9SJMUuXKUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMRiHn/btrU1M6Wf8F/tKZVwM2rRAOR9SJMUuXKUK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2030&quot; data-origin-height=&quot;1262&quot; data-filename=&quot;스크린샷 2022-12-31 오전 1.48.48.png&quot; width=&quot;481&quot; height=&quot;299&quot; style=&quot;width: 40.7908%;&quot; data-widthpercent=&quot;41.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMRiHn/btrU1M6Wf8F/tKZVwM2rRAOR9SJMUuXKUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMRiHn%2FbtrU1M6Wf8F%2FtKZVwM2rRAOR9SJMUuXKUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2030&quot; height=&quot;1262&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왼쪽의 A태그를 클릭하면 href에 적혀있는 주소로 이동..!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2) 상대 경로&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672419341220&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;a href=&quot;index.html&quot;&amp;gt;A태그&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-31 오전 1.52.49.png&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bY812p/btrUYqXUAd9/4WlgyX8ETmWUGKN0I6dQx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bY812p/btrUYqXUAd9/4WlgyX8ETmWUGKN0I6dQx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bY812p/btrUYqXUAd9/4WlgyX8ETmWUGKN0I6dQx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbY812p%2FbtrUYqXUAd9%2F4WlgyX8ETmWUGKN0I6dQx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;118&quot; data-filename=&quot;스크린샷 2022-12-31 오전 1.52.49.png&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;118&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 폴더 안에 있는 index.html로 이동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cN6d6A/btrUV3PI9YX/c8jAPGmQcOepX6GviOttZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cN6d6A/btrUV3PI9YX/c8jAPGmQcOepX6GviOttZ1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2924&quot; data-origin-height=&quot;1704&quot; data-filename=&quot;스크린샷 2022-12-31 오전 1.55.00.png&quot; style=&quot;width: 49.5174%; margin-right: 10px;&quot; data-widthpercent=&quot;50.1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cN6d6A/btrUV3PI9YX/c8jAPGmQcOepX6GviOttZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcN6d6A%2FbtrUV3PI9YX%2Fc8jAPGmQcOepX6GviOttZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2924&quot; height=&quot;1704&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bixBwQ/btrU1NkvoqT/YDuzmFz8AfjDmyXm2tRKWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bixBwQ/btrU1NkvoqT/YDuzmFz8AfjDmyXm2tRKWK/img.png&quot; data-origin-width=&quot;2926&quot; data-origin-height=&quot;1712&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.9&quot; style=&quot;width: 49.3198%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bixBwQ/btrU1NkvoqT/YDuzmFz8AfjDmyXm2tRKWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbixBwQ%2FbtrU1NkvoqT%2FYDuzmFz8AfjDmyXm2tRKWK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2926&quot; height=&quot;1712&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;a.html -&amp;gt; index.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 자바스크립트 호출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672419457564&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;a href=&amp;rdquo;javascript:alert(&amp;lsquo;Hello&amp;rsquo;);&amp;rdquo;&amp;gt;A태그&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2934&quot; data-origin-height=&quot;1700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pCkka/btrUTYgPqHM/IPvgsMC8Q0xaN7WZ8bkRTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pCkka/btrUTYgPqHM/IPvgsMC8Q0xaN7WZ8bkRTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pCkka/btrUTYgPqHM/IPvgsMC8Q0xaN7WZ8bkRTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpCkka%2FbtrUTYgPqHM%2FIPvgsMC8Q0xaN7WZ8bkRTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;672&quot; height=&quot;389&quot; data-origin-width=&quot;2934&quot; data-origin-height=&quot;1700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/65</guid>
      <comments>https://8156217.tistory.com/65#entry65comment</comments>
      <pubDate>Sat, 31 Dec 2022 02:01:57 +0900</pubDate>
    </item>
    <item>
      <title>[ 개발 환경 ] 웹서버에 파일 업로드 하기 (FileZila , Vscode)</title>
      <link>https://8156217.tistory.com/64</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chpwWE/btrUTKwbT0q/mfRhlah79DAiazMkRtBe71/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chpwWE/btrUTKwbT0q/mfRhlah79DAiazMkRtBe71/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chpwWE/btrUTKwbT0q/mfRhlah79DAiazMkRtBe71/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchpwWE%2FbtrUTKwbT0q%2FmfRhlah79DAiazMkRtBe71%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;373&quot; height=&quot;379&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;오늘은 웹서버에 파일을 업로드 하는 방법에 대해서 알아 보겠습니다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;1. 파일 질라 ( File Zila )&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beZHzj/btrU02B3Pml/qQesrABRyBClCGHrMMQt6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beZHzj/btrU02B3Pml/qQesrABRyBClCGHrMMQt6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beZHzj/btrU02B3Pml/qQesrABRyBClCGHrMMQt6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeZHzj%2FbtrU02B3Pml%2FqQesrABRyBClCGHrMMQt6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;서버에&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;파일을 업/다운로드 할 수 있게 해주는 프리웨어 (무료) 프로그램&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&amp;nbsp;1) 파일 질라 홈페이지 이동 및 다운로드&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;URL :&lt;/b&gt; &lt;a href=&quot;https://filezilla-project.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://filezilla-project.org/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 8.56.49.png&quot; data-origin-width=&quot;2938&quot; data-origin-height=&quot;1202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNTMlv/btrUZXnvmW1/U6cKTjYzbqtHoskTCmJwW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNTMlv/btrUZXnvmW1/U6cKTjYzbqtHoskTCmJwW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNTMlv/btrUZXnvmW1/U6cKTjYzbqtHoskTCmJwW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNTMlv%2FbtrUZXnvmW1%2FU6cKTjYzbqtHoskTCmJwW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;665&quot; height=&quot;1202&quot; data-filename=&quot;스크린샷 2022-12-30 오후 8.56.49.png&quot; data-origin-width=&quot;2938&quot; data-origin-height=&quot;1202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왼쪽의 클라이언트 클릭!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 8.57.50.png&quot; data-origin-width=&quot;2892&quot; data-origin-height=&quot;1110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ITnkW/btrUYqcp4OG/p58eVrhscaXbk93dzsdJbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ITnkW/btrUYqcp4OG/p58eVrhscaXbk93dzsdJbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ITnkW/btrUYqcp4OG/p58eVrhscaXbk93dzsdJbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FITnkW%2FbtrUYqcp4OG%2Fp58eVrhscaXbk93dzsdJbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;654&quot; height=&quot;1110&quot; data-filename=&quot;스크린샷 2022-12-30 오후 8.57.50.png&quot; data-origin-width=&quot;2892&quot; data-origin-height=&quot;1110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자신의 운영 체제에 맞게 선택하여 다운로드 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 8.59.44.png&quot; data-origin-width=&quot;2648&quot; data-origin-height=&quot;1514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Og2b0/btrU15SI94g/KKBua4CabwLnt9vRRDrIB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Og2b0/btrU15SI94g/KKBua4CabwLnt9vRRDrIB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Og2b0/btrU15SI94g/KKBua4CabwLnt9vRRDrIB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOg2b0%2FbtrU15SI94g%2FKKBua4CabwLnt9vRRDrIB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;689&quot; height=&quot;1514&quot; data-filename=&quot;스크린샷 2022-12-30 오후 8.59.44.png&quot; data-origin-width=&quot;2648&quot; data-origin-height=&quot;1514&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하단을 보시면 파일이 다운로드 된 것을 확인할 수 있습니다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클릭 후 다운로드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GMsxH/btrUZYUdIyJ/nwbwW8oemQ6vOi07XaI1s0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GMsxH/btrUZYUdIyJ/nwbwW8oemQ6vOi07XaI1s0/img.png&quot; data-alt=&quot;실행 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GMsxH/btrUZYUdIyJ/nwbwW8oemQ6vOi07XaI1s0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGMsxH%2FbtrUZYUdIyJ%2FnwbwW8oemQ6vOi07XaI1s0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;769&quot; height=&quot;1912&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실행 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다운 완료!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2) 파일 질라 실행 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 9.02.45.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bddWuI/btrUSAmVp80/tmDMQ0cBVJa1aRzDVSQQP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bddWuI/btrUSAmVp80/tmDMQ0cBVJa1aRzDVSQQP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bddWuI/btrUSAmVp80/tmDMQ0cBVJa1aRzDVSQQP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbddWuI%2FbtrUSAmVp80%2FtmDMQ0cBVJa1aRzDVSQQP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;790&quot; height=&quot;260&quot; data-filename=&quot;스크린샷 2022-12-30 오후 9.02.45.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;위쪽 화면을 보시면 호스트 , 사용자명 , 비밀번호 , 포트 그리고 빠른 연결 버튼이 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각각 입력해주시면 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;호스트&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 접속할 곳의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;아이피 혹은 주소&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;예) ohinhyuk13.dothome.co.kr&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;사용자명&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;FTP 아이디 &lt;/span&gt;&lt;span&gt;입력&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;비밀번호&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;FTP 비밀번호&lt;/span&gt;&lt;span&gt;&amp;nbsp;입력&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;포트&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: FTP 접속 시 이용할&lt;/span&gt;&lt;span style=&quot;color: #0075c8;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;포트&lt;/span&gt;&lt;/span&gt;&lt;span&gt;를 입력합니다. 입력하지 않을 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;기본포트(21)&lt;/span&gt;&lt;span&gt;를 통해 연결합니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;* 닷홈 웹호스팅은 기본포트(21)를 이용하여 연결합니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;* sftp 접속 시 22 를 입력하시면 됩니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2920&quot; data-origin-height=&quot;1794&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kAK7k/btrU0vK9Wvo/MHdEIopSpgReihWcZwku60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kAK7k/btrU0vK9Wvo/MHdEIopSpgReihWcZwku60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kAK7k/btrU0vK9Wvo/MHdEIopSpgReihWcZwku60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkAK7k%2FbtrU0vK9Wvo%2FMHdEIopSpgReihWcZwku60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;1794&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2920&quot; data-origin-height=&quot;1794&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;확인&quot; 누르시면 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2918&quot; data-origin-height=&quot;1624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvx8ij/btrU00Yxe2T/niqEma3jSZVmxi9AWeJDok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvx8ij/btrU00Yxe2T/niqEma3jSZVmxi9AWeJDok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvx8ij/btrU00Yxe2T/niqEma3jSZVmxi9AWeJDok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbvx8ij%2FbtrU00Yxe2T%2FniqEma3jSZVmxi9AWeJDok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;788&quot; height=&quot;1624&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2918&quot; data-origin-height=&quot;1624&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nkcJQ/btrUWQ3xAor/6z7oXWMAhgF9vIEyWSE4Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nkcJQ/btrUWQ3xAor/6z7oXWMAhgF9vIEyWSE4Jk/img.png&quot; data-alt=&quot;상태창&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nkcJQ/btrUWQ3xAor/6z7oXWMAhgF9vIEyWSE4Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnkcJQ%2FbtrUWQ3xAor%2F6z7oXWMAhgF9vIEyWSE4Jk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;744&quot; height=&quot;160&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;상태창&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이렇게 뜨시면 연결 성공입니다..!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3) 파일 업로드 하는 법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;업로드 하고자 하는 프로젝트를 리모트의 html 폴더 밑에 넣으시면 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;저는 html 폴더 밑에 momentum 이라는 프로젝트를 집어넣었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.29.05.png&quot; data-origin-width=&quot;1776&quot; data-origin-height=&quot;1440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqmKUt/btrU3bkTvgh/qLObyfcDfyW0ymtBPmIXyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqmKUt/btrU3bkTvgh/qLObyfcDfyW0ymtBPmIXyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqmKUt/btrU3bkTvgh/qLObyfcDfyW0ymtBPmIXyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqmKUt%2FbtrU3bkTvgh%2FqLObyfcDfyW0ymtBPmIXyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1776&quot; height=&quot;1440&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.29.05.png&quot; data-origin-width=&quot;1776&quot; data-origin-height=&quot;1440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;momentum 프로젝트 안에 index파일과 css , js 파일들이 들어있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.30.34.png&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;1124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cawVI8/btrUYPiTcUi/KN3R476w6JsecyFZ4EyUL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cawVI8/btrUYPiTcUi/KN3R476w6JsecyFZ4EyUL1/img.png&quot; data-alt=&quot;html/momentum/index.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cawVI8/btrUYPiTcUi/KN3R476w6JsecyFZ4EyUL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcawVI8%2FbtrUYPiTcUi%2FKN3R476w6JsecyFZ4EyUL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;879&quot; height=&quot;664&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.30.34.png&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;1124&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;html/momentum/index.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이 프로젝트를 보기 위해서는 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;***.dothome.co.kr/momentum 이라고 주소를 입력하시면 업로드 된 프로젝트를 볼 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;( html 경로는 생략 됩니다. )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2916&quot; data-origin-height=&quot;1556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZTKY2/btrU3aM3US6/W6sH0ick2UzhkhxFRsVA9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZTKY2/btrU3aM3US6/W6sH0ick2UzhkhxFRsVA9K/img.png&quot; data-alt=&quot;ohinhyuk13.dothome.co.kr/momentum/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZTKY2/btrU3aM3US6/W6sH0ick2UzhkhxFRsVA9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZTKY2%2FbtrU3aM3US6%2FW6sH0ick2UzhkhxFRsVA9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;1556&quot; data-origin-width=&quot;2916&quot; data-origin-height=&quot;1556&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ohinhyuk13.dothome.co.kr/momentum/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;만약 ***.dothome.co.kr/momentum 이 아니라 ***.dothome.co.kr/ 로 프로젝트를 열고 싶다면 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;file zila 에서 html 폴더에 momentum 폴더를 업로드 하지 않고&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;html 폴더 바로 아래에 momentum 폴더 안에 있는 index.html 과 js , css 파일이 들어가도록 업로드 하시면 됩니다..!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;아래 사진과 함께 보시겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.37.38.png&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;1170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lE3kh/btrU2JB3MkN/uTcmY6nfakiKwpE9YPU9X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lE3kh/btrU2JB3MkN/uTcmY6nfakiKwpE9YPU9X1/img.png&quot; data-alt=&quot;html/index.html&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lE3kh/btrU2JB3MkN/uTcmY6nfakiKwpE9YPU9X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlE3kh%2FbtrU2JB3MkN%2FuTcmY6nfakiKwpE9YPU9X1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;684&quot; height=&quot;532&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.37.38.png&quot; data-origin-width=&quot;1504&quot; data-origin-height=&quot;1170&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;html/index.html&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;html 폴더 밑에 index.html 파일이 들어있는 것이 보입니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2936&quot; data-origin-height=&quot;1634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSYZAp/btrU0vLclOJ/XYQgLzEAb5jl6mbj34ASjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSYZAp/btrU0vLclOJ/XYQgLzEAb5jl6mbj34ASjk/img.png&quot; data-alt=&quot;ohinhyuk13.dothome.co.kr&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSYZAp/btrU0vLclOJ/XYQgLzEAb5jl6mbj34ASjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSYZAp%2FbtrU0vLclOJ%2FXYQgLzEAb5jl6mbj34ASjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2936&quot; height=&quot;1634&quot; data-origin-width=&quot;2936&quot; data-origin-height=&quot;1634&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ohinhyuk13.dothome.co.kr&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ohinhyuk13.dothome.co.kr/ 로 index.html에 접근이 가능해졌습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2. VS Code&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;sftp 확장 프로그램을 통해 웹 서버와 로컬을 연결&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) VS Code 다운로드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://code.visualstudio.com/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://code.visualstudio.com/download&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672402603580&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Download Visual Studio Code - Mac, Linux, Windows&quot; data-og-description=&quot;Visual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows. Download Visual Studio Code to experience a redefined code editor, optimized for building and debugging modern web and cloud applications.&quot; data-og-host=&quot;code.visualstudio.com&quot; data-og-source-url=&quot;https://code.visualstudio.com/download&quot; data-og-url=&quot;https://code.visualstudio.com/Download&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cEk2Gw/hyQ5BnOIBl/c8kwlWBPYoFsKqdw0aNHMK/img.png?width=1012&amp;amp;height=506&amp;amp;face=0_0_1012_506&quot;&gt;&lt;a href=&quot;https://code.visualstudio.com/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://code.visualstudio.com/download&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cEk2Gw/hyQ5BnOIBl/c8kwlWBPYoFsKqdw0aNHMK/img.png?width=1012&amp;amp;height=506&amp;amp;face=0_0_1012_506');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Download Visual Studio Code - Mac, Linux, Windows&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Visual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows. Download Visual Studio Code to experience a redefined code editor, optimized for building and debugging modern web and cloud applications.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;code.visualstudio.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 9.17.07.png&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;1400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7h24X/btrUV9277wN/DtCAyVtM3KhNzbAUsYoboK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7h24X/btrUV9277wN/DtCAyVtM3KhNzbAUsYoboK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7h24X/btrUV9277wN/DtCAyVtM3KhNzbAUsYoboK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7h24X%2FbtrUV9277wN%2FDtCAyVtM3KhNzbAUsYoboK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;1400&quot; data-filename=&quot;스크린샷 2022-12-30 오후 9.17.07.png&quot; data-origin-width=&quot;2478&quot; data-origin-height=&quot;1400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;운영 체제에 맞게 설치하시면 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 9.23.33.png&quot; data-origin-width=&quot;1620&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xdzU4/btrU2LzPJHM/6A1zVonqKF9UDNsKCQvlz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xdzU4/btrU2LzPJHM/6A1zVonqKF9UDNsKCQvlz0/img.png&quot; data-alt=&quot;VS code 실행 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xdzU4/btrU2LzPJHM/6A1zVonqKF9UDNsKCQvlz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxdzU4%2FbtrU2LzPJHM%2F6A1zVonqKF9UDNsKCQvlz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;664&quot; height=&quot;956&quot; data-filename=&quot;스크린샷 2022-12-30 오후 9.23.33.png&quot; data-origin-width=&quot;1620&quot; data-origin-height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;VS code 실행 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다운 완료 후 실행 화면&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2) SFTP 확장 프로그램 설치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1609&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nwMcp/btrUYPQCh1Q/Uju7XVMjFRRowBabDcYIbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nwMcp/btrUYPQCh1Q/Uju7XVMjFRRowBabDcYIbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nwMcp/btrUYPQCh1Q/Uju7XVMjFRRowBabDcYIbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnwMcp%2FbtrUYPQCh1Q%2FUju7XVMjFRRowBabDcYIbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;729&quot; height=&quot;812&quot; data-origin-width=&quot;1609&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;install 누르기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 환경 설정 ( json 파일 만들기 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2202&quot; data-origin-height=&quot;1294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vXkQL/btrUZXnwDi8/Axjax3r9I2fLyV0tCEuZt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vXkQL/btrUZXnwDi8/Axjax3r9I2fLyV0tCEuZt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vXkQL/btrUZXnwDi8/Axjax3r9I2fLyV0tCEuZt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvXkQL%2FbtrUZXnwDi8%2FAxjax3r9I2fLyV0tCEuZt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;678&quot; height=&quot;1294&quot; data-origin-width=&quot;2202&quot; data-origin-height=&quot;1294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;f1 키를 누르고 ( Mac은 fn + f1 ) SFTP: Config 입력 후 엔터를 누르시면 .vscode 라는 폴더와 그 아래 sftp.json 파일이 생깁니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.45.49.png&quot; data-origin-width=&quot;1613&quot; data-origin-height=&quot;977&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3hG27/btrU38uOVT5/roAeUm9hy3AlMzDmAEzCh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3hG27/btrU38uOVT5/roAeUm9hy3AlMzDmAEzCh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3hG27/btrU38uOVT5/roAeUm9hy3AlMzDmAEzCh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3hG27%2FbtrU38uOVT5%2FroAeUm9hy3AlMzDmAEzCh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;841&quot; height=&quot;509&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.45.49.png&quot; data-origin-width=&quot;1613&quot; data-origin-height=&quot;977&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;name : 원하는 이름 입력&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;host : 연결할 대상 (서버) 의 IP 주소&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;protocol : &lt;span style=&quot;color: #006dd7;&quot;&gt;ftp&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;port : &lt;span style=&quot;color: #006dd7;&quot;&gt;21&lt;/span&gt; ( protocol이 sftp 이면 22 )&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;username : 연결할 대상 (서버) 사용자의 이름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;remotePath : 로컬과 연결할 서버의 파일 경로&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;uploadOnSave : True일 경우, 로컬에서 변경 사항을 저장할 때마다 서버 파일에 동기화됨&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리모트 패쓰를 모르겠으면 &lt;span style=&quot;color: #ee2323;&quot;&gt;파일 질라&lt;/span&gt;에서 확인하면 됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.44.21.png&quot; data-origin-width=&quot;1706&quot; data-origin-height=&quot;1402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxt2Z8/btrU1pqpTYY/kmZDChkynFF6ijiksQgtWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxt2Z8/btrU1pqpTYY/kmZDChkynFF6ijiksQgtWk/img.png&quot; data-alt=&quot;index.html의 위치 : /html/momentum&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxt2Z8/btrU1pqpTYY/kmZDChkynFF6ijiksQgtWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxt2Z8%2FbtrU1pqpTYY%2FkmZDChkynFF6ijiksQgtWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;512&quot; height=&quot;421&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.44.21.png&quot; data-origin-width=&quot;1706&quot; data-origin-height=&quot;1402&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;index.html의 위치 : /html/momentum&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파일 질라에서 리모트 패쓰 확인&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다 작성한 뒤 연결을 시도하면 됩니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.48.15.png&quot; data-origin-width=&quot;488&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/efUS4C/btrUYRgGyom/5nbzKWaUKfnD3dwTspzAg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/efUS4C/btrUYRgGyom/5nbzKWaUKfnD3dwTspzAg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/efUS4C/btrUYRgGyom/5nbzKWaUKfnD3dwTspzAg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FefUS4C%2FbtrUYRgGyom%2F5nbzKWaUKfnD3dwTspzAg0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;219&quot; height=&quot;344&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.48.15.png&quot; data-origin-width=&quot;488&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.48.47.png&quot; data-origin-width=&quot;1532&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ldZzy/btrUYQB5a6w/EPftzuiNlXNKDssDzn0O40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ldZzy/btrUYQB5a6w/EPftzuiNlXNKDssDzn0O40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ldZzy/btrUYQB5a6w/EPftzuiNlXNKDssDzn0O40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FldZzy%2FbtrUYQB5a6w%2FEPftzuiNlXNKDssDzn0O40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1532&quot; height=&quot;110&quot; data-filename=&quot;스크린샷 2022-12-30 오후 10.48.47.png&quot; data-origin-width=&quot;1532&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연결 완료&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 11.02.39.png&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;899&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vt6vG/btrUYpLmZDS/Vgb6J1xs06pjB4LxAiFBK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vt6vG/btrUYpLmZDS/Vgb6J1xs06pjB4LxAiFBK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vt6vG/btrUYpLmZDS/Vgb6J1xs06pjB4LxAiFBK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVt6vG%2FbtrUYpLmZDS%2FVgb6J1xs06pjB4LxAiFBK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;155&quot; height=&quot;512&quot; data-filename=&quot;스크린샷 2022-12-30 오후 11.02.39.png&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;899&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;감사합니다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 환경 설정</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/64</guid>
      <comments>https://8156217.tistory.com/64#entry64comment</comments>
      <pubDate>Fri, 30 Dec 2022 23:02:56 +0900</pubDate>
    </item>
    <item>
      <title>[Dothome] 닷홈 (dothome) 무료 호스팅 서비스 이용 방법</title>
      <link>https://8156217.tistory.com/63</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNLpln/btrUXpkgNLI/UHhFmL9xL86cFZz37nzHPK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNLpln/btrUXpkgNLI/UHhFmL9xL86cFZz37nzHPK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNLpln/btrUXpkgNLI/UHhFmL9xL86cFZz37nzHPK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dNLpln/btrUXpkgNLI/UHhFmL9xL86cFZz37nzHPK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;272&quot; height=&quot;210&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;닷홈은 도메인, 무료 웹호스팅, 웹빌더, 메일호스팅, SSL보안인증서, 서버호스팅, 코로케이션 등등 &lt;b&gt;다양한 호스팅 서비스&lt;/b&gt;를 제공하는 홈페이지입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;@호스팅이란??&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&quot;서버 컴퓨터의 전체 또는 일정 공간을 이용할 수 있도록 임대해 주는 서비스&quot;&lt;br /&gt;를 말합니다.&lt;/b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&amp;nbsp;쉽게 설명 드리자면 개인 홈페이지를 만들려고 하면 홈페이지가 들어설 수 있는 웹 상의 공간이 필요한데 이 공간을 닷홈 에서 제공해 준다는 것입니다. 닷홈은 무료로 호스팅 서비스를 제공 하기 때문에 많은 분들이 사용합니다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;오늘은 닷홈의 무료 호스팅 서비스 사용법에 대해서 알아볼 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;1.&amp;nbsp; 닷홈 홈페이지 접속 후 회원 가입&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;닷홈 바로가기&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;a style=&quot;color: #1a5490;&quot; href=&quot;https://www.dothome.co.kr/?gclid=Cj0KCQiAtbqdBhDvARIsAGYnXBNPiShH4rU26fdxQbgFl6yJ2XvqKuklkBLHNgCO3yxny6O7-lVZtucaAlA6EALw_wcB&quot;&gt;https://www.dothome.co.kr/?gclid=Cj0KCQiAtbqdBhDvARIsAGYnXBNPiShH4rU26fdxQbgFl6yJ2XvqKuklkBLHNgCO3yxny6O7-lVZtucaAlA6EALw_wcB&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672394974829&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;닷홈 호스팅&quot; data-og-description=&quot;닷홈은 도메인, 무료 웹호스팅, 웹빌더, 메일호스팅, SSL보안인증서, 서버호스팅, 코로케이션 등 다양한 호스팅 서비스를 제공하고 있습니다.&quot; data-og-host=&quot;www.dothome.co.kr&quot; data-og-source-url=&quot;https://www.dothome.co.kr/?gclid=Cj0KCQiAtbqdBhDvARIsAGYnXBNPiShH4rU26fdxQbgFl6yJ2XvqKuklkBLHNgCO3yxny6O7-lVZtucaAlA6EALw_wcB&quot; data-og-url=&quot;https://www.dothome.co.kr/index.php&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/m3w8L/hyQ5GW4rzf/frs1wG5LLaIBeSKB4MTbiK/img.jpg?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200&quot;&gt;&lt;a href=&quot;https://www.dothome.co.kr/?gclid=Cj0KCQiAtbqdBhDvARIsAGYnXBNPiShH4rU26fdxQbgFl6yJ2XvqKuklkBLHNgCO3yxny6O7-lVZtucaAlA6EALw_wcB&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.dothome.co.kr/?gclid=Cj0KCQiAtbqdBhDvARIsAGYnXBNPiShH4rU26fdxQbgFl6yJ2XvqKuklkBLHNgCO3yxny6O7-lVZtucaAlA6EALw_wcB&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/m3w8L/hyQ5GW4rzf/frs1wG5LLaIBeSKB4MTbiK/img.jpg?width=200&amp;amp;height=200&amp;amp;face=0_0_200_200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;닷홈 호스팅&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;닷홈은 도메인, 무료 웹호스팅, 웹빌더, 메일호스팅, SSL보안인증서, 서버호스팅, 코로케이션 등 다양한 호스팅 서비스를 제공하고 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.dothome.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;회원 가입 페이지&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;1544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWNDnm/btrUYQIHxRM/wsFQrccZlaHcUH9hZyBZB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWNDnm/btrUYQIHxRM/wsFQrccZlaHcUH9hZyBZB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWNDnm/btrUYQIHxRM/wsFQrccZlaHcUH9hZyBZB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWNDnm%2FbtrUYQIHxRM%2FwsFQrccZlaHcUH9hZyBZB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;541&quot; height=&quot;339&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;1544&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 7.13.53.png&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfzYor/btrUZY7HSgD/9QMPRgBlIZq2YNmWKIkky1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfzYor/btrUZY7HSgD/9QMPRgBlIZq2YNmWKIkky1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfzYor/btrUZY7HSgD/9QMPRgBlIZq2YNmWKIkky1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfzYor%2FbtrUZY7HSgD%2F9QMPRgBlIZq2YNmWKIkky1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;358&quot; height=&quot;105&quot; data-filename=&quot;스크린샷 2022-12-30 오후 7.13.53.png&quot; data-origin-width=&quot;838&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;2. 웹 호스팅 (무료 호스팅) 신청 하기&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;상단 메뉴바 - 웹 호스팅 - 무료호스팅&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 7.21.24.png&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhhCFX/btrUZXubEuX/GDnuUE1QdwSEB7mLnQ0lZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhhCFX/btrUZXubEuX/GDnuUE1QdwSEB7mLnQ0lZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhhCFX/btrUZXubEuX/GDnuUE1QdwSEB7mLnQ0lZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhhCFX%2FbtrUZXubEuX%2FGDnuUE1QdwSEB7mLnQ0lZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;797&quot; height=&quot;470&quot; data-filename=&quot;스크린샷 2022-12-30 오후 7.21.24.png&quot; data-origin-width=&quot;797&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;신청하기 클릭&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 7.22.28.png&quot; data-origin-width=&quot;2572&quot; data-origin-height=&quot;1278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JJyl9/btrUTYns3tb/yghjKkKsKjaKhbzn8SUuG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JJyl9/btrUTYns3tb/yghjKkKsKjaKhbzn8SUuG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JJyl9/btrUTYns3tb/yghjKkKsKjaKhbzn8SUuG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJJyl9%2FbtrUTYns3tb%2FyghjKkKsKjaKhbzn8SUuG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;740&quot; height=&quot;368&quot; data-filename=&quot;스크린샷 2022-12-30 오후 7.22.28.png&quot; data-origin-width=&quot;2572&quot; data-origin-height=&quot;1278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;절차 따라서 정보 입력!!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;! DB 암호 &amp;amp; FTP 암호는 다시 확인할 수 없습니다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;! 기억해 두기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2022-12-30 오후 7.27.18.png&quot; data-origin-width=&quot;2596&quot; data-origin-height=&quot;1562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dj5jqV/btrUTYOy13z/ULtWXiKxYPrhsy7eQPxxC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dj5jqV/btrUTYOy13z/ULtWXiKxYPrhsy7eQPxxC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dj5jqV/btrUTYOy13z/ULtWXiKxYPrhsy7eQPxxC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdj5jqV%2FbtrUTYOy13z%2FULtWXiKxYPrhsy7eQPxxC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;801&quot; height=&quot;482&quot; data-filename=&quot;edited_스크린샷 2022-12-30 오후 7.27.18.png&quot; data-origin-width=&quot;2596&quot; data-origin-height=&quot;1562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;@ 확인 후 조금만 기다리면..!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-30 오후 7.28.42.png&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btE9mN/btrUV3BT4nv/j97nlA8jBerkkgi5YYqfc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btE9mN/btrUV3BT4nv/j97nlA8jBerkkgi5YYqfc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btE9mN/btrUV3BT4nv/j97nlA8jBerkkgi5YYqfc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtE9mN%2FbtrUV3BT4nv%2Fj97nlA8jBerkkgi5YYqfc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;57&quot; data-filename=&quot;스크린샷 2022-12-30 오후 7.28.42.png&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2022-12-30 오후 7.33.33.png&quot; data-origin-width=&quot;1896&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vNIBM/btrU0uL9Ie0/fKVylz5UcazDDfntk94Xuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vNIBM/btrU0uL9Ie0/fKVylz5UcazDDfntk94Xuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vNIBM/btrU0uL9Ie0/fKVylz5UcazDDfntk94Xuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvNIBM%2FbtrU0uL9Ie0%2FfKVylz5UcazDDfntk94Xuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;634&quot; height=&quot;255&quot; data-filename=&quot;edited_스크린샷 2022-12-30 오후 7.33.33.png&quot; data-origin-width=&quot;1896&quot; data-origin-height=&quot;764&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;3. 정보 확인&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;마이닷홈 - 상세보기&amp;nbsp; &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;에서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;- 도메인 정보&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;- 웹서버 / FTP 정보&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;- DB정보를 보실 수 있습니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;! 앞서 말씀드렸듯이 &lt;b&gt;FTP암호 &amp;amp; DB암호는 조회가 불가능&lt;/b&gt;합니다&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2022-12-30 오후 7.40.14.png&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;1240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cF9Wxz/btrUTYgFubh/jnzKKDkFAuBkXKvkooQa5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cF9Wxz/btrUTYgFubh/jnzKKDkFAuBkXKvkooQa5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cF9Wxz/btrUTYgFubh/jnzKKDkFAuBkXKvkooQa5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcF9Wxz%2FbtrUTYgFubh%2FjnzKKDkFAuBkXKvkooQa5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;536&quot; height=&quot;360&quot; data-filename=&quot;edited_스크린샷 2022-12-30 오후 7.40.14.png&quot; data-origin-width=&quot;1844&quot; data-origin-height=&quot;1240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;이렇게 해서 무료 호스팅을 서비스를 제공 받았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;다음 게시글에서는 제공 받은 서버에 파일을 업로드 할 수 있는 방법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;1. FTP 프로그램 FileZila (파일 질라)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;&lt;b&gt;2. VS code + stfp 확장 프로그램&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;에 대해 알아볼 것입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1a5490;&quot;&gt;감사합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>개발 환경 설정</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/63</guid>
      <comments>https://8156217.tistory.com/63#entry63comment</comments>
      <pubDate>Fri, 30 Dec 2022 20:01:55 +0900</pubDate>
    </item>
    <item>
      <title>[ Mac OS / Java ] 맥북 자바 버전 변경</title>
      <link>https://8156217.tistory.com/62</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckMe8D/btrUxd6AYwM/92GMo9hI3FmWL2XLmpsYvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckMe8D/btrUxd6AYwM/92GMo9hI3FmWL2XLmpsYvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckMe8D/btrUxd6AYwM/92GMo9hI3FmWL2XLmpsYvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckMe8D%2FbtrUxd6AYwM%2F92GMo9hI3FmWL2XLmpsYvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;294&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;오늘은 자바 jdk를 변경하는 포스팅을 하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;저의 경우 이 포스팅에서 자바 1.8에서 자바 11로 변경하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) 원하는 jdk 버전 다운로드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/downloads/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.oracle.com/java/technologies/downloads/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1672044244155&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Download the Latest Java LTS Free&quot; data-og-description=&quot;Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.&quot; data-og-host=&quot;www.oracle.com&quot; data-og-source-url=&quot;https://www.oracle.com/java/technologies/downloads/&quot; data-og-url=&quot;https://www.oracle.com/java/technologies/downloads/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bOGbjQ/hyQ3XQAZuE/SoCtT1mYbmIKhujVL2rcMK/img.jpg?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/b1Lsu4/hyQ1gjYlig/0V0cCXvieVRxSkTTLv1j11/img.jpg?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/downloads/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.oracle.com/java/technologies/downloads/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bOGbjQ/hyQ3XQAZuE/SoCtT1mYbmIKhujVL2rcMK/img.jpg?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/b1Lsu4/hyQ1gjYlig/0V0cCXvieVRxSkTTLv1j11/img.jpg?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Download the Latest Java LTS Free&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Subscribe to Java SE and get the most comprehensive Java support available, with 24/7 global access to the experts.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 사이트에서 원하는 jdk를 다운 받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 터미널을 키고 아래 커맨드들을 날리면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2) 현재 jdk 버전 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672043644537&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ java -version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dPkHyK/btrUImf7GmG/Wr9e4XVxD6TWwhktTNZLOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dPkHyK/btrUImf7GmG/Wr9e4XVxD6TWwhktTNZLOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dPkHyK/btrUImf7GmG/Wr9e4XVxD6TWwhktTNZLOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdPkHyK%2FbtrUImf7GmG%2FWr9e4XVxD6TWwhktTNZLOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;542&quot; height=&quot;82&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3) 설치된 모든 jdk 버전들 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672043716916&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ /usr/libexec/java_home -V&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-26 오후 5.35.42.png&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Em5r3/btrUJjpTgwn/f1iJjQjsTXM71uwT6fFPCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Em5r3/btrUJjpTgwn/f1iJjQjsTXM71uwT6fFPCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Em5r3/btrUJjpTgwn/f1iJjQjsTXM71uwT6fFPCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEm5r3%2FbtrUJjpTgwn%2Ff1iJjQjsTXM71uwT6fFPCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;469&quot; height=&quot;208&quot; data-filename=&quot;스크린샷 2022-12-26 오후 5.35.42.png&quot; data-origin-width=&quot;954&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;

&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4) 원하는 jdk로 변경&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저의 경우 1.8 에서 11 로 변경하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672043799548&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export JAVA_HOME=$(/usr/libexec/java_home -v 11.0.17)
source ~/.bash_profile&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-26 오후 5.37.44.png&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;60&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J7qud/btrUGqpMmzn/Pg0odb7Z2Nz0KkwUC7NpLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J7qud/btrUGqpMmzn/Pg0odb7Z2Nz0KkwUC7NpLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J7qud/btrUGqpMmzn/Pg0odb7Z2Nz0KkwUC7NpLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ7qud%2FbtrUGqpMmzn%2FPg0odb7Z2Nz0KkwUC7NpLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;605&quot; height=&quot;38&quot; data-filename=&quot;스크린샷 2022-12-26 오후 5.37.44.png&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;60&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4.5) default jdk를 변경하고 싶을 때&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 방법까지는 일시적으로 jdk를 바꾸어 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커맨드를 껐다 키면 다시 default jdk 버전으로 돌아와 있는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영구적으로 바꾸어 주고 싶으면 ~/.zshrc에도 추가해주어야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1672046313811&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vim ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-26 오후 6.24.36.png&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byYnNw/btrUHR1OUqm/dXtSRyboXuOCeILqAyoKwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byYnNw/btrUHR1OUqm/dXtSRyboXuOCeILqAyoKwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byYnNw/btrUHR1OUqm/dXtSRyboXuOCeILqAyoKwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyYnNw%2FbtrUHR1OUqm%2FdXtSRyboXuOCeILqAyoKwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;482&quot; height=&quot;204&quot; data-filename=&quot;스크린샷 2022-12-26 오후 6.24.36.png&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672046367438&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export JAVA_HOME=$(/usr/libexec/java_home -v 11.0.17)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-26 오후 6.21.06.png&quot; data-origin-width=&quot;1132&quot; data-origin-height=&quot;514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqwUNV/btrUBaH6BmN/jAIwxXJ1xEkoqtdeyWv6vK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqwUNV/btrUBaH6BmN/jAIwxXJ1xEkoqtdeyWv6vK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqwUNV/btrUBaH6BmN/jAIwxXJ1xEkoqtdeyWv6vK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqwUNV%2FbtrUBaH6BmN%2FjAIwxXJ1xEkoqtdeyWv6vK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;494&quot; height=&quot;224&quot; data-filename=&quot;스크린샷 2022-12-26 오후 6.21.06.png&quot; data-origin-width=&quot;1132&quot; data-origin-height=&quot;514&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1672046497817&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;source ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5) 변경된 jdk 버전 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1672044170110&quot; class=&quot;applescript&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ java -version&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11로 변경된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-26 오후 5.42.40.png&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B7XJL/btrUEwDOdAi/YiLvyKo4X5qBot6l43dKO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B7XJL/btrUEwDOdAi/YiLvyKo4X5qBot6l43dKO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B7XJL/btrUEwDOdAi/YiLvyKo4X5qBot6l43dKO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB7XJL%2FbtrUEwDOdAi%2FYiLvyKo4X5qBot6l43dKO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;634&quot; height=&quot;84&quot; data-filename=&quot;스크린샷 2022-12-26 오후 5.42.40.png&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다.&lt;/p&gt;</description>
      <category>java</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/62</guid>
      <comments>https://8156217.tistory.com/62#entry62comment</comments>
      <pubDate>Mon, 26 Dec 2022 17:49:20 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] MVC 란 무엇인가??</title>
      <link>https://8156217.tistory.com/61</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdyS1f/btrT6dy9wnt/kymkRi1wF9SLdj1Xy6mkLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdyS1f/btrT6dy9wnt/kymkRi1wF9SLdj1Xy6mkLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdyS1f/btrT6dy9wnt/kymkRi1wF9SLdj1Xy6mkLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdyS1f%2FbtrT6dy9wnt%2FkymkRi1wF9SLdj1Xy6mkLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;290&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Spring은&amp;nbsp;Java&amp;nbsp;기반 프레임워크로 엄청 유명하기 때문에 다들 한번씩 들어보셨을 겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;이 프레임워크는 어떤 식으로 구성이 되어 있을 까요??&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;오늘은 Spring framework의 Web architecture인 MVC Architecture에 대해서 공부해 볼 것입니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;오늘날의 Web architecture에 대해 공부하기 전에 과거의 web architecture에 대해 공부해 봅시다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;과거에는 어떤 Web architecture를 썼을까요??&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;그리고 왜 지금 MVC를 사용 하는 걸까요??&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;과거&amp;nbsp;Web architecture의 모습&amp;nbsp;: JSP Model1 Architecture&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;1990 ~ 2000년 초 까지의 웹 개발 아키텍쳐이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;JSP와&amp;nbsp;Java Bean으로 구성되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&lt;b&gt;JSP는&amp;nbsp;[Controller&amp;nbsp;와&amp;nbsp;View를 포함]&lt;/b&gt; 하고&amp;nbsp;&lt;b&gt;Java Bean은&amp;nbsp;[Model&amp;nbsp;부분]을 담당&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;Controller와&amp;nbsp;View가 통합되어 있기 때문에&lt;b&gt; 유지 보수에 어려움&lt;/b&gt;이 생긴다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;이 어려움을 극복하여 새로 나타나게 된 것이 오늘 날의&amp;nbsp;&lt;b&gt;JSP Model2 Architecture&lt;/b&gt;&amp;nbsp;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;다른말로&lt;b&gt; MVC Architecture&amp;nbsp;&lt;/b&gt;라고 부릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;M( Model )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;V( View )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;C ( Controller ) Architecture는&amp;nbsp;Model , View , Controller로 분리되어 있어서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;유지 보수에 있어 유리하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Spring Framework도&amp;nbsp;MVC&amp;nbsp;패턴을 통해 작업이 이루어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Web architecture &amp;nbsp;: MVC&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;MVC는 Model , View , Controller의 약자입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Spring은 MVC가 각각 독립적으로 나누어져 구성 되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;하나씩 들여다 봅시다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Model : DB와 직접 상호 작용하는 부분이다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DB에서 데이터를 가지고 와서 데이터를 처리한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DB를 다루는 쿼리도 이 부분에 해당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;자바 개발자가 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;View :&amp;nbsp;사용자에게 보여줄&amp;nbsp;UI ( User Interface ) 이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JSP Page로 구성되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;View는 보통 웹 디자이너들이 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Controller :&amp;nbsp;전체적인 화면의 로직을 처리한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;사용자 입력 데이터 추출&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Model class의&amp;nbsp;DB&amp;nbsp;연동 함수 호출&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;화면 이동&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;자바 개발자&amp;nbsp;or framework가 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;MVC의 상호작용 과정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;1.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;사용자&amp;nbsp;(클라이언트)가 웹 서버에&amp;nbsp;Request를 보낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;2.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;웹 서버가 요청을 전달해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;3.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;요청을 전달 받아&amp;nbsp;Controller가 요청에 맞게&amp;nbsp;Model을 이용하여&amp;nbsp;DB에서 적절한 데이터 처리를 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;4.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;그리고 처리 된 데이터를&amp;nbsp;View에 전달해 주면&amp;nbsp;View는 알맞은 웹 페이지를 웹 서버로 보내 준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;5.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;웹 서버가 사용자에게&amp;nbsp;Response를 보낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;MVC는 이런 방식을 통해 작동하게 됩니다..!&lt;/span&gt;&lt;/p&gt;</description>
      <category>Java Spring</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/61</guid>
      <comments>https://8156217.tistory.com/61#entry61comment</comments>
      <pubDate>Tue, 20 Dec 2022 19:07:29 +0900</pubDate>
    </item>
    <item>
      <title>[java] HashMap 사용법 및 예제 총정리</title>
      <link>https://8156217.tistory.com/60</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbhdlT/btrT0S2jrMZ/ES1xKhkYvU0aGR8Jggu2mK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbhdlT/btrT0S2jrMZ/ES1xKhkYvU0aGR8Jggu2mK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbhdlT/btrT0S2jrMZ/ES1xKhkYvU0aGR8Jggu2mK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbhdlT%2FbtrT0S2jrMZ%2FES1xKhkYvU0aGR8Jggu2mK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;213&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자바에서 많이 사용하는 자료 구조인 Hashmap에 대해서 알아보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;map의 주요 특징은 key 와 value를 한 쌍으로 사용한다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;map에는 여러 가지가 있는 데 그 중 가장 많이 사용하는 Hashmap을 공부해보도록 하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;0) 선언&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671436592058&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap&amp;lt;Integer ,String&amp;gt; map = new HashMap&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 값 넣기 (&amp;nbsp; put 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1671436987548&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;map.put(key , value);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1671439787027&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;map.put(1,&quot;AAA&quot;);
map.put(2,&quot;BBB&quot;);
map.put(3,&quot;CCC&quot;);
map.put(4,&quot;DDD&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 특정 key로 value 얻기 ( get 함수 , getOrDefault 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671437077046&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;value = map.get(key);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key가 없으면 null 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key가 없을 때 null 아닌 Default 반환 ( Default는 String으로 아무거나 설정 가능 )&lt;/p&gt;
&lt;pre id=&quot;code_1671438505414&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;value = map.getOrDefault(key, default);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1671439868298&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;System.out.println( map.get(1));
System.out.println( map.getOrDefault(5, &quot;Nope&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) map의 원소 갯수 확인 ( size 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671437282276&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int size = map.size();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) map의 value 값 바꾸기 ( replace 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671437612654&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;map.replace(key , newValue);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5) map 안에 key / value 가 있는 지 확인 ( containsKey , containsValue 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671438029667&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;boolean isKey = map.containsKey(key);

boolean isValue = map.containsValue(value);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6) map이 비어 있는 지 확인 ( isEmpty 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671438097677&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;boolean is = map.isEmpty();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7) 원소 삭제 ( remove 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671438571940&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;value = map.remove(key);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8) Key가 없거나 Value가 null일때만 삽입 ( putIfAbsent 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671438637949&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;map.putIfAbsent(key, value);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;9) 모든 Key 가져오기 ( map.keySet 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671438841617&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set&amp;lt;Integer&amp;gt; keySet = map.keySet();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671439040313&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap&amp;lt;Integer ,String&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
        
map.put(1, &quot;AAA&quot;);
map.put(2,&quot;BBB&quot;);
map.put(3,&quot;CCC&quot;);
map.put(4,&quot;DDD&quot;);

Set&amp;lt;Integer&amp;gt; set = map.keySet();

System.out.println(set);

for(Integer key : set){
	System.out.println(key);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1671439078779&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;출력

[1, 2, 3, 4]
1
2
3
4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;10) 모든 value 가져오기 ( map.values 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671439383760&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Collection&amp;lt;String&amp;gt; col = map.values();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671439320058&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap&amp;lt;Integer ,String&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
        
map.put(1, &quot;AAA&quot;);
map.put(2,&quot;BBB&quot;);
map.put(3,&quot;CCC&quot;);
map.put(4,&quot;DDD&quot;);

Collection&amp;lt;String&amp;gt; col = map.values();

System.out.println(col);

for(String key : col){
	System.out.println(key);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671439408612&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;출력

[AAA, BBB, CCC, DDD]
AAA
BBB
CCC
DDD&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11) 모든 key , value 쌍 가져오기 ( entrySet 함수 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671439667533&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set&amp;lt; Entry&amp;lt; Integer,String&amp;gt;&amp;gt; set = map.entrySet();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671439653867&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap&amp;lt;Integer ,String&amp;gt; map = new HashMap&amp;lt;&amp;gt;();

map.put(1, &quot;AAA&quot;);
map.put(2,&quot;BBB&quot;);
map.put(3,&quot;CCC&quot;);
map.put(4,&quot;DDD&quot;);

Set&amp;lt; Entry&amp;lt; Integer,String&amp;gt;&amp;gt; set = map.entrySet();

for(Entry&amp;lt;Integer,String&amp;gt; entry : set){
    System.out.println(entry.getKey() + &quot; &quot; + entry.getValue());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671439709719&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;출력

1 AAA
2 BBB
3 CCC
4 DDD&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>java</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/60</guid>
      <comments>https://8156217.tistory.com/60#entry60comment</comments>
      <pubDate>Mon, 19 Dec 2022 17:48:39 +0900</pubDate>
    </item>
    <item>
      <title>[java] Stack 클래스 사용법 및 예제 총정리</title>
      <link>https://8156217.tistory.com/59</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o6YLl/btrT4IRQ2ey/E94yf1wgEOcLkX9luWCdc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o6YLl/btrT4IRQ2ey/E94yf1wgEOcLkX9luWCdc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o6YLl/btrT4IRQ2ey/E94yf1wgEOcLkX9luWCdc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo6YLl%2FbtrT4IRQ2ey%2FE94yf1wgEOcLkX9luWCdc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;597&quot; height=&quot;299&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자바 언어를 좀 더 단단히 배우고 싶어서 자바 자료 구조에 대해서 정리하면서 공부해 보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;오늘은 Stack에 대해서 정리를 해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;0) 선언&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671433585764&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; Stack&amp;lt;자료형 타입&amp;gt; stk = new Stack&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시&lt;/p&gt;
&lt;pre id=&quot;code_1671433535847&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; Stack&amp;lt;Integer&amp;gt; stk = new Stack&amp;lt;&amp;gt;();
 Stack&amp;lt;String&amp;gt; stk2 = new Stack&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 스택에 값 추가&amp;nbsp; ( add , push 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671431838179&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.add(10);
stk.push(20);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차이점은 반환 값이 add는 true / false , push는 집어 넣은 값이 리턴 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1671431859857&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;        System.out.println(stk.add(30));    // true 출력
        System.out.println(stk.push(40));   // 40 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) 스택에 값 제거 ( pop 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pop된 값을 출력 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1671432414186&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.pop();

System.out.println(stk.pop()); // 반환 값 출력&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택 비었는 지 확인 ( empty 함수 )&lt;/p&gt;
&lt;pre id=&quot;code_1671432618345&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;boolean isempty = stk.empty();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) isempty , push , pop 사용 예제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671432743189&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class stack {
    public static void main(String[] args) {
        Stack&amp;lt;Integer&amp;gt; stk = new Stack&amp;lt;&amp;gt;();
        
        stk.add(10);		// 10
        stk.push(20);		// 20 10
        stk.push(30);		// 30 20 10
        
        while(!stk.empty()){
            System.out.println(stk.pop());
        }
        
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1671432775090&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;출력

30
20
10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) 최 상단 노드 확인 ( peak 함수 )&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최상단 노드 반환&lt;/p&gt;
&lt;pre id=&quot;code_1671433158987&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.peak();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5) 노드의 갯수 ( size 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드의 갯수 반환&lt;/p&gt;
&lt;pre id=&quot;code_1671433220320&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.size();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6) 특정 노드를 가지고 있는 지 확인 ( contain 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671433253505&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.contain(value);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;peak , size , contain 사용 예제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671433285010&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class stack {
    public static void main(String[] args) {
        Stack&amp;lt;Integer&amp;gt; stk = new Stack&amp;lt;&amp;gt;();
        
        stk.push(10);
        stk.push(20);
        stk.push(30);
        
        System.out.println(stk.peek());
        System.out.println(stk.size());
        System.out.println(stk.contains(30));
        System.out.println(stk.contains(40));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671433300705&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;출력

30
3
true
false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7) stack 속 모든 값 삭제 ( clear 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671433408600&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.clear();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8) 차례로 출력 ( for문 사용 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료형 타입을 맞춰 주고 &lt;b&gt;임의의변수&lt;/b&gt; &lt;b&gt;: 스택이름&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1671434421201&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.push(10);
stk.push(20);
stk.push(30);

for(Integer s : stk) {
    System.out.println(s);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671434544607&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;출력

10
20
30&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;9) 특정 노드 위치 반환 ( search 함수 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671434052631&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; stk.search(value);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671434074056&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.push(10);
stk.push(20);
stk.push(30);

System.out.println(stk.search(10));
System.out.println(stk.search(20));
System.out.println(stk.search(30));&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1671434098624&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;출력

3
2
1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;10) 스택 정렬&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671434787222&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.sort(null);				// 오름차순
stk.sort(Collections.reverseOrder());	// 내림차순&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1671434829474&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stk.push(30);
stk.push(10);
stk.push(20);

stk.sort(null);

for(Integer s : stk) {
    System.out.println(s);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1671434841028&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;출력

10
20
30&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>java</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/59</guid>
      <comments>https://8156217.tistory.com/59#entry59comment</comments>
      <pubDate>Mon, 19 Dec 2022 16:27:54 +0900</pubDate>
    </item>
    <item>
      <title>[C++] [BFS / DFS] 백준 2331 번 문제 풀이</title>
      <link>https://8156217.tistory.com/58</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9aWvJ/btrJ7rlE135/ZwLigQeVTiRzG4MYv2KIS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9aWvJ/btrJ7rlE135/ZwLigQeVTiRzG4MYv2KIS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9aWvJ/btrJ7rlE135/ZwLigQeVTiRzG4MYv2KIS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9aWvJ%2FbtrJ7rlE135%2FZwLigQeVTiRzG4MYv2KIS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;485&quot; height=&quot;253&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmH1yC/btrJ7qUBpEE/QDvo8is9pttXIBs2otn7A1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmH1yC/btrJ7qUBpEE/QDvo8is9pttXIBs2otn7A1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmH1yC/btrJ7qUBpEE/QDvo8is9pttXIBs2otn7A1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmH1yC%2FbtrJ7qUBpEE%2FQDvo8is9pttXIBs2otn7A1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1225&quot; height=&quot;736&quot; data-origin-width=&quot;1225&quot; data-origin-height=&quot;736&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;DFS / BFS 와 그리디 두 가지 방법으로 풀었는데 DFS / BFS를 사람들이 일반적으로 많이 사용한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;시간적으로는 DFS / BFS 가 효율적이고 , 메모리 사용량으로 보면 그리디가 좀 더 효율적이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;첫 번째 풀이 : DFS / BFS&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;A 의 최대는 9999 , P의 최대는 5&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나올 수 있는 가장 큰 값은 : 9의 5승 * 4 = 236196&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Code&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660900684351&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// BaekJoon 2331
// Title : 반복 수열
// URL : https://www.acmicpc.net/problem/2331

#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cmath&amp;gt;

using namespace std;

#define MAX_NUM 236196

int visit[MAX_NUM];
int P;
int answer = 0;

void DFS(int A){
    int origin = A;
    int next = 0;

    visit[A-1]++;

    while(A &amp;gt; 0){
        next += (int)pow( A % 10 , P);
        A /= 10;
    }

    if(visit[next-1] == 2) return ;
     
    DFS(next);

    if(visit[origin-1] == 1) answer++;

}

int main(int argc, char** argv){
    int A , num;

    cin &amp;gt;&amp;gt; A &amp;gt;&amp;gt; P;

    DFS(A);

    cout &amp;lt;&amp;lt; answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;두 번째 풀이 : 그리디 알고리즘&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Data structure로는 deque를 사용하였다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;반복 구간을 algorithm의 find 함수로 찾아서 iterator를 통해 갯수를 구했다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Code&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660900798975&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// BaekJoon 2331
// Title : 반복 수열
// URL : https://www.acmicpc.net/problem/2331

#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;deque&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using namespace std;

int next_num(int D , int P){
    int total = 0;
    
    while(D &amp;gt; 0){ 
        total += pow( (D % 10) , P);
        D /= 10;
    }
    return total;
}

int main(int argc , char** argv){
    int A , P , num;
    deque&amp;lt;int&amp;gt; dq;
    deque&amp;lt;int&amp;gt; ::iterator iter;

    cin &amp;gt;&amp;gt; A &amp;gt;&amp;gt; P;

    dq.push_back(A);

    while(1){

        A = next_num(A , P);
        iter = find(dq.begin() , dq.end() , A);
        if(iter != dq.end()){
            num = iter - dq.begin();
            break;
        }

        dq.push_back(A);
    }

    cout &amp;lt;&amp;lt; num;

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2331&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/2331&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1660900906526&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2331번: 반복수열&quot; data-og-description=&quot;첫째 줄에&amp;nbsp;반복되는 부분을 제외했을 때, 수열에 남게 되는 수들의 개수를 출력한다.&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2331&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2331&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jCEUf/hyPuKtibGh/NOLCnymgQFHXwwybhogIoK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2331&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2331&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jCEUf/hyPuKtibGh/NOLCnymgQFHXwwybhogIoK/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2331번: 반복수열&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에&amp;nbsp;반복되는 부분을 제외했을 때, 수열에 남게 되는 수들의 개수를 출력한다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>c++/백준 문제 풀이</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/58</guid>
      <comments>https://8156217.tistory.com/58#entry58comment</comments>
      <pubDate>Fri, 19 Aug 2022 18:21:46 +0900</pubDate>
    </item>
    <item>
      <title>[C++][BFS / DFS] 백준 2606번 문제 풀이</title>
      <link>https://8156217.tistory.com/57</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buZPPP/btrJ7e0rC1v/pnoRyZDiYdc9WCEhweVmcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buZPPP/btrJ7e0rC1v/pnoRyZDiYdc9WCEhweVmcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buZPPP/btrJ7e0rC1v/pnoRyZDiYdc9WCEhweVmcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuZPPP%2FbtrJ7e0rC1v%2FpnoRyZDiYdc9WCEhweVmcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;261&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;892&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R2JDS/btrJ3hxVX89/mGDKNfIisfD9hjAH06iXj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R2JDS/btrJ3hxVX89/mGDKNfIisfD9hjAH06iXj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R2JDS/btrJ3hxVX89/mGDKNfIisfD9hjAH06iXj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR2JDS%2FbtrJ3hxVX89%2FmGDKNfIisfD9hjAH06iXj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1240&quot; height=&quot;892&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;892&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;간단한&lt;br /&gt;BFS or DFS 문제&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◎ Data structure는 Deque를 사용함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◎ adj_list 먼저 만들고 DFS Search로 답을 구함 (BFS 사용해도 됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◎ adj_list , check를 전역 변수로 선언 하지 않고 매개변수로 보내줌 ( &lt;b&gt;동적 할당&lt;/b&gt;을 위해 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Code&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1660891624863&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// BaekJoon 2606
// Title : Virus
// URL : https://www.acmicpc.net/problem/2606

#include &amp;lt;iostream&amp;gt;
#include &amp;lt;deque&amp;gt;

using namespace std;

void DFS(deque&amp;lt;int&amp;gt; adj_list[] ,deque&amp;lt;bool&amp;gt; &amp;amp;check , int i , int &amp;amp;cnt){
    check[i-1] = true;

    for(int j = 0 ; j &amp;lt; adj_list[i-1].size() ; ++j){
        if(check[adj_list[i-1][j] - 1] == false){ DFS(adj_list,check , adj_list[i-1][j], cnt) ; cnt++; }
    }
}

int main(int argc , char** argv){

    int cmpr , num , first , second;
    int cnt = 0;

    cin &amp;gt;&amp;gt; cmpr &amp;gt;&amp;gt; num;

    deque&amp;lt;int&amp;gt; adj_list[cmpr];
    deque&amp;lt;bool&amp;gt; check(cmpr , false);
    
    // Making adj_list
    
    while(num--){
        
        cin &amp;gt;&amp;gt; first &amp;gt;&amp;gt; second;

        adj_list[first - 1].push_back(second);
        adj_list[second - 1].push_back(first);

    }
    
    // DFS search
    
    DFS(adj_list , check , 1 , cnt);
    
    cout &amp;lt;&amp;lt; cnt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2606&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/2606&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1660891855719&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;2606번: 바이러스&quot; data-og-description=&quot;첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/2606&quot; data-og-url=&quot;https://www.acmicpc.net/problem/2606&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hzTNZ/hyPuJH5jZF/wcMwajGuprNT87gzzlNUY0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2606&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/2606&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hzTNZ/hyPuJH5jZF/wcMwajGuprNT87gzzlNUY0/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;2606번: 바이러스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>c++/백준 문제 풀이</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/57</guid>
      <comments>https://8156217.tistory.com/57#entry57comment</comments>
      <pubDate>Fri, 19 Aug 2022 15:50:50 +0900</pubDate>
    </item>
    <item>
      <title>[C++][BFS / DFS] 백준 10451번 문제 풀이</title>
      <link>https://8156217.tistory.com/56</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DD4B9/btrJ3wfINPe/KaQK6RdLZFIV6VmErZdSck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DD4B9/btrJ3wfINPe/KaQK6RdLZFIV6VmErZdSck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DD4B9/btrJ3wfINPe/KaQK6RdLZFIV6VmErZdSck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDD4B9%2FbtrJ3wfINPe%2FKaQK6RdLZFIV6VmErZdSck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;534&quot; height=&quot;279&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;807&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RvGTv/btrJ3hC1dAz/uFXwXZTNx3owFxoxUEc5q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RvGTv/btrJ3hC1dAz/uFXwXZTNx3owFxoxUEc5q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RvGTv/btrJ3hC1dAz/uFXwXZTNx3owFxoxUEc5q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRvGTv%2FbtrJ3hC1dAz%2FuFXwXZTNx3owFxoxUEc5q1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1210&quot; height=&quot;807&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;807&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;◎ 저는 이 문제를 adjacent matrix를 만들고 DFS로 탐색하며 문제를 해결하였습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Code&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1660819339186&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// BaekJoon 10451
// Title : 순열 사이클
// URL : https://www.acmicpc.net/problem/10451

#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;


// DFS recursion

void DFS(vector&amp;lt;vector&amp;lt;bool&amp;gt;&amp;gt; &amp;amp;arr ,vector&amp;lt;bool&amp;gt; &amp;amp;check ,int i){
    check[i-1] = true;
    for(int j = 1 ; j &amp;lt;= check.size(); ++j){
        if(arr[i-1][j-1] == true &amp;amp;&amp;amp; check[j-1] == false) DFS(arr,check, j );
    }
}

int main(int argc , char** argv){

    int T , N , temp;
    
    cin &amp;gt;&amp;gt; T;

    while(T--){

        int cnt = 0;        // answer

        cin &amp;gt;&amp;gt; N;

        vector&amp;lt;vector&amp;lt;bool&amp;gt;&amp;gt; arr(N , vector&amp;lt;bool&amp;gt;(N , false));      // adj matrix
        vector&amp;lt;bool&amp;gt; check ( N , false );                           // check list
        
        for(int i = 1 ; i &amp;lt;= N ; ++i){

            cin &amp;gt;&amp;gt; temp;

            arr[i-1][temp - 1] = true;
            arr[temp-1][i-1] = true;

        }

        for(int i = 1 ; i &amp;lt;= N ; ++i){
            if(check[i-1] == false){
                DFS(arr , check, i );       // DFS or BFS
                cnt++;
            }
        }

        cout &amp;lt;&amp;lt; cnt &amp;lt;&amp;lt; endl;

    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10451&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/10451&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1660819387324&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;10451번: 순열 사이클&quot; data-og-description=&quot;1부터 N까지 정수 N개로 이루어진 순열을 나타내는 방법은 여러 가지가 있다. 예를 들어, 8개의 수로 이루어진 순열 (3, 2, 7, 8, 1, 4, 5, 6)을 배열을 이용해 표현하면 \(\begin{pmatrix} 1 &amp;amp; 2 &amp;amp;3&amp;amp;4&amp;amp;5&amp;amp;6&amp;amp;7&amp;amp;8 \\ &amp;nbsp;3&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/10451&quot; data-og-url=&quot;https://www.acmicpc.net/problem/10451&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bFnDAj/hyPuOWJEX1/qnIP2R6GZ2s70a98xhlAXk/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/10451&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/10451&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bFnDAj/hyPuOWJEX1/qnIP2R6GZ2s70a98xhlAXk/img.png?width=2834&amp;amp;height=1480&amp;amp;face=0_0_2834_1480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;10451번: 순열 사이클&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1부터 N까지 정수 N개로 이루어진 순열을 나타내는 방법은 여러 가지가 있다. 예를 들어, 8개의 수로 이루어진 순열 (3, 2, 7, 8, 1, 4, 5, 6)을 배열을 이용해 표현하면 \(\begin{pmatrix} 1 &amp;amp; 2 &amp;amp;3&amp;amp;4&amp;amp;5&amp;amp;6&amp;amp;7&amp;amp;8 \\ &amp;nbsp;3&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>c++/백준 문제 풀이</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/56</guid>
      <comments>https://8156217.tistory.com/56#entry56comment</comments>
      <pubDate>Thu, 18 Aug 2022 19:43:21 +0900</pubDate>
    </item>
    <item>
      <title>[C++][자료구조 Stack] 백준 10828번 문제 풀이</title>
      <link>https://8156217.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pqrbL/btrH3SlcWEo/4KVAJiHZW9vtvRTUbPcXrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pqrbL/btrH3SlcWEo/4KVAJiHZW9vtvRTUbPcXrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pqrbL/btrH3SlcWEo/4KVAJiHZW9vtvRTUbPcXrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpqrbL%2FbtrH3SlcWEo%2F4KVAJiHZW9vtvRTUbPcXrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;375&quot; height=&quot;422&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;백준 10828&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;문제&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/corOxJ/btrH5e9QugT/QQlQvTcrtsIPegyk6EmBt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/corOxJ/btrH5e9QugT/QQlQvTcrtsIPegyk6EmBt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/corOxJ/btrH5e9QugT/QQlQvTcrtsIPegyk6EmBt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcorOxJ%2FbtrH5e9QugT%2FQQlQvTcrtsIPegyk6EmBt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1171&quot; height=&quot;566&quot; data-origin-width=&quot;1171&quot; data-origin-height=&quot;566&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #781b33;&quot;&gt;&amp;nbsp;자료 구조 Stack 구현&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Stack Class를 직접 구현하여 사용하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Code&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658664426984&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// BaekJun  10828
// Title : Stack
// URL : https://www.acmicpc.net/problem/10828

/*

문제

정수를 저장하는 스택을 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.

명령은 총 다섯 가지이다.

push X: 정수 X를 스택에 넣는 연산이다.
pop: 스택에서 가장 위에 있는 정수를 빼고, 그 수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.
size: 스택에 들어있는 정수의 개수를 출력한다.
empty: 스택이 비어있으면 1, 아니면 0을 출력한다.
top: 스택의 가장 위에 있는 정수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.

*/

#include &amp;lt;iostream&amp;gt;

using namespace std;

class Stack{

private:
        int* arr;
        int index;
public:
    Stack(int N){
        arr = new int [N];
        index = -1;
    }
    ~Stack(){};

    void push(int num){
        arr[++index] = num;
    }
    int top(){
        if(index == -1) return -1;
        return arr[index];
    }
    int size(){
        return (index+1);
    }
    int empty(){
        if (index == -1) return 1;
        else return 0;
    }
    int pop(){
        if(index == -1) return -1;
        return arr[index--];
    }

};

int main(){
	
    // speed up function
    cin.tie(NULL); cout.tie(NULL);
    ios_base::sync_with_stdio(false);

    int N;
    int num;
    string input;

    cin &amp;gt;&amp;gt; N;

    Stack s(N);


    for(int i = 0 ; i &amp;lt; N ; ++i){
        
        cin &amp;gt;&amp;gt; input;

        if(input == &quot;push&quot;){
            cin &amp;gt;&amp;gt; num;
            s.push(num);
        }
        else if(input == &quot;top&quot;) cout &amp;lt;&amp;lt; s.top() &amp;lt;&amp;lt; &quot;\n&quot;;
        else if(input == &quot;pop&quot;) cout &amp;lt;&amp;lt; s.pop() &amp;lt;&amp;lt; &quot;\n&quot;;    
        else if(input == &quot;size&quot;) cout &amp;lt;&amp;lt; s.size() &amp;lt;&amp;lt; &quot;\n&quot;;    
        else if(input == &quot;empty&quot;) cout &amp;lt;&amp;lt; s.empty() &amp;lt;&amp;lt; &quot;\n&quot;;    
        
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>c++/백준 문제 풀이</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/55</guid>
      <comments>https://8156217.tistory.com/55#entry55comment</comments>
      <pubDate>Sun, 24 Jul 2022 21:14:14 +0900</pubDate>
    </item>
    <item>
      <title>[C++] 백준 5397번 풀이</title>
      <link>https://8156217.tistory.com/54</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTXp6t/btrH75EwTDH/63uZHkg2vvErI3LV4NN8Z0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTXp6t/btrH75EwTDH/63uZHkg2vvErI3LV4NN8Z0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTXp6t/btrH75EwTDH/63uZHkg2vvErI3LV4NN8Z0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTXp6t%2FbtrH75EwTDH%2F63uZHkg2vvErI3LV4NN8Z0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;286&quot; height=&quot;322&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;&lt;b&gt;백준 5397&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1217&quot; data-origin-height=&quot;874&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JUizL/btrIazSG1SU/caKBs0c1olayAhv9mTeWR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JUizL/btrIazSG1SU/caKBs0c1olayAhv9mTeWR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JUizL/btrIazSG1SU/caKBs0c1olayAhv9mTeWR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJUizL%2FbtrIazSG1SU%2FcaKBs0c1olayAhv9mTeWR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;813&quot; height=&quot;584&quot; data-origin-width=&quot;1217&quot; data-origin-height=&quot;874&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;시간 제한은 1초&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;문자열의 길이는 최대 100만&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;&lt;b&gt;시간 복잡도 O(N^2) 으로는 풀 수 없고&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;&lt;b&gt;시간 복잡도 O(nlogn) or O(N) 으로 풀어야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;&lt;b&gt;Linear 만에 풀기 위해 l&lt;b&gt;ist +&lt;/b&gt;&amp;nbsp;iterator를 사용하였다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #5f6d2b;&quot;&gt;&lt;b&gt;Code&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1658664136804&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// BaekJoon 5397
// Title : 키로거
// URL : https://www.acmicpc.net/problem/5397

/*


문제


창영이는 강산이의 비밀번호를 훔치기 위해서 강산이가 사용하는 컴퓨터에 키로거를 설치했다. 
며칠을 기다린 끝에 창영이는 강산이가 비밀번호 창에 입력하는 글자를 얻어냈다.

키로거는 사용자가 키보드를 누른 명령을 모두 기록한다. 
따라서, 강산이가 비밀번호를 입력할 때, 화살표나 백스페이스를 입력해도 정확한 비밀번호를 알아낼 수 있다. 

강산이가 비밀번호 창에서 입력한 키가 주어졌을 때, 강산이의 비밀번호를 알아내는 프로그램을 작성하시오. 
강산이는 키보드로 입력한 키는 알파벳 대문자, 소문자, 숫자, 백스페이스, 화살표이다.


*/

#include &amp;lt;iostream&amp;gt;
#include &amp;lt;list&amp;gt;

using namespace std;

int main(){

    int N;
    string s;
 
    cin &amp;gt;&amp;gt; N;

    list&amp;lt;char&amp;gt;::iterator it;
    list&amp;lt;char&amp;gt; password;
    
    

    for(int i = 0 ; i &amp;lt; N ; ++i){
        
        cin &amp;gt;&amp;gt; s;    

        password.clear();
        it = password.begin();    
        
        
        for(int j = 0 ; j &amp;lt; s.length(); ++j){
            if(s[j] =='&amp;lt;') {
                if(it != password.begin()) it--;
            }
            else if(s[j]=='&amp;gt;'){
                if( it != password.end()) it++;
            }
            else if(s[j]=='-'){
                if(it != password.begin()) it = password.erase(--it);
            }
            else{
                it = password.insert(it,s[j]);
                it++;
            }   
        }

        for(char x : password) cout &amp;lt;&amp;lt; x;
        cout &amp;lt;&amp;lt; endl;
    }
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>c++/백준 문제 풀이</category>
      <category>5397</category>
      <category>iterator</category>
      <category>list</category>
      <category>백준</category>
      <category>키로거</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/54</guid>
      <comments>https://8156217.tistory.com/54#entry54comment</comments>
      <pubDate>Sun, 24 Jul 2022 21:04:29 +0900</pubDate>
    </item>
    <item>
      <title>[C++][Malloc] Implicit allocator 구조 및 구현</title>
      <link>https://8156217.tistory.com/53</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/co1ac0/btrH1CwUpfO/IWhC4KYyLufNFkaZNpXB3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/co1ac0/btrH1CwUpfO/IWhC4KYyLufNFkaZNpXB3K/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://www.crunchbase.com/organization/allocator&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/co1ac0/btrH1CwUpfO/IWhC4KYyLufNFkaZNpXB3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fco1ac0%2FbtrH1CwUpfO%2FIWhC4KYyLufNFkaZNpXB3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;402&quot; height=&quot;246&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://www.crunchbase.com/organization/allocator&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;오늘은 C 와 C++에서 사용되는 Malloc 의 구현 방식인&lt;span&gt;&lt;b&gt; Implicit&lt;/b&gt; &lt;/span&gt;&lt;b&gt;allocator&lt;/b&gt;에 대해서 공부해 보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;그 전에 사전 지식을 조금 먼저 이야기를 해보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Dynamic Memory Allocation 이란??&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PXTRy/btrH6IP7Fsd/WE5x4sOC1KYn6A6ktcfjbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PXTRy/btrH6IP7Fsd/WE5x4sOC1KYn6A6ktcfjbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PXTRy/btrH6IP7Fsd/WE5x4sOC1KYn6A6ktcfjbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPXTRy%2FbtrH6IP7Fsd%2FWE5x4sOC1KYn6A6ktcfjbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;272&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;@ 프로그램이 작동하는 도중 (런타임 동안) 필요한 메모리를 할당 받고자 할 때 사용 하는 할당 방법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;@ 프로세스의 Heap 공간에 저장 -&amp;gt;&amp;nbsp;단편화(Fragmentation) 문제 발생 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;@ 단편화 문제를 해결하고 효과적으로 메모리들을 저장하기 위한 Dynamic allocator로 Explicit Allocator , Implicit Allocator 등 이 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;&lt;b&gt;사용 이유&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;: 효율적인 메모리 관리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Block 이란?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #666666;&quot;&gt;메모리를 관리하는 단위&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm5U8g/btrH0RVCdJk/Sjj8K3OIW9KMmauK5NN85k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm5U8g/btrH0RVCdJk/Sjj8K3OIW9KMmauK5NN85k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm5U8g/btrH0RVCdJk/Sjj8K3OIW9KMmauK5NN85k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm5U8g%2FbtrH0RVCdJk%2FSjj8K3OIW9KMmauK5NN85k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;415&quot; height=&quot;388&quot; data-origin-width=&quot;507&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;&amp;lt; Block 구성 &amp;gt; ( Implicit allocator )&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;[Header , Payload , Padding , Footer]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Header , Footer : 각각 블록의 시작과 끝을 나타내는 부분, 블록의 사이즈와 할당 여부를 저장한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Payload : 실제 정보들이 들어가는 부분&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Padding : 8Bytes 단위를 맞추기 위해 할당해야 할 메모리보다 많은 메모리를 할당해줌 (선택적으로 사용한다.)&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;※ Header , Footer 들은 각각 32 bit 운영 체제 기준 4 Bytes 이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Memory는 이런 블록들로 구성되어 Heap 속에 저장되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;블록 들을 저장하는 방법에 따라 Explicit Allocator , Implicit Allocator 두 가지 할당기로 나뉘게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;여기에서는 Java / Lisp 에서 사용하는 Implicit Allocator에 대해서 배워 보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size16&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #781b33; font-family: 'Noto Serif KR';&quot;&gt;Implicit allocator&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;@ 순차적으로 모든 블록들을 검사하는 선형적인 방법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;@ Free가 자동으로 진행 되기 때문에 garbage collection이라고도 불림&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;@ Java / Lisp 등 high-level 언어에서 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;※ Java 에서는 C언어에서 처럼 일일이 할당된 메모리를 직접 Free를 통해 해제 해줄 필요가 없는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;그 이유는 Java에는 garbage collection이 있어서 자동으로 불필요한 메모리를 해제해주기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;가용 블록을 찾는 방법&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;First-fit : 할당 가능한 가용 블록을 앞에서 부터 찾는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Next-fit : 할당 요청된 메모리에 알맞은 메모리를 줬다면 그 다음 메모리 요청 때는 그 위치에서 부터 시작하여 찾는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Best-fit : 할당 가능한 가용 블록 중 가장 작은 블록을 할당해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Next-fit 이 가장 성능이 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;하지만 쉬운 이해를 위해 First-fit으로 구현을 해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;&lt;b&gt;Heap 구조&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpNxaD/btrH31o8wDl/kA3AveOIYXNcuvjjLSJDk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpNxaD/btrH31o8wDl/kA3AveOIYXNcuvjjLSJDk1/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://velog.io/@emplam27/CS-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%8F%99%EC%A0%81%ED%95%A0%EB%8B%B9-Implicit-Explicit-Segregated-list-Allocator&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpNxaD/btrH31o8wDl/kA3AveOIYXNcuvjjLSJDk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpNxaD%2FbtrH31o8wDl%2FkA3AveOIYXNcuvjjLSJDk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;575&quot; height=&quot;93&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;171&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://velog.io/@emplam27/CS-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%8F%99%EC%A0%81%ED%95%A0%EB%8B%B9-Implicit-Explicit-Segregated-list-Allocator&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;가용 블록과 할당 블록이 함께 존재하는 Implicit allocator의 heap공간이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Implicit Allocator 구현&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;C++를 통해 구현하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;맴버 변수&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650107616&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;char* heap ;        // Start point of Heap                      
char* brk;          // End point of Heap
char* max_addr;     // Max Address of Heap&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;매크로&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650139138&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief Macros for Block Size &amp;amp; Alloc 
 */

// size + alloc bit
#define PACK(size, alloc) ((size) | (alloc))

// GET , SET Function block pointer
#define GET(p) (*(unsigned int *)(p))
#define PUT(p,val) (*(unsigned int*)(p) = (val))

#define GET_SIZE(p) (GET(p) &amp;amp; ~0x7)
#define GET_ALLOC(p) (GET(p) &amp;amp; 0x1)


/**
 * @brief Macros for Block
 */

#define HDRP(bp) ((char *)(bp) - WSIZE)
#define FTRP(bp) ((char *)(bp) + (GET_SIZE(HDRP(bp))) - DSIZE )

#define NEXT_BLKP(bp) ((char*)(bp) + GET_SIZE(HDRP(bp)))
#define PREV_BLRP(bp) ((char*)(bp) - GET_SIZE( (char *)(bp) - DSIZE ))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;매크로가 정말 많다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;PACK&lt;/b&gt;&amp;nbsp;&lt;b&gt;:&lt;/b&gt;&amp;nbsp;Header 와 Footer에 필요한 Size , Alloc여부를 합쳐주는 매크로&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;GET , PET :&lt;/b&gt;&amp;nbsp;char* 가 인자로 주어지므로 int 값을 얻기 위해 형 변환 진행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;GET_SIZE , GET_ALLOC :&lt;/b&gt;&amp;nbsp;PACK에서 각각 size 와 alloc 여부를 뽑아냄&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;HDBP , FTBP :&lt;/b&gt;&amp;nbsp;각각 Header와 Footer를 가리키는 pointer를 반환&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;PREV_BLKP , NEXT_BLKP :&lt;/b&gt;&amp;nbsp;각각 이전 , 다음 블록으로 이동하는 매크로&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;서브 함수들&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;b&gt;Extend_heap , Mem_sbrk 함수&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Heap을 늘려 주는 함수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;mem_sbrk : heap 크기를 늘려줌&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;extend_heap : heap이 늘어남에 따라 블록 조정을 해줌&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650240690&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief The function that increases space of heap when it is lack
 * 
 * @param words : Number of words ( word : 4 Bytes ) 
 * @return void* : New Free block pointer
 */
char* Mymalloc::extend_heap (size_t words)
{
    char *bp;
    size_t size;

    size = (words % 2) ? (words +1) * WSIZE : words * WSIZE;

    if((long)(bp = mem_sbrk(size)) == -1) return NULL;

    PUT(HDRP(bp),PACK(size , 0));
    PUT(FTRP(bp) ,PACK(size , 0));
    PUT(HDRP(NEXT_BLKP(bp)) , PACK(0,1));

    return coalesce(bp);
}



/**
 * @brief The function that increases the size of the heap
 * 
 * @param incr : Amount of increasement of heap
 * @return void* : Brk pointer before increasement
 */
char* Mymalloc::mem_sbrk(int incr){
    char* old_brk = brk;

    if( (incr &amp;lt; 0) || ( (brk + incr) &amp;gt; max_addr) ){
        perror(&quot;mem_sbrk failed.&quot;);
        return (char *)-1;
    }
    
    brk += incr;
    return (char*)old_brk;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;&lt;b&gt;Coalesce 함수&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Coalesce : 가용 블록이 생겼을 때 바로 옆에 가용 블록이 있다면 합치는 함수 ( 단편화를 줄이기 위함 )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650302658&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief The function that combines the free blocks
 * 
 * @param bp : Pointer which is pointing free block
 * @return void* : Pointer which is pointing combined free block
 */
char * Mymalloc::coalesce(char *bp){
    
    size_t size = GET_SIZE(HDRP(bp));
    size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLRP(bp)));
    size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));

    if(prev_alloc &amp;amp;&amp;amp; next_alloc){
        return bp;
    }

    else if( !prev_alloc  &amp;amp;&amp;amp; next_alloc){
        size += GET_SIZE(HDRP(PREV_BLRP(bp)));
        PUT(HDRP(PREV_BLRP(bp)),PACK(size , 0));
        PUT(FTRP(bp), PACK(size,0));

        bp = PREV_BLRP(bp);
    }

    else if(prev_alloc &amp;amp;&amp;amp; !next_alloc ) {
        size += GET_SIZE( HDRP(NEXT_BLKP(bp)));
        PUT(HDRP(bp), PACK(size,0));
        PUT(FTRP(bp) , PACK(size,0));

    }

    else{
        size += GET_SIZE(HDRP(PREV_BLRP(bp))) + GET_SIZE(HDRP(NEXT_BLKP(bp)));
        PUT( HDRP(PREV_BLRP(bp)) , PACK(size , 0));
        PUT( FTRP(NEXT_BLKP(bp)), PACK(size,0));

        bp = PREV_BLRP(bp);
    }

    return bp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;주석 참고!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;&lt;b&gt;Find_Fit , Place 함수&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;메모리 할당을 도와주는 함수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Find_fit : 사용하기에 알맞은 가용 블록을 찾아 주는 함수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Place : 가용 블록 할당 후 블록의 남은 부분을 다시 가용 블록으로 만들어 주는 함수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650360068&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief The function that searches fit free block, in heap( First-Fit )
 * 
 * @param asize : Demanded size
 * @return void* : Pointer which is pointing fit free block. ( IF there isn't, return nullptr )
 */
char * Mymalloc::find_fit(size_t asize){
    char* bp;

    for(bp = heap ; GET_SIZE(HDRP(bp)) &amp;gt; 0; bp += GET_SIZE(HDRP(bp)) ){
        if(!GET_ALLOC(HDRP(bp)) &amp;amp;&amp;amp; GET_SIZE(HDRP(bp)) &amp;gt;= asize) return bp;
    }

    return NULL;
}


/**
 * @brief The function that put the remaining block back in the heap again, when Free block is too large
 * 
 * @param bp : Pointer which is pointing large free block
 * @param asize : Size of large free block
 */
void Mymalloc::place(char *bp, size_t asize){

    size_t csize = GET_SIZE(HDRP(bp));

    if((csize - asize) &amp;gt;= 2 * DSIZE){
        PUT(HDRP(bp) , PACK(asize , 1));
        PUT(FTRP(bp) , PACK(asize , 1));
        
        PUT(HDRP(NEXT_BLKP(bp)),PACK(csize-asize , 0));
        PUT(FTRP(NEXT_BLKP(bp)) , PACK(csize-asize , 0));
    }   
    else{
        PUT(HDRP(bp) , PACK(csize , 1));
        PUT(FTRP(bp) , PACK(csize, 1));
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;&lt;b&gt;Malloc 함수들 ( Malloc , Calloc , Realloc , Free)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;&lt;b&gt;1) init 초기화&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Malloc을 위한 준비&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650411407&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief Heap initalization for allocation
 */
void Mymalloc::mm_init(){
    if( (heap = (char *)mem_sbrk(4 * WSIZE)) == (char* )-1 ) return ;

    PUT(heap , 0);                              // Padding
    PUT(heap + 1 * WSIZE , PACK(DSIZE , 1));    // Header
    PUT(heap + 2 * WSIZE , PACK(DSIZE , 1));    // Footer
    PUT(heap + 3 * WSIZE , PACK(0,1));          // Last Block
    heap += (2 * WSIZE);                       

    if(extend_heap(CHUNKSIZE / WSIZE) == NULL) return ;

    return ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;2) Malloc&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;Malloc : 메모리 할당&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650437729&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief Malloc Implementation
 * 
 * @param size : Size of allocation
 * @return void* : Pointer which is pointing allocated memory
 */
void * Mymalloc::mm_malloc(size_t size)
{
    size_t asize;
    size_t extendsize;
    char *bp;

    if(size == 0) return NULL;

    // Alignment - Double word ( 8bytes )
    if(size &amp;lt;= DSIZE) asize = 2 * DSIZE;
    else asize = DSIZE + ((size + DSIZE -1) / DSIZE) * DSIZE ;
    
    // Finding Free block
    if((bp = find_fit(asize)) != NULL){
        
        place(bp,asize);
        return bp;
    }

    // If heap size is lack -&amp;gt; extend_heap
    if( (bp = extend_heap(asize / WSIZE)) == NULL) return NULL;
    
    place(bp,asize);
    return (void *)bp;
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;&lt;b&gt;3) Calloc&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #781b33;&quot;&gt;메모리 할당 + 0으로 초기화&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650467515&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief Calloc implementation
 * 
 * @param size : Calloc Size
 * @return void* : Pointer which is pointing Callocated memory
 */
void* Mymalloc::mm_calloc(size_t size)
{

    // Malloc
    char* bp;
    if( (bp = (char *)mm_malloc(size)) == NULL) return NULL;

    
    if(size &amp;lt;= DSIZE) size = DSIZE;
    else size = ((size + (DSIZE-1)) / DSIZE) * DSIZE;
    
    // Initialization to zero
    for(int i = 0 ; i &amp;lt; size ; ++i){
        *(bp+i) = (char)0x0;
    }

    return bp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Malloc을 이용하여 구현 하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Malloc을 해준 뒤 값들을 0으로 초기화 해준 것이 전부이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;4) Realloc&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;할당된 메모리를 재할당 해주는 함수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;의외로 해줄 것이 많다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;주어진 사이즈와 next 블록의 할당 여부에 따라 여러가지 case들이 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;자세한 Case들은 주석에 적어 두었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;주어진 사이즈가 작으면 Decrease&lt;/span&gt;하는 것도 구현 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650496362&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief Realloc implementation
 * 
 * @param bp : Pointer which is pointing allocated memory
 * @param size : Realloc Size
 * @return void* : Pointer which is pointing reallocated memory
 */
void * Mymalloc::mm_realloc(void* bp ,size_t size){
    
    // Can't reallocate
    if(GET_ALLOC(HDRP(bp)) == 0 || size &amp;lt;= 0) return NULL;

    size_t asize = DSIZE + ((size + (DSIZE - 1)) / DSIZE) * DSIZE;
    size_t before_asize = GET_SIZE(HDRP(bp));

    // Size Increasement
    if( asize &amp;gt; before_asize ){
        
        // Case 1
        // Next block is free Block &amp;amp; big enough
        if( GET_ALLOC(HDRP(NEXT_BLKP(bp))) == 0 &amp;amp;&amp;amp; (GET_SIZE(HDRP(NEXT_BLKP(bp))) + before_asize &amp;gt;= asize) ){
            size_t next_size = GET_SIZE(HDRP(NEXT_BLKP(bp)));
            
            if(next_size + before_asize &amp;gt; asize + DSIZE){
                PUT(HDRP(bp) , PACK(asize , 1));
                PUT(FTRP(bp) , PACK(asize , 1));

                PUT(HDRP(NEXT_BLKP(bp)) ,PACK( (next_size + before_asize - asize),0 ) );
                PUT(FTRP(NEXT_BLKP(bp)) , PACK( (next_size + before_asize - asize),0 ) );

                coalesce(NEXT_BLKP(bp));
                
                return bp;
            }
            else{
                PUT(HDRP(bp) , PACK( (next_size + before_asize) , 1));
                PUT(FTRP(bp) , PACK( (next_size + before_asize) , 1));

                return bp;
            }
        }

        // Case 2
        // Finding free block which is big enough
        else{
            char * new_bp;
            mm_free(bp);

            new_bp = (char *)mm_malloc(size);

            for(int i = 0 ; i &amp;lt; ( asize - DSIZE) ; ++i){
                *(new_bp +i) = *((char*)bp+i);
            }

            return new_bp;
        }
    }
    // Size Decreasement
    else if(asize &amp;lt; before_asize){
        
        size_t next_size = before_asize - asize;

        // Case 1
        // Remaining memory is bigger than DSIZE * 2
        
        if(before_asize - asize &amp;gt; DSIZE){

            PUT(HDRP(bp) , PACK(asize , 1));
            PUT(FTRP(bp) , PACK(asize , 1));

            PUT(HDRP(NEXT_BLKP(bp)), PACK(next_size , 0));
            PUT(FTRP(NEXT_BLKP(bp)) , PACK(next_size , 0));

            coalesce(NEXT_BLKP(bp));
            return bp;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt;5) Free&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Deallocation 함수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1658650537620&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief Free Implementation
 * 
 * @param bp : Pointer which is pointing allocated block
 */
void Mymalloc::mm_free(void* bp)
{
    size_t size = GET_SIZE(HDRP(bp));

    PUT(HDRP(bp),PACK(size,0));
    PUT(FTRP(bp),PACK(size,0));
    coalesce((char *)bp);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;여기까지가 Implicit allocator 구현이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;전체 코드는 github에 올려두었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;Github 주소 :&lt;/span&gt;&lt;span&gt; &lt;a href=&quot;https://github.com/ohinhyuk/MCNL-Study/blob/main/%EA%B3%A0%EC%9C%A4%EB%AF%BC%EA%B5%90%EC%88%98%EB%8B%98%20%EC%8A%A4%ED%84%B0%EB%94%94/week%203/Implicit_allocator.cpp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/ohinhyuk/MCNL-Study/blob/main/%EA%B3%A0%EC%9C%A4%EB%AF%BC%EA%B5%90%EC%88%98%EB%8B%98%20%EC%8A%A4%ED%84%B0%EB%94%94/week%203/Implicit_allocator.cpp&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Operating System</category>
      <author>today_me</author>
      <guid isPermaLink="true">https://8156217.tistory.com/53</guid>
      <comments>https://8156217.tistory.com/53#entry53comment</comments>
      <pubDate>Sun, 24 Jul 2022 17:21:05 +0900</pubDate>
    </item>
  </channel>
</rss>