<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Junvely 개발일기</title>
    <link>https://junvelee.tistory.com/</link>
    <description>프론트엔드 개발</description>
    <language>ko</language>
    <pubDate>Thu, 11 Jun 2026 00:59:36 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>junvely</managingEditor>
    <image>
      <title>Junvely 개발일기</title>
      <url>https://tistory1.daumcdn.net/tistory/5269852/attach/cdf6d1af315e404eac499471ae8cddec</url>
      <link>https://junvelee.tistory.com</link>
    </image>
    <item>
      <title>Typescript 앱 생성하기(초기 셋팅 방법)</title>
      <link>https://junvelee.tistory.com/170</link>
      <description>&lt;h3 style=&quot;color: #f8f8f2; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;JS 프로젝트를 TS 프로젝트로 마이그레이션 하기 or TS 템플릿으로 생성하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;gt; 마이그레이션 시 보통 파일을 하나씩 변경한다.&lt;/span&gt;&lt;/div&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1. 직접 react-create-app 마이그레이션 하기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1) 리액트 앱 생성 및 타입 선언 패키지 install&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;
&lt;pre id=&quot;code_1732779266042&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   npx create-react-app .
   npm i @types/node @types/react @types/react-dom @types/jest`&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;2) tsconfig.json 설정하기&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;
&lt;pre id=&quot;code_1732779321263&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ES5&quot;,
    &quot;module&quot;: &quot;CommonJS&quot;,
    &quot;strict&quot;: true,
    &quot;allowJs&quot;: true,
    &quot;esModuleInterop&quot;: true, // 외부 패키지 등에서나 export default가 없어도 기본옵션으로 추가하기
    &quot;jsx&quot;: &quot;react-jsx&quot; // ts는 기본적으로 jsx해석못하기 때문에 추가
  },
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3) 모든 js파일을 jsx 컴포넌트로 변경&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; 타입스크립트의 컴파일러(tsc)가 파일 확장자와 구성 옵션을 통해 코드의 의도를 명확히 구분하기 때문&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; &amp;nbsp;-&amp;gt; .js와 .jsx는 순수 JavaScript 코드로 간주되며, 기본적으로 타입 검사를 최소화하거나 생략한다.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; &amp;nbsp;따라서, .js 파일에서 JSX를 사용하면 타입스크립트는 이를 별도의 설정 없이는 처리하려고 시도하지 않는다.&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;4)&amp;nbsp;개별 파일들 tsx로 하나씩 변경 후 에러를 옵션 등으로 해결하기&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre id=&quot;code_1732779532808&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//index.tsx 에러 
const root = ReactDOM.createRoot(
  document.getElementById(&quot;root&quot;) as HTMLElement // 단언 추가
);
root.render(
  &amp;lt;React.StrictMode&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/React.StrictMode&amp;gt;
);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #f8f8f2; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #f8f8f2; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #f8f8f2; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2. 한 번에 ts 프로젝트 생성하는 방법(ts 템플릿)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;
&lt;pre id=&quot;code_1732779395873&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; npx create-react-app my-app --template typescript
 // 또는 현재 폴더에서 생성하기
 npx create-react-app . --template typescript&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #dddddd;&quot;&gt;&amp;lt;참고&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;color: #f8f8f2; text-align: start;&quot;&gt;
&lt;figure id=&quot;og_1732779412059&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;[React] create-react-app &amp;amp; Typescript  초기 세팅 완벽 정리&quot; data-og-description=&quot;최근에 타입스크립트를 배우고 타입스크립트로 create-react-app을 설정하는데 시간이 많이 걸렸다..그리고 새로 프로젝트를 시작할 때 초기세팅을 완벽하게 하자! 라고 생각을 해서 협업을 할 때 &quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@junghyeonsu/React-create-react-app-Typescript-%EC%B4%88%EA%B8%B0-%EC%84%B8%ED%8C%85-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC&quot; data-og-url=&quot;https://velog.io/@junghyeonsu/React-create-react-app-Typescript-초기-세팅-완벽-정리&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DiGJW/hyXGOGoN3s/Ako1NHGhExDAWzkhV3SI40/img.png?width=800&amp;amp;height=480&amp;amp;face=0_0_800_480,https://scrap.kakaocdn.net/dn/cJE9sN/hyXDmSlHyv/CrskALMz3VRLmeKzng1fMk/img.png?width=800&amp;amp;height=480&amp;amp;face=0_0_800_480,https://scrap.kakaocdn.net/dn/C0okr/hyXDmSlHCR/emVpKl6CaUb7KWjL06fpN1/img.png?width=1200&amp;amp;height=500&amp;amp;face=0_0_1200_500&quot;&gt;&lt;a href=&quot;https://velog.io/@junghyeonsu/React-create-react-app-Typescript-%EC%B4%88%EA%B8%B0-%EC%84%B8%ED%8C%85-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@junghyeonsu/React-create-react-app-Typescript-%EC%B4%88%EA%B8%B0-%EC%84%B8%ED%8C%85-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DiGJW/hyXGOGoN3s/Ako1NHGhExDAWzkhV3SI40/img.png?width=800&amp;amp;height=480&amp;amp;face=0_0_800_480,https://scrap.kakaocdn.net/dn/cJE9sN/hyXDmSlHyv/CrskALMz3VRLmeKzng1fMk/img.png?width=800&amp;amp;height=480&amp;amp;face=0_0_800_480,https://scrap.kakaocdn.net/dn/C0okr/hyXDmSlHCR/emVpKl6CaUb7KWjL06fpN1/img.png?width=1200&amp;amp;height=500&amp;amp;face=0_0_1200_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;[React] create-react-app &amp;amp; Typescript 초기 세팅 완벽 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최근에 타입스크립트를 배우고 타입스크립트로 create-react-app을 설정하는데 시간이 많이 걸렸다..그리고 새로 프로젝트를 시작할 때 초기세팅을 완벽하게 하자! 라고 생각을 해서 협업을 할 때&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&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;/div&gt;</description>
      <category>JavaScript/TypeScript</category>
      <category>타입스크립트</category>
      <category>타입스크립트 마이그레이션</category>
      <category>타입스크립트 셋팅</category>
      <category>타입스크립트 앱 생성 방법</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/170</guid>
      <comments>https://junvelee.tistory.com/170#entry170comment</comments>
      <pubDate>Thu, 28 Nov 2024 16:40:31 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] tsconfig.json 설정 옵션 알아보기</title>
      <link>https://junvelee.tistory.com/169</link>
      <description>&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;br /&gt;&amp;nbsp;1. tsconfig.json&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;tsconfig.json에서는 이렇게 컴파일러 옵션을 설정할 수 있는데, 컴파일 시 얼마나 엄격하게 타입 오류를 검사할지, 자바스크립트 버전을 어떻게 할지 프로젝트에 따라, 개발자의 입맛에 맞춰 설정할 수 있다. tsc --init으로 초기화 하면 tsconfig.json 파일이 기본옵션으로 생성된다.(직접 생성해도 된다)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) &quot;include&quot;&amp;nbsp; : 컴파일할 파일이 많을 경우, 일일히 컴파일 하지 않고 특정 위치 기준으로 아래의 모든 파일을 컴파일하도록 설정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729590234684&quot; class=&quot;json&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;{
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) &quot;compilerOptions&quot; : &quot;target&quot;, &quot;module&quot;, &quot;outDir&quot;, &quot;strict&quot;, &quot;mpduleDetection&quot; 등&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729590234684&quot; class=&quot;bash&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;  {
  &quot;compilerOptions&quot;: {
    &quot;target&quot;: &quot;ES5&quot;, //컴파일 될 자바스크립트 버전 설정 가능
    &quot;module&quot;: &quot;CommonJS&quot;, // 자바스크립트 모듈 시스템 버전을 설정 가능
    &quot;outDir&quot; : &quot;dist&quot;, // 컴파일 될 js파일들을 어디에 위치할지 설정 가능
    &quot;strict&quot;: true, // &quot;엄격한 타입 검사&quot;하도록 지정(매개변수에 타입 지정안하면 오류)
    &quot;strictNullChecks&quot;: false, // null타입을 엄격하게 검사할지 여부(다른 타입에 null 넣을 수 있음)
    				// &quot;strict&quot;의 하위 옵션이기 때문에 해당 옵션이 꺼져있으면 같이 꺼진다.
     &quot;moduleDetection&quot;: &quot;force&quot;, // 타입스크립트의 전역 모듈들을 개별 모듈로 자동 변환
     &quot;skipLibCheck&quot;: true, // @types 버전이 20버전 이상으로 업데이트 되면서 이후 모든 tsconfig.json에옵션 추가
     			위 옵션은 타입 정의 파일(.d.ts 확장자를 갖는 파일)의 타입 검사를 생략하는 옵션.
				보통 타입 정의 파일은 라이브러리에서 사용하는데 가끔 라이브러리의 타입 정의 파일에서 타입 오류가 발생하는 일이 발생할 수 있다.
				따라서 해당 옵션을 true로 설정하셔서 불 필요한 타입 정의 파일의 타입 검사를 생략하도록 설정.
  	 
  },
  &quot;include&quot;: [&quot;src&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;❗ &quot;undici-types&quot; 에러 날 경우 : &quot;skipLibCheck&quot;: true 옵션은 타입 정의 파일(.d.ts 확장자를 갖는 파일)의 타입 검사를 생략하는 옵션. 보통 타입 정의 파일은 라이브러리에서 사용하는데 가끔 라이브러리의 타입 정의 파일에서 타입 오류가 발생하는 일이 발생할 수 있다.따라서 해당 옵션을 true로 설정하셔서 불 필요한 타입 정의 파일의 타입 검사를 생략하도록 설정.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;❗ &quot;moduleDetection&quot; : 자바스크립트에서는 하나의 파일을 독립적 모듈로 취급하지만, 타입스크립트에서는 모든 파일을 전역 모듈로 취급한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;즉 각각 파일에 변수명이 같아도 자바스크립트는 독립된 모듈이라 전혀 상관없지만, 타입스크립트는 동일한 전역 스코프로 취급되어 에러가 발생한다. 이에 2가지 해결방법이 있는데,&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;834&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pFz7T/btsKe8fhI6P/yKwbK6wLW7zXqJf1ifwt11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pFz7T/btsKe8fhI6P/yKwbK6wLW7zXqJf1ifwt11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pFz7T/btsKe8fhI6P/yKwbK6wLW7zXqJf1ifwt11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpFz7T%2FbtsKe8fhI6P%2FyKwbK6wLW7zXqJf1ifwt11%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;508&quot; height=&quot;92&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) 한 파일에 export 또는 import 등 모듈시스템을 1번 이상 강제로 사용 하여 독립된 모듈로 취급한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) tsconfig.json에 &quot;moduleDitection&quot; : &quot;force&quot; 옵션을 추가한다. (에러 안사라지면 ctr+shift+p 로 restart 검색하여 ts 다시 검사) -&amp;gt; 이렇게 하면 컴파된 js파일에 자동으로 export 키워드가 추가시켜 개별 모듈로 변환 것을 확인할 수 있다.&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;242&quot; data-origin-height=&quot;118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbMW0p/btsKfpA7plD/FSL7O4YRLwZI232lpceNHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbMW0p/btsKfpA7plD/FSL7O4YRLwZI232lpceNHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbMW0p/btsKfpA7plD/FSL7O4YRLwZI232lpceNHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbMW0p%2FbtsKfpA7plD%2FFSL7O4YRLwZI232lpceNHk%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;242&quot; height=&quot;118&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;118&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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 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;&lt;span style=&quot;color: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;참고&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 내용은 인프런 이정환 '한입 크기로 잘라먹는 타입스크립트' 강의를 공부하며 작성하였습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>JavaScript/TypeScript</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/169</guid>
      <comments>https://junvelee.tistory.com/169#entry169comment</comments>
      <pubDate>Tue, 22 Oct 2024 18:44:25 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입 스크립트의 필요성과 동작 원리</title>
      <link>https://junvelee.tistory.com/168</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1. 타입 스크립트가 등장하게 된 계기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;자바스크립트는 본래 간단한 프로그래밍을 위해 만들어졌기 때문에 웹 브라우저에서만 작동하고, 유연하게 설계되었다는 장점이 있었다. 하지만 자바스크립트의 인기가 더욱 커지고 Node.js가 등장하게 되면서 웹 브라우저 외의 환경에서도 사용이 가능해졌고 활용도가 높아지면서 더 복잡한 프로그래밍에도 널리 사용이 가능해졌다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2. 자바스크립트의 한계점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) 자바스크립트는 동적 타입 시스템이다. 곧 정적 타입 시스템(자바, c언어)과 달리 변수의 타입들을 런타임 중에 결정한다.(정적 타입 시스템처럼 우리가 직접 타입을 정의하지 않는다. ex.파이썬, 자바스크립트) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) 변수의 타입이 고정적이지 않고 런타임 도중에 변경된다(유연함).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3) 타입으로 인한 오류 발생 시, 정적 타입 시스템같은 경우 실행 전에 이미 검사하여 즉시 실행이 안되지만 동적 타입 시스템인 자바스크립트는 즉시 실행이 멈추지 않고 나중에 갑자기 에러가 나는 등의 문제가 발생한다. &lt;span style=&quot;text-align: start;&quot;&gt;즉 개발자에 의한 타입 실수를 잡아주지 못하여 &lt;span style=&quot;text-align: start;&quot;&gt;나중에 더 큰 문제를 발생시킨다.&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4) 하지만 정적 타입 시스템은 실행 전에 타입 검사를 하여 안정적이라는 장점과 동시에 모든 변수에 타입을 명시해야 하기때문에 타이핑 양이 엄청나다는 단점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;타입 스크립트는 독특한 타입 시스템(점진적 타입 시스템)을 가지고 있다 -&amp;gt; &lt;b&gt;정적 + 동적 타입 시스템의 장점을 모두 가지고 있어 안정적이면서도 유연&lt;/b&gt;하다. 정적 타입 시스템처럼 &lt;b&gt;타입 오류가 나면 알려주기 때문에 안전&lt;/b&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;1852&quot; data-origin-height=&quot;717&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3hgHx/btsKdZcwpaG/hZ0zn82klVcknIjoAwBbrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3hgHx/btsKdZcwpaG/hZ0zn82klVcknIjoAwBbrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3hgHx/btsKdZcwpaG/hZ0zn82klVcknIjoAwBbrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3hgHx%2FbtsKdZcwpaG%2FhZ0zn82klVcknIjoAwBbrk%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;1852&quot; height=&quot;717&quot; data-origin-width=&quot;1852&quot; data-origin-height=&quot;717&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3. 타입스크립트는 어떻게 동작할까?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) 대다수의 프로그래밍 언어는 고급언어에 가깝다. 따라서 사람이 이해하기 쉬운 프로그래밍 언어를 기계어로 변환하는 '컴파일(Compile)을 통해 컴퓨터가 이해할 수 있는 언어로 변환하는 작업을 거쳐야 한다. 컴파일된 언어 = 바이트 코드&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;1529&quot; data-origin-height=&quot;926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU2tS4/btsKeWZ9Ywi/8A0Ak5uayK8UczZ1orv5IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU2tS4/btsKeWZ9Ywi/8A0Ak5uayK8UczZ1orv5IK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU2tS4/btsKeWZ9Ywi/8A0Ak5uayK8UczZ1orv5IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU2tS4%2FbtsKeWZ9Ywi%2F8A0Ak5uayK8UczZ1orv5IK%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;384&quot; data-origin-width=&quot;1529&quot; data-origin-height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;컴파일 과정은 프로그래밍 언어를 -&amp;gt; AST(추상 문법 트리)구조로 만들고 쪼개어 -&amp;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;1730&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RB1Yl/btsKeWePS4K/fKz2DAYywgQLMH0lZ2JHr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RB1Yl/btsKeWePS4K/fKz2DAYywgQLMH0lZ2JHr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RB1Yl/btsKeWePS4K/fKz2DAYywgQLMH0lZ2JHr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRB1Yl%2FbtsKeWePS4K%2FfKz2DAYywgQLMH0lZ2JHr1%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;557&quot; height=&quot;278&quot; data-origin-width=&quot;1730&quot; data-origin-height=&quot;862&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;1600&quot; data-origin-height=&quot;730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0wEvc/btsKf6ncqqI/0Ic4uAZB6MTIy3fFZjGywk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0wEvc/btsKf6ncqqI/0Ic4uAZB6MTIy3fFZjGywk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0wEvc/btsKf6ncqqI/0Ic4uAZB6MTIy3fFZjGywk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0wEvc%2FbtsKf6ncqqI%2F0Ic4uAZB6MTIy3fFZjGywk%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;555&quot; height=&quot;253&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;730&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) 하지만 타입 스크립트의 경우 AST로 변환하고, AST를 보고 &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;1835&quot; data-origin-height=&quot;1011&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjCSgZ/btsKeVmGORn/uDAPWF70p2XesOWrCaUAPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjCSgZ/btsKeVmGORn/uDAPWF70p2XesOWrCaUAPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjCSgZ/btsKeVmGORn/uDAPWF70p2XesOWrCaUAPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjCSgZ%2FbtsKeVmGORn%2FuDAPWF70p2XesOWrCaUAPk%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;564&quot; height=&quot;311&quot; data-origin-width=&quot;1835&quot; data-origin-height=&quot;1011&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이렇게 컴파일된 자바스크립트 코드를 웹 브라우저나 Node.js환경에서 실행하면, 다시 한번 컴파일 과정을 거쳐 바이트 코드로 변환&lt;/b&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;1782&quot; data-origin-height=&quot;761&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kTkkg/btsKeXrisVQ/Sw54vizfmkgjBsoBSK7O91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kTkkg/btsKeXrisVQ/Sw54vizfmkgjBsoBSK7O91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kTkkg/btsKeXrisVQ/Sw54vizfmkgjBsoBSK7O91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkTkkg%2FbtsKeXrisVQ%2FSw54vizfmkgjBsoBSK7O91%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;555&quot; height=&quot;237&quot; data-origin-width=&quot;1782&quot; data-origin-height=&quot;761&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;+ 컴파일과 인터프리터&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;브라우저에서 실행되던 &lt;u&gt;자바스크립트는 전통적으로 컴파일이 필요없는 대표적인 인터프리터(interpreter) 언어&lt;/u&gt;였는데요. 브라우저나 Node.js는 우리가 작성한 자바스크립트 코드를 있는 그대로 이해하고 바로 실행할 수 있기 때문입니다.&lt;br /&gt;&lt;span style=&quot;text-align: left;&quot;&gt;컴파일(compile)은 소스 코드를 특정 플렛폼에서 실행 가능한 형태로 변환하는 과정을 의미하는데요. 기존에는 C++나 Java와 같이 자체 타입 시스템을 가진 프로그래밍 언어에서 주로 다뤄지던 개념이었으나, 타입스크립트의 등장 이후로는 자바스크립트에서도 컴파일이라는 용어를 심심치 않게 들을 수 있게 되었습니다.&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;자바스크립트 대신에 &lt;u&gt;타입스크립트로 코드를 작성하는 것이 보편화됨에 따라&lt;/u&gt; 이제 많은 자바스크립트 프로젝트에서 &lt;u&gt;컴파일 과정이 필요하게 되었습니다. 브라우저는 적어도 아직까지는 타입스크립트 코드를 있는 처리할 수가 없기 때문&lt;/u&gt;인데요. 따라서 개발 단계에서는 타입스크립트로 코드를 작성하지만, 배포할 때는 반드시 코드를 자바스크립트로 변환해줘야 하죠.&lt;/span&gt;&lt;/blockquote&gt;
&lt;figure id=&quot;og_1729581233611&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;타입스크립트 컴파일러 사용법 (tsc 커맨드)&quot; data-og-description=&quot;Engineering Blog by Dale Seo&quot; data-og-host=&quot;www.daleseo.com&quot; data-og-source-url=&quot;https://www.daleseo.com/tsc/&quot; data-og-url=&quot;https://www.daleseo.com/tsc/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cwQk1D/hyXlWS9PmX/Q58sWllKt9tvWKdqOvQlo1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.daleseo.com/tsc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.daleseo.com/tsc/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cwQk1D/hyXlWS9PmX/Q58sWllKt9tvWKdqOvQlo1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;타입스크립트 컴파일러 사용법 (tsc 커맨드)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Engineering Blog by Dale Seo&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.daleseo.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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3. Node.js환경에서 typescript 실행 해보기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1. npm init 하여 패키지 환경 셋팅&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;node에서 사용하는 문법의 타입들을 설치&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;typescript 컴파일러 전역으로 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729582490169&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm init
npm i @types/node
npm install typescript -g&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4. 설치가 잘 됐는지 tsc(타입컴파일러) 버전 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729582639322&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tsc -v&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;5. index.ts 작성 후 tsc로 컴파일 해보기&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729582671406&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//index.ts파일 작성
console.log(&quot;hello typescript&quot;);
const a: number = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1729582703833&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 컴파일 하기 -&amp;gt; 컴파일된 자바스크립트 파일 생성됨
tsc src/index.ts&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;6. 컴파일된 자바스크립트 파일 생성됨 확인, index.js에서는 타입이 모두 사라짐 확인&lt;/span&gt;&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/dYMjSx/btsKerzXciL/SIkJv5rJFNKwkMKGV9hA0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYMjSx/btsKerzXciL/SIkJv5rJFNKwkMKGV9hA0k/img.png&quot; data-origin-width=&quot;181&quot; data-origin-height=&quot;66&quot; data-is-animation=&quot;false&quot; width=&quot;151&quot; height=&quot;55&quot; style=&quot;width: 30.9041%; margin-right: 10px;&quot; data-widthpercent=&quot;31.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYMjSx/btsKerzXciL/SIkJv5rJFNKwkMKGV9hA0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYMjSx%2FbtsKerzXciL%2FSIkJv5rJFNKwkMKGV9hA0k%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;181&quot; height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNTbqu/btsKeIH4Ksg/BFNk9jHhrjkdd5Zppc7xYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNTbqu/btsKeIH4Ksg/BFNk9jHhrjkdd5Zppc7xYk/img.png&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;141&quot; data-is-animation=&quot;false&quot; width=&quot;434&quot; style=&quot;width: 67.9331%;&quot; data-widthpercent=&quot;68.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNTbqu/btsKeIH4Ksg/BFNk9jHhrjkdd5Zppc7xYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNTbqu%2FbtsKeIH4Ksg%2FBFNk9jHhrjkdd5Zppc7xYk%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;850&quot; height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- node에서 컴파일된 자바스크립트 코드 정상 실행됨 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729584108187&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node src/index.js&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;158&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b36nNG/btsKeT3x8sy/h22xGzP1LNznzDG7icPJh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b36nNG/btsKeT3x8sy/h22xGzP1LNznzDG7icPJh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b36nNG/btsKeT3x8sy/h22xGzP1LNznzDG7icPJh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb36nNG%2FbtsKeT3x8sy%2Fh22xGzP1LNznzDG7icPJh0%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;158&quot; height=&quot;69&quot; data-origin-width=&quot;158&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;하지만 &lt;b&gt;일일히 개발중에 tsc로 매번 컴파일, node로 확인할 수 없으니 ts-node 설치(ts를 즉시 실행까지 한번에 가능한 패키지다)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729583349913&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install ts-node -g
ts-node src/index.ts //실행 했더니 에러 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;❗ts-node실행 시 에러 발생 : Warning: To load an ES module, set &quot;type&quot;: &quot;module&quot; in the package.json or use the .mjs extension.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;ES모듈을 사용하려면 package.json에 &quot;type&quot;: &quot;module&quot;을 추가 했더니 &lt;span style=&quot;text-align: start;&quot;&gt;.ts 파일을 실행 못한다는 &lt;/span&gt;또 다른 에러 발생.. 다시 제거하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;현재 자바스크립트 생태계에서는 여러 종류의 모듈 시스템이 공존하고 있다.&lt;/span&gt; Node.js와 ts-node에서는 CommonJS모듈을 사용하는 것과 같이 &lt;/span&gt;컴파일 시 module 종류를 지정하여 맞춰주어야 하는 문제 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;-&amp;gt; 결론 : &lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;u&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;Node.js가 CommonJS을 지원하기 때문에&amp;nbsp;&lt;/span&gt;&lt;/b&gt;ts-node를 사용할 때에 tsconfig.json 파일에 컴파일러옵션에 &quot;module&quot;: &quot;CommonJS&quot;를 사용해야 한다. &lt;/u&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;b&gt;tsconfig.json 파일 생성 후, 컴파일러 옵션에서 &quot;module&quot; : &quot;CommonJS&quot; 를 설정해주니 정상 작동&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729584220842&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// tsconfig.json 파일 생성
{
  &quot;compilerOptions&quot;: {
    &quot;preserveValueImports&quot;: false,
    &quot;module&quot;: &quot;CommonJS&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;❗ 하지만 &lt;span style=&quot;text-align: start;&quot;&gt;컴파일된 코드를 Node.js의 구식 버전과 같이 CommonJS를 모듈 시스템으로 사용하는 실행 환경에서 돌릴 게 아니라면, 표준으로 자라잡고 있는 ES 모듈의 문법을 사용해서 컴파일해야 할 것이다. 이럴 경우 &quot;module&quot; 옵션을 &quot;es6&quot;으로 지정해주면 된다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729585021995&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;compilerOptions&quot;: {
    &quot;preserveValueImports&quot;: false,
    &quot;module&quot;: &quot;es6&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;ts-node 정상 작동 확인!&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;183&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GQUfA/btsKfyxTR6p/GndT7h3f253LX7JqXHPWGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GQUfA/btsKfyxTR6p/GndT7h3f253LX7JqXHPWGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GQUfA/btsKfyxTR6p/GndT7h3f253LX7JqXHPWGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGQUfA%2FbtsKfyxTR6p%2FGndT7h3f253LX7JqXHPWGk%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;183&quot; height=&quot;57&quot; data-origin-width=&quot;183&quot; data-origin-height=&quot;57&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;하지만 이렇게 잘 되다가도 또 .ts에러가 나는 경우가 발생했다....&amp;nbsp;&lt;span style=&quot;text-align: start;&quot;&gt;ts-node는 Node 20 버전 이상에서는 더 이상 동작하지 않는다고 한다. 따라서&lt;/span&gt;&amp;nbsp;ts-node 대신 tsx를 사용을 권장한다.&amp;nbsp;&lt;span style=&quot;text-align: start;&quot;&gt;tsx는 단 한번의 명령어로 타입스크립트 코드를 실행시켜주는 도구다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729588783505&quot; class=&quot;properties&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;npm i -g tsx
tsx src/index.ts&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;-&amp;gt; 사실 tsc로 컴파일을 실행할 때 아래와 같이 module 옵션을 지정해 줄 수 있는데, 매번 일일히 tsc로 모듈 지정하여 실행할 수는 없고 옵션들이 많아질 수록 작성이 길어지게 되니 tsconfig 파일에서 여러가지 옵션들을 설정해 놓면 편리하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729585265937&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx tsc --module es6 index.ts&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;다음 글에서는 tsconfig.json 옵션에 대해 간단히 알아보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729590296062&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;tsconfig.json 설정 옵션 알아보기&quot; data-og-description=&quot;1. tsconfig.jsontsconfig.json에서는 이렇게 컴파일러 옵션을 설정할 수 있는데, 컴파일 시 얼마나 엄격하게 타입 오류를 검사할지, 자바스크립트 버전을 어떻게 할지 프로젝트에 따라, 개발자의 입맛&quot; data-og-host=&quot;junvelee.tistory.com&quot; data-og-source-url=&quot;https://junvelee.tistory.com/169&quot; data-og-url=&quot;https://junvelee.tistory.com/169&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bU6JDJ/hyXlOVcbTS/OedBkJmaMAjoKz85mvA1iK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bMuR5U/hyXlScbXly/glzYWGSKk4SA93EytFOOp0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://junvelee.tistory.com/169&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://junvelee.tistory.com/169&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bU6JDJ/hyXlOVcbTS/OedBkJmaMAjoKz85mvA1iK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bMuR5U/hyXlScbXly/glzYWGSKk4SA93EytFOOp0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&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;tsconfig.json 설정 옵션 알아보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. tsconfig.jsontsconfig.json에서는 이렇게 컴파일러 옵션을 설정할 수 있는데, 컴파일 시 얼마나 엄격하게 타입 오류를 검사할지, 자바스크립트 버전을 어떻게 할지 프로젝트에 따라, 개발자의 입맛&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;junvelee.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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&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: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;참고&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 내용은 인프런 이정환 '한입 크기로 잘라먹는 타입스크립트' 강의를 공부하며 작성하였습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>JavaScript/TypeScript</category>
      <category>타입스크립트</category>
      <category>타입스크립트 동작 원리</category>
      <category>타입스크립트 필요성</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/168</guid>
      <comments>https://junvelee.tistory.com/168#entry168comment</comments>
      <pubDate>Tue, 22 Oct 2024 16:11:06 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] App 디렉토리에서 route handlers로 API 구현하기 - Vercel Postgres + Prisma 풀스택 구현</title>
      <link>https://junvelee.tistory.com/167</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;[Next.js]&amp;nbsp;App&amp;nbsp;디렉토리에서&amp;nbsp;route&amp;nbsp;handlers로&amp;nbsp;API&amp;nbsp;구현하기&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;-&amp;nbsp;Vercel&amp;nbsp;Postgres&amp;nbsp;+&amp;nbsp;Prisma&amp;nbsp;풀스택&amp;nbsp;구현&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;1. Vercel Postgres 데이터베이스 설정&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;1. postgres와 vercel 설치&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710863401502&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @vercel/postgres
npm install -g vercel@latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2. vercel에 프로젝트 배포 후 strorage에서 DB 생성(가까운 나라로) -&amp;gt; 프로젝트 연결(Connect Project) 확인(프로젝트명 맞는지 꼭 확인)&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;984&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vHxNK/btsFW7X6fhq/YBobFgLI8KEcKhyPR4hgV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vHxNK/btsFW7X6fhq/YBobFgLI8KEcKhyPR4hgV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vHxNK/btsFW7X6fhq/YBobFgLI8KEcKhyPR4hgV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvHxNK%2FbtsFW7X6fhq%2FYBobFgLI8KEcKhyPR4hgV1%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;984&quot; height=&quot;214&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. vscode 터미널에서 vercel 연결&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710863638511&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vercel link&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5. DB의 &lt;span style=&quot;text-align: start;&quot;&gt;.env.local에 있는 키들을&amp;nbsp; .env파일에 옮겨오는 작업 / 옮겨지지 않을 경우 수동으로 복사해서 붙여넣으면 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710863763542&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vercel env pull .env&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;955&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3tNlD/btsFWIxqVxg/xqR81t73HuJvU27xq41c90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3tNlD/btsFWIxqVxg/xqR81t73HuJvU27xq41c90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3tNlD/btsFWIxqVxg/xqR81t73HuJvU27xq41c90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3tNlD%2FbtsFWIxqVxg%2FxqR81t73HuJvU27xq41c90%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;667&quot; height=&quot;207&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;297&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;6. Next api 생성하여 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; postgres가 잘 연결됐는지 확인해 보기&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;나는 app 디렉토리로 구성하여 app/api/movie/route.ts 파일에 route handlers&lt;span style=&quot;text-align: start;&quot;&gt;(공식문서 참조)&lt;/span&gt;로 api를 생성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;page 디렉토리라면 pages/api/movie.ts 파일에 api routes&lt;span style=&quot;text-align: start;&quot;&gt;(공식문서 참조)&lt;/span&gt;로 api를 생성하면 될 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710844092739&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { sql } from '@vercel/postgres';
import { NextResponse } from 'next/server';
 
export async function GET(request: Request) {
  try {
    const result =
      await sql`CREATE TABLE Pets ( Name varchar(255), Owner varchar(255) );`;
    return NextResponse.json({ result }, { status: 200 });
  } catch (error) {
    return NextResponse.json({ error }, { status: 500 });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;api 주소에서 다음과 같이 나오는지 확인해 보자 -&amp;gt; ex) http://localhost:3000/api/movie&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710844115521&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;result&quot;: {
  &quot;command&quot;: &quot;CREATE&quot;,
  &quot;fields&quot;: [],
  &quot;rowAsArray&quot;: false,
  &quot;rowCount&quot;: null,
  &quot;rows&quot;: [],
  &quot;viaNeonFetch&quot;: true
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;7. 데이터베이스 샘플 테이블 추가해보기&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710844145485&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { sql } from '@vercel/postgres';
import { NextResponse } from 'next/server';
 
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const petName = searchParams.get('petName');
  const ownerName = searchParams.get('ownerName');
 
  try {
    if (!petName || !ownerName) throw new Error('Pet and owner names required');
    await sql`INSERT INTO Pets (Name, Owner) VALUES (${petName}, ${ownerName});`;
  } catch (error) {
    return NextResponse.json({ error }, { status: 500 });
  }
 
  const pets = await sql`SELECT * FROM Pets;`;
  return NextResponse.json({ pets }, { status: 200 });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;api 주소에서 다음과 같이 나오는지 확인해 보자 -&amp;gt; ex)&amp;nbsp;http://localhost:3000/api/movie&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710844158966&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  pets: {
    command: &quot;SELECT&quot;,
    fields: [
      {
        columnID: 1,
        dataTypeID: 1043,
        dataTypeModifier: 259,
        dataTypeSize: -1,
        format: &quot;text&quot;,
        name: &quot;name&quot;,
        tableID: 12345,
      },
      {
        columnID: 2,
        dataTypeID: 1043,
        dataTypeModifier: 259,
        dataTypeSize: -1,
        format: &quot;text&quot;,
        name: &quot;owner&quot;,
        tableID: 12345,
      },
    ],
    rowCount: 1,
    rows: [
      {
        name: &quot;Fluffy&quot;,
        owner: &quot;John&quot;,
      },
    ],
    viaNeonFetch: true,
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;u&gt;&lt;b&gt;2. Prisma 설정 및 데이터베이스 스키마 생성&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1. Prisma 설치 및 초기화&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710863231414&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install prisma --save-dev
npx prisma init&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2.&amp;nbsp;prisma/schema.prisma 파일에서 db의 env키가 맞는지 확인 및 샘플 스키마 생성&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;vscode에서 활성화 안된 것 같이 코드에 불이 안들어와도 당황하지 말기....작동은 되고 있다..&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710862822479&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// schema.prisma

generator client {
  provider = &quot;prisma-client-js&quot;
}

datasource db {
  provider = &quot;postgresql&quot;
  url = env(&quot;POSTGRES_PRISMA_URL&quot;) // uses connection pooling
  directUrl = env(&quot;POSTGRES_URL_NON_POOLING&quot;) // uses a direct connection
}

model Post {
  id        String     @default(cuid()) @id
  title     String
  content   String?
  published Boolean @default(false)
  author    User?   @relation(fields: [authorId], references: [id])
  authorId  String?
}

model User {
  id            String       @default(cuid()) @id
  name          String?
  email         String?   @unique
  createdAt     DateTime  @default(now()) @map(name: &quot;created_at&quot;)
  updatedAt     DateTime  @updatedAt @map(name: &quot;updated_at&quot;)
  posts         Post[]
  @@map(name: &quot;users&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3. Prisma 스키마를 기반으로 vercel 데이터베이스에 테이블 생성&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710862890296&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx prisma db push Prisma&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;실행하면 다음과 같은 질문을 한다. 이미 앞에 테스트 했던 데이터베이스 테이블이 존재하여 삭제를 진행해도 되냐는 말이었다. y를 입력한다.&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;523&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ByeQQ/btsFTZtYfYI/GJN3UFzKQQy66YkBB58EYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ByeQQ/btsFTZtYfYI/GJN3UFzKQQy66YkBB58EYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ByeQQ/btsFTZtYfYI/GJN3UFzKQQy66YkBB58EYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FByeQQ%2FbtsFTZtYfYI%2FGJN3UFzKQQy66YkBB58EYK%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;437&quot; height=&quot;102&quot; data-origin-width=&quot;523&quot; data-origin-height=&quot;122&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;완료가 되면 vercel의 storage의 data탭에 들어가 보면 prisma에서 생성한 스키마로 데이터 Post와 User 테이블이 추가된 것을 확인할 수 있다.&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;733&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U0QPu/btsFTYohhgJ/tgctWY2ThCDdNf8AKkiKVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U0QPu/btsFTYohhgJ/tgctWY2ThCDdNf8AKkiKVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U0QPu/btsFTYohhgJ/tgctWY2ThCDdNf8AKkiKVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU0QPu%2FbtsFTYohhgJ%2FtgctWY2ThCDdNf8AKkiKVK%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;470&quot; height=&quot;185&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;289&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;+ Prisma Studio를 사용하여 초기 데이터를 추가할 수 있다...!&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710864320987&quot; class=&quot;ebnf&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;npx prisma studio&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;1019&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QWOt3/btsFR3jjszJ/eGYlgvO8ZNqGtvGOYvdLj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QWOt3/btsFR3jjszJ/eGYlgvO8ZNqGtvGOYvdLj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QWOt3/btsFR3jjszJ/eGYlgvO8ZNqGtvGOYvdLj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQWOt3%2FbtsFR3jjszJ%2FeGYlgvO8ZNqGtvGOYvdLj0%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;1019&quot; height=&quot;217&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;3. Prisma 클라이언트 설치 및 생성&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. Prisma를 사용하여 Next.js에서 데이터베이스에 액세스하려면 Prisma Client를 설치해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710864491941&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @prisma/client&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;+ 만약 Prisma 스키마 파일이 변경될 경우, 다음 명령어로 prisma를 재생성 해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710864516619&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx prisma generate&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 루트 디렉토리에서 lib폴더 내부에 prisma.ts 파일을 생성한다. -&amp;gt; PrismaClient 인스턴스를 생성한다. -&amp;gt; lib/prisma.ts&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710864724246&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { PrismaClient } from '@prisma/client';

let prisma: PrismaClient;

if (process.env.NODE_ENV === 'production') {
  prisma = new PrismaClient();
} else {
  if (!global.prisma) {
    global.prisma = new PrismaClient();
  }
  prisma = global.prisma;
}

export default prisma;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이렇게 하면 DB에 연결 할 때 마다 &lt;span style=&quot;text-align: start;&quot;&gt;Prisma Client에 연결하여 &lt;/span&gt;prisma 인스턴스를 사용할 수 있게 된다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4. 이제 드디어 Prisma를 사용하여 간단하게 데이터베이스에 연결해 보자!&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710865884029&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NextResponse } from &quot;next/server&quot;;
import prisma from &quot;../../../lib/db&quot;;

export async function GET(request: Request) {
  try {
    const data = await prisma.user.findMany(); // user의 모든 결과 가져오기
    return Response.json({ data }, { status: 200 });
  } catch (e) {
    return NextResponse.json({ message: &quot;fail&quot; }, { status: 500 });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;감격스럽게도 내가 설정한 api주소에서(&lt;span style=&quot;text-align: start;&quot;&gt;http://localhost:3000/api/movie &lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;방금 업데이트한(&lt;span style=&quot;text-align: start;&quot;&gt;Prisma Studio에서 &lt;/span&gt;)따끈따끈한 user 데이터를 확인할 수 있었다&lt;span style=&quot;text-align: start;&quot;&gt;.....❗&lt;/span&gt;&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;409&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nAZZq/btsFUq5RpsO/h4Rk0N9uFZICvNKOqTQ8FK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nAZZq/btsFUq5RpsO/h4Rk0N9uFZICvNKOqTQ8FK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nAZZq/btsFUq5RpsO/h4Rk0N9uFZICvNKOqTQ8FK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnAZZq%2FbtsFUq5RpsO%2Fh4Rk0N9uFZICvNKOqTQ8FK%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;409&quot; height=&quot;246&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;246&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;오늘은 여기까지...... &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;다음 Prisma 공식문서에서 CRUD관련 메소드를 확인해 보자..!&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710866690903&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;Querying the database : typescript-postgresql&quot; data-og-description=&quot;Write data to and query the database&quot; data-og-host=&quot;www.prisma.io&quot; data-og-source-url=&quot;https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/querying-the-database-typescript-postgresql#write-your-first-query-with-prisma-client&quot; data-og-url=&quot;https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/querying-the-database-typescript-postgresql&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eBYhi/hyVDIuGoqu/DyCrQMlh3oViQr5b3Nso8k/img.png?width=1200&amp;amp;height=640&amp;amp;face=0_0_1200_640,https://scrap.kakaocdn.net/dn/bdJcgF/hyVAzMV2XB/7GQjGhVWbOkMGo8iYdIC1k/img.png?width=1200&amp;amp;height=640&amp;amp;face=0_0_1200_640&quot;&gt;&lt;a href=&quot;https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/querying-the-database-typescript-postgresql#write-your-first-query-with-prisma-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.prisma.io/docs/getting-started/setup-prisma/start-from-scratch/relational-databases/querying-the-database-typescript-postgresql#write-your-first-query-with-prisma-client&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eBYhi/hyVDIuGoqu/DyCrQMlh3oViQr5b3Nso8k/img.png?width=1200&amp;amp;height=640&amp;amp;face=0_0_1200_640,https://scrap.kakaocdn.net/dn/bdJcgF/hyVAzMV2XB/7GQjGhVWbOkMGo8iYdIC1k/img.png?width=1200&amp;amp;height=640&amp;amp;face=0_0_1200_640');&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;Querying the database : typescript-postgresql&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Write data to and query the database&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.prisma.io&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;span style=&quot;color: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&amp;lt;참고&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. Prisma &lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #9d9d9d; text-align: start;&quot;&gt;연결&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710866716211&quot; style=&quot;color: #333333; text-align: start;&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bCEB7J/hyVALzM5kV/Z32NA4dwmpoB4oBLQv3350/img.png?width=1600&amp;amp;height=900&amp;amp;face=0_0_1600_900,https://scrap.kakaocdn.net/dn/dfLTDO/hyVAIC3MDK/hOkkYD5031o3icchmUt1sK/img.png?width=1600&amp;amp;height=900&amp;amp;face=0_0_1600_900&quot; data-og-url=&quot;https://vercel.com/login&quot; data-og-source-url=&quot;https://vercel.com/junvelys-projects/learn-next-js/stores/postgres/store_aLAbOaUfOu1eX2sw/guides&quot; data-og-host=&quot;vercel.com&quot; data-og-description=&quot;Welcome to Vercel. Log in with GitHub, GitLab, Bitbucket, or email to deploy websites for free with zero configuration, automatic SSL, and global CDN.&quot; data-og-title=&quot;Login &amp;ndash; Vercel&quot; data-og-type=&quot;website&quot; data-ke-align=&quot;alignCenter&quot; data-ke-type=&quot;opengraph&quot;&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1710844184969&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;How to Build a Fullstack App with Next.js, Prisma, &amp;amp; PostgreSQL&quot; data-og-description=&quot;Learn how to create and deploy a fullstack application with Next.js, Prisma, PostgreSQL, and Vercel.&quot; data-og-host=&quot;vercel.com&quot; data-og-source-url=&quot;https://vercel.com/guides/nextjs-prisma-postgres#step-3-setup-prisma-and-create-the-database-schema&quot; data-og-url=&quot;https://vercel.com/guides/nextjs-prisma-postgres#step-3-setup-prisma-and-create-the-database-schema&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b94FIb/hyVAGypRSa/ayQFQwZ4fmmqO1doTkLMy1/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441,https://scrap.kakaocdn.net/dn/gPJaG/hyVDFdATZp/c8iIXq1q8Mrjd0my5P5ML1/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441,https://scrap.kakaocdn.net/dn/dRKoB1/hyVAIpsZVW/t4jIbi2P9nihepXUTPmeV0/img.png?width=2880&amp;amp;height=1800&amp;amp;face=0_0_2880_1800&quot;&gt;&lt;a href=&quot;https://vercel.com/guides/nextjs-prisma-postgres#step-3-setup-prisma-and-create-the-database-schema&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://vercel.com/guides/nextjs-prisma-postgres#step-3-setup-prisma-and-create-the-database-schema&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b94FIb/hyVAGypRSa/ayQFQwZ4fmmqO1doTkLMy1/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441,https://scrap.kakaocdn.net/dn/gPJaG/hyVDFdATZp/c8iIXq1q8Mrjd0my5P5ML1/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441,https://scrap.kakaocdn.net/dn/dRKoB1/hyVAIpsZVW/t4jIbi2P9nihepXUTPmeV0/img.png?width=2880&amp;amp;height=1800&amp;amp;face=0_0_2880_1800');&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;How to Build a Fullstack App with Next.js, Prisma, &amp;amp; PostgreSQL&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn how to create and deploy a fullstack application with Next.js, Prisma, PostgreSQL, and Vercel.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;vercel.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>JavaScript/Next.js</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/167</guid>
      <comments>https://junvelee.tistory.com/167#entry167comment</comments>
      <pubDate>Wed, 20 Mar 2024 01:46:28 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] CSR의 Link 태그의 원리, Link와 useRouter의 차이점</title>
      <link>https://junvelee.tistory.com/166</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;[Next.js]&amp;nbsp;CSR의&amp;nbsp;Link&amp;nbsp;태그의&amp;nbsp;원리,&amp;nbsp;Link와&amp;nbsp;useRouter의&amp;nbsp;차이점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1. CSR의 Link 태그의 원리&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;❓내가 궁금했던 부분 1 :&lt;/b&gt; Link태그를 사용하여 페이지 이동을 설정해놓을 경우 브라우저에서 소스 코드로 확인해 보면 &amp;lt;a&amp;gt;태그로 변환되어 있다. 이는 Link태그 내부에 &amp;lt;a&amp;gt;태그가 내장되어 있기 때문인데, 그렇다면 변환된 것은 &amp;lt;a&amp;gt;태그이므로 사용자가 클릭 했을 때에 새로고침이 일어나야 하는 것이 아닌가? 어떻게 부드러운 사용성을 유지할 수 있는가? 문득 궁금했다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Next.js의 Link 컴포넌트를 사용하면 서버에서 받은 HTML에서는 &amp;lt;a&amp;gt; 태그로 변환되어 있으므로 기본적으로는 클릭 시 새로고침이 발생합니다.그러나 사용자의 브라우저가 JavaScript를 실행할 수 있고, JavaScript가 활성화되어 있는 경우에는 다음과 같은 과정으로 부드러운 화면 전환을 경험하게 됩니다:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 사용자가 Link 컴포넌트를 클릭합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 브라우저는 JavaScript를 실행하고, 클라이언트 측 라우팅 메커니즘이 활성화됩니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 클라이언트 측 라우팅은 새로운 페이지의 필요한 컴포넌트 및 데이터를 로드합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4. 화면이 부드럽게 전환되면서 새로운 페이지가 렌더링됩니다. 이 과정에서는 전체 페이지를 새로 렌더링하는 것이 아니라 필요한 부분만 업데이트됩니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5. 사용자는 새로운 페이지로 이동한 것처럼 보이지만, 실제로는 전체 페이지의 새로고침 없이 부드럽게 화면이 전환됩니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 과정을 통해 사용자는 페이지 전환 시에 부드러운 경험을 할 수 있습니다. 이는 클라이언트 측 라우팅을 활용하여 페이지 간 전환을 빠르고 부드럽게 만드는 원리입니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;내가 이해하기로는, Next.js와 같은 서버 사이드 렌더링에서는 서버로부터 렌더링된 HTML 문서를 받게 된다. &lt;span style=&quot;text-align: start;&quot;&gt;서버에서 받는 HTML에서는 Link가 a태그로 변화되어 클릭시 새로고침이 일어나야 하지만, 실제로 사용자가 클릭할 때 js가 켜져있다면 새로고침을 하지 않고 페이지는 유지하면서 내부 컴포넌트를 교체해주는 식으로 화면을 부드럽게 전환되는 것처럼 보이게 하는 것 같다. 또 js가 일어나지 않는 상황에서도 페이지는 이동되어야 하기 때문에 그런 경우에는 a태그를 통해 페이지를 새로고침 하는 것으로 보인다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt; &lt;b&gt;❓내가 궁금했던 부분 2 :&lt;/b&gt;&lt;span style=&quot;text-align: start;&quot;&gt; Next.js 13 버전 부터는 서버 컴포넌트와 클라이언트 컴포넌트를 선택적으로 사용 가능하고, 클라이언트 컴포넌트에 한해서만 hydration이 일어나 CSR을 하는 것으로 알고 있다. 클라이언트 컴포넌트로 사용하기 위해서는 &quot;use client&quot;를 반드시 선언해 주어야 한다고 알고있다. 하지만 Link태그 같은 경우 &quot;use client&quot;를 사용하지 않아도 에러가 발생하지 않는다. 클라이언트 컴포넌트로 선언도 하지 않았는데 &lt;span style=&quot;text-align: start;&quot;&gt;어떻게 자동적으로&lt;/span&gt; Link를 사용하면 CSR 방식으로 페이지 이동이 가능한 것일까?&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;컴포넌트 모듈에 'use client' 지시어가 포함된 경우 해당 컴포넌트의 사용은 클라이언트 컴포넌트임이 보장됩니다. 하지만 컴포넌트에 'use client' 지시어가 없더라도 클라이언트에서 평가될 수 있습니다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;정적 생성을 사용하는 페이지의 경우 뷰포트의 모든 &amp;lt;Link /&amp;gt; 는 기본적으로 해당 데이터를 포함하여 미리 가져오기됩니다 (초기 또는 스크롤을 통해).&amp;nbsp;서버 렌더링&amp;nbsp;경로에 대한 해당 데이터는 &amp;lt; Link /&amp;gt;를 클릭할 때만 가져옵니다&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&amp;nbsp;- 공식문서 참조 : &lt;a style=&quot;color: #000000;&quot; href=&quot;https://ko.react.dev/reference/react/use-client&quot;&gt;https://ko.react.dev/reference/react/use-client&lt;/a&gt;&amp;nbsp;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;+ Link 컴포넌트는 Server Side Rendering + Client Side Routing이다. Next.js에서 제공하는 클라이언트 사이드 라우팅을 구현하는데 사용되며, 클라이언트 측 라우팅을 위한 컴포넌트이기 때문에, &quot;use client&quot;를 명시적으로 선언하지 않아도 클라이언트에서도 렌더링 된다. Next.js의 Link 컴포넌트가 기본적으로 클라이언트 측 라우팅을 지원하기 때문에 클라이언트 측에서만 동작하도록 설계되어 있기 때문이다.&lt;/span&gt;&lt;br /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 1. Link 컴포넌트의 자동 클라이언트 측 렌더링: Next.js의 Link 컴포넌트는 자체적으로 클라이언트 측 렌더링을 수행하기 때문에 &quot;use client&quot;를 명시적으로 선언하지 않아도 클라이언트 측에서 렌더링됩니다. 이것은 Link 컴포넌트가 클라이언트 측 라우팅을 지원하기 위해 설계되었기 때문입니다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. JavaScript 번들의 서버 전달: 클라이언트 측 라우팅을 사용하는 경우에도, 서버에서 해당 페이지에 필요한 JavaScript 번들이 클라이언트로 전달됩니다. 이것은 클라이언트 측 라우팅을 위한 JavaScript 코드가 클라이언트로 전달되어야 하기 때문입니다.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. Hydration 작업: Link 컴포넌트를 클릭하면 해당 페이지에 필요한 JavaScript 번들이 클라이언트로부터 다운로드되고 실행되며, 이를 통해 클라이언트 측 라우팅과 Hydration 작업이 수행됩니다. Hydration 작업은 클라이언트에서 미리 렌더링된 HTML과 일치하도록 페이지를 업데이트하는 과정을 의미합니다. &lt;/span&gt;&lt;/p&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2. 'use Client' 동작 원리&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1. React 서버 컴포넌트를 사용하는 앱의 경우, 기본적으로 앱은 서버에서 렌더링 됩니다. 'use client'는 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://ko.react.dev/learn/understanding-your-ui-as-a-tree#the-module-dependency-tree&quot;&gt;모듈 종속성 트리&lt;/a&gt;에 서버-클라이언트 경계를 도입하여 효과적으로 클라이언트 모듈의 하위 트리를 만듭니다. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2. 'use client'&lt;span style=&quot;text-align: center;&quot;&gt;는 React 서버 컴포넌트 앱의 모듈 종속성 트리를 분할하여 &lt;/span&gt;InspirationGenerator.js&lt;span style=&quot;text-align: center;&quot;&gt;와 모든 종속성을 클라이언트-렌더링으로 표시합니다.&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;text-align: left;&quot;&gt;3. 렌더링하는 동안 프레임워크는 루트 컴포넌트를 서버-렌더링하고 &lt;/span&gt;&lt;a style=&quot;color: #000000; text-align: left;&quot; href=&quot;https://ko.react.dev/learn/understanding-your-ui-as-a-tree#the-render-tree&quot;&gt;렌더 트리&lt;/a&gt;&lt;span style=&quot;text-align: left;&quot;&gt;를 통해 계속 진행하여 클라이언트에서 가져온 코드를 평가하지 않습니다. &lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;그런 다음 서버에서 렌더링한 렌더 트리 부분을 클라이언트로 보냅니다. 클라이언트 코드를 다운로드한 클라이언트는 트리의 나머지 부분 렌더링을 완료합니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://ko.react.dev/reference/react/use-client&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식 문서 :&amp;nbsp; 트리를 통해 잘 확인할 수 있으니 한 번 읽어보자&lt;/a&gt;.&amp;nbsp;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;3. Link와&amp;nbsp;useRouter의&amp;nbsp;차이점&lt;/b&gt; &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;가장 큰 차이점은 검색엔진(SEO)인것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Link &lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&amp;lt;a&amp;gt;태그로 변환되기 때문에 검색엔진이 링크를 인식할 수 있으므로 SEO를 보장하면서도 사용자 경험을 개선할 수 있다. -&amp;gt; &lt;b&gt;검색엔진이 indexing처리를 할 때 href속성을 읽어 indexing처리&lt;/b&gt;를 하는데 href가 없으면 검색엔진이 추적을 할 수 없다. &lt;b&gt;href props는 Link태그를 사용할 때 필수로 사용해야하기 때문에 SEO에 유리&lt;/b&gt;하다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt; useRouter&amp;nbsp;&lt;/b&gt; &lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;useRouter는 next.js에서 &quot;함수형식&quot;으로 routing을 해주는 Next.js가 제공하는 라이브러리이다. 크롤러가 링크를 감지하지 못해 SEO가 좋지 않을 수 있다. &lt;span style=&quot;text-align: left;&quot;&gt;페이지를 이동 할 때에 단순히 즉시 페이지를 이동하는 것이 아니라 어떤 비즈니스 로직 등을 수행한 후, 결과 처리로 페이지를 이동 하는 등 함수 형식의 기능을 수행할 때 사용한다. &lt;/span&gt;외부 URL을 사용할 경우 window.location 혹은 a 태그를 사용해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt; + Next.js가 13버전이 release하면서 app routing기능을 추구하고있다. app routing을 사용한다면 useRouter는 next/router가 아닌 next/navigation에서 import하여 사용하여야 한다.&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;결론&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; Next.js의 Link 컴포넌트는 자체적으로 클라이언트 측 렌더링을 수행하기 때문에 &quot;use client&quot;를 명시적으로 선언하지 않아도 클라이언트 측에서 렌더링된다. 이것은 Link 컴포넌트가 클라이언트 측 라우팅을 지원하기 위해 설계되었기 때문이다. 클라이언트 사이드 라우팅과 &lt;span style=&quot;background-color: #fcfcfc; text-align: left;&quot;&gt;클라이언트 사이드 렌더링, &lt;/span&gt;클라이언트 컴포넌트와의 관계성이 모두 같아야 한다고 생각해서 계속 고민했던 것 같다. &lt;u&gt;'서버 사이드 렌더링이면서, 클라이언트 사이드 라우팅을 사용하는 Next.js는 서버 컴포넌트에서도 클라이언트 사이드 렌더링이 가능하다'가 결론이다. 굳이 클라이언트 컴포넌트가 아니어도 가능하다 = 'use client'를 사용할 필요가 없다는 것이다.&amp;nbsp;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;또 React의 Link 태그와 Next.js의 Link 태그가 다른 점은 React는 클라이언트 사이드 렌더링, 클라이언트 컴포넌트 이기 때문에 서버사이드 렌더링을 하기 위해선 별도 구현이 필요하다는 점, Next.js에서는 prefetch와 같이 React의 기능을 확장하고 더 많은 기능을 제공한다는 점이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;되도록이면 SEO를 위해 Link태그를 사용하는 것을 권장한다. 하지만 페이지를 즉시 이동하는 것이 아니라 어떤 로직을 수행 후에 이동해야 한다면 useRouter를 사용하면 될 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JavaScript/Next.js</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/166</guid>
      <comments>https://junvelee.tistory.com/166#entry166comment</comments>
      <pubDate>Mon, 18 Mar 2024 13:59:14 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Data fetching하기, Loading 및 Error Handling</title>
      <link>https://junvelee.tistory.com/165</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;Next.js 13이후 Data를 fetching하는 방법&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;1. 기존 React에서 컴포넌트에서 Data를 fetching하는 방법(클라이언트 컴포넌트 형식)&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1710605179966&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;use client&quot;;
import { useEffect, useState } from &quot;react&quot;;

// export const metadata = {
//   title: &quot;Home&quot;,
// }; // 클라이언트 컴포넌트에서는 meta data 사용불가

export default function Page() {
  const [movies, setMovies] = useState([]);
  const [isLoading, setisLoading] = useState(true);

  const getMovies = async () =&amp;gt; {
    const res = await fetch(
      &quot;https://nomad-movies.nomadcoders.workers.dev/movies&quot;
    );
    const json = await res.json();
    setMovies(json);
    setisLoading(false);
  };

  useEffect(() =&amp;gt; {
    getMovies();
  }, []);
  return (
    &amp;lt;&amp;gt;
      &amp;lt;div&amp;gt;{isLoading ? &quot;Loading... &quot; : JSON.stringify(movies)}&amp;lt;/div&amp;gt; // 또는 usequery 등으로 로딩 상태 관리
     
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;+ 네트워크 탭에서 우리가 요청한 api정보 등을 확인 가능하다. 보안에 취약하다.&lt;/span&gt;&lt;/p&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;u&gt;2. 서버 컴포넌트에서 Data를 fetching하는 방법&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;클라이언트 컴포넌트와 달리 서버 컴포넌트를 사용하게 되면 useState나 useEffect, useQuery 등의 필요성이 사라지는 등 좀 더 편리해졌다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;컴포넌트 함수 외부에서도 함수 사용 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;useState, useEffetct를 사용하지 않아도 된다. -&amp;gt; 서버사이드 렌더링으로 데이터 fetching이 완료된 HTML페이지를 전달해 주기 때문 +&lt;span style=&quot;text-align: left;&quot;&gt; 서버 컴포넌트에서는 클라이언트 사이드와 달리 사용자 상호 작용이 없으므로 상태 변화(라이프 사이클)를 관리할 필요가 없다. 서버 컴포넌트의 주된 목적은 초기 데이터 로딩 및 HTML 생성이므로, 상태를 관리할 필요성이 크게 줄어든다. &lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;fetch 사용 시 프레임워크에서 자동으로 URL을 캐싱 해준다(useQuery 필요성 사라짐).&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;자동 캐싱 때문에 초기 data fetching 때에만 loading 상태가 필요하다. -&amp;gt; &lt;b&gt;&lt;u&gt;❗하지만 서버에서 이루어지기 때문에 fetching될 때 까지 사용자가 아예 페이지 자체를 사용자가 확인할 수 없다. 때문에 사용자에게 로딩상태를 알려줄 수 있는 조치가 필요하다(아래에서 정리)&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;캐싱된 데이터가 아닌 최신 데이터가 필요할 경우 revalidation을 공부해 보도록 하자&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1710605061926&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const metadata = {
  title: &quot;Home&quot;,
}; //서버 컴포넌트에서는 metadata 가능

const URL = &quot;https://nomad-movies.nomadcoders.workers.dev/movies&quot;;

//1. 서버 컴포넌트 -&amp;gt; 외부에 함수 작성 가능
async function getMovies() {
  console.log(&quot;i'm fetching!&quot;); // 서버 컴포넌트기 때문에 서버에서 로그 찍힘
  //2. 서버 컴포넌트 사용시, Next.js에서 fetch한 URL을 자동으로 캐싱해줌, useQuery 필요없음
  // 최신 데이터가 필요할 경우 revalidation에 대해 공부하기
  const res = await fetch(URL);
  const json = await res.json();
  return json;
}
export default async function HomePage() {
  //3. useState, useEffect 필요 없음
  //4. loading state도 필요 없음 -&amp;gt; 캐싱되기 때문,
  //❗but, 처음에는 api요청에 따른 로딩 발생 -&amp;gt; 서버에서 html를 받을 때까지 사용자는 페이지를 확인하지 못함(서버가 로딩중인 상태)
  // 사용자가 로딩중인걸 바로 확인해야 함
  const movies = await getMovies();
  return (
    &amp;lt;&amp;gt;
      &amp;lt;div&amp;gt;{JSON.stringify(movies)}&amp;lt;/div&amp;gt;
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;컴포넌트에 async를 붙이는 것은 NextJs가 해당 컴포넌트에서 await 해야 하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;+ 리액트 라이프사이클(Life cycle)과 훅(Hooks)의 목적 복습하기&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;라이프사이클과 훅의 목적은 주로 컴포넌트의 생명주기에 따른 동작을 관리하고, 상태(state)를 효율적으로 관리하여 UI를 최신 상태로 유지하는 데 있다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;  라이프사이클: &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;라이프사이클은 컴포넌트가 생성되고 소멸되는 과정에서 발생하는 다양한 이벤트를 의미한다. 예를 들어, 컴포넌트가 처음 렌더링될 때, 업데이트될 때, 혹은 제거될 때 특정 작업을 수행하고 싶을 때 라이프사이클 메서드를 사용한다. 이를 통해 컴포넌트의 초기화, 데이터 로딩, 상태 갱신 등을 관리할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;  Hooks의 목적 :&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;훅은 함수형 컴포넌트에서 상태와 생명주기 기능을 사용할 수 있게 해주는 React의 기능이다. useState, useEffect, useContext 등의 훅을 사용하여 컴포넌트의 상태를 관리하고, 생명주기 이벤트에 대응하여 특정 작업을 수행할 수 있다. 훅을 사용함으로써 클래스형 컴포넌트에서 제공되는 기능과 유사한 기능을 함수형 컴포넌트에서도 사용할 수 있게 되었다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 상태 관리: 컴포넌트의 상태를 관리하여 UI를 최신 상태로 유지한다. useState 훅을 사용하여 컴포넌트의 상태를 선언하고, 상태가 변경될 때마다 UI를 업데이트할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 생명주기 관리: 컴포넌트의 생명주기에 따른 동작을 관리한다. useEffect 훅을 사용하여 컴포넌트가 마운트되었을 때, 업데이트되었을 때, 혹은 언마운트되었을 때 특정 작업을 수행할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 부수 효과 관리: 데이터 가져오기, 구독 설정, 타이머 설정 등의 부수 효과를 관리한다. useEffect 훅을 사용하여 컴포넌트의 부수 효과를 관리하고, 필요한 경우 정리(clean-up) 작업을 수행한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;따라서 리액트에서 라이프사이클과 훅을 사용하여 상태를 관리하고, 컴포넌트의 생명주기를 관리하여 UI를 최신 상태로 유지하는 것이 주요 목적이다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;u&gt;3. Loading Components&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;page폴더 안에 loading.tsx를 생성하면, 서버가 렌더링될 때 동안 해당 페이지 자리에 로딩 컴포넌트를 보여준다.&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;154&quot; data-origin-height=&quot;87&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r9zcb/btsFRb7YTBt/xpJCJwENPU2SuHf4RGajNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r9zcb/btsFRb7YTBt/xpJCJwENPU2SuHf4RGajNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r9zcb/btsFRb7YTBt/xpJCJwENPU2SuHf4RGajNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr9zcb%2FbtsFRb7YTBt%2FxpJCJwENPU2SuHf4RGajNk%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;154&quot; height=&quot;87&quot; data-origin-width=&quot;154&quot; data-origin-height=&quot;87&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;사용자가 페이지를 요청하면, 서버가 &lt;span style=&quot;text-align: start;&quot;&gt;즉시&lt;/span&gt; &lt;span style=&quot;text-align: start;&quot;&gt;먼저 준비된 작은 HTML문서들(청크) Navigator, Loading페이지 등을 먼저 전달하고, 백엔드 통신이 마무리 되지 않이 기다려야 함을 알림 -&amp;gt; component는 await 중 -&amp;gt; &lt;/span&gt;서버가 데이터 fetching이 완료가 되면 해당 컴포넌트를 전달한다. -&amp;gt; Loading컴포넌트를 해당 컴포넌트로 바꿔줌 -&amp;gt;&amp;nbsp; &lt;span style=&quot;text-align: start;&quot;&gt;서버가 content를 streaming 하는 것.&amp;nbsp;&lt;/span&gt; &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;260&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caT8ZT/btsFTdKKeOT/Fko5kqAOVHiCTLPMP67ONk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caT8ZT/btsFTdKKeOT/Fko5kqAOVHiCTLPMP67ONk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caT8ZT/btsFTdKKeOT/Fko5kqAOVHiCTLPMP67ONk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaT8ZT%2FbtsFTdKKeOT%2FFko5kqAOVHiCTLPMP67ONk%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;260&quot; height=&quot;270&quot; data-origin-width=&quot;260&quot; data-origin-height=&quot;270&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;u&gt; &lt;b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;-&amp;gt; ❗하지만 매번 이런 식으로 폴더에 Loading 컴포넌트를 만들기는 번거롭다. 다른 대안이 필요하다.&lt;/span&gt;&lt;/b&gt; &lt;/u&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; text-align: start;&quot;&gt;+ 컴포넌트에 async를 붙이는 것은 NextJs가 해당 컴포넌트에서 await 해야 하기 때문이다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710659627423&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 HomePage() {
  await new Promise((resolve) =&amp;gt; setTimeout(resolve, 5000));
  const movies = await getMovies();
  return (
    &amp;lt;&amp;gt;
      &amp;lt;div&amp;gt;{JSON.stringify(movies)}&amp;lt;/div&amp;gt;
    &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;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;  구글 검색엔진은 로딩페이지를 인식할까? &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;로딩 페이지나 Suspense를 사용하는 경우 Google 봇은 로딩요소를 볼 수 없다. 앞서 본 것처럼 페이지는 기술적으로 로드되지 않았으며 데이터가 도착할 때만 '공식적으로' 로드되기 때문이다. Google 봇은 페이지가 로드될 때까지 기다린다. 브라우저는 대기가 완료될 때까지 페이지가 로드되었다고 '생각'하지 않는다.&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;u&gt;4. Parallel Requests (Promise.all)&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;같은 컴포넌트에서 동시에 다수의 데이터 통신을 수행할 경우, async await을 사용하면 먼저 실행된 데이터 통신이 마무리 된 후에, 다음 데이터 통신이 실행됨 -&amp;gt; 데이터 통신이 많고 오래걸릴 수록 -&amp;gt; 모든 데이터 통신이 완료될 때 까지 시간이 굉장히 오래걸린다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710662703851&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const movie = await getMovie(id); // 2개의 데이터 통신 할 경우
const videos = await getVideos(id); // 1번이 완료되어야 2번이 진행됨 -&amp;gt; 병렬적으로 실행 방법 Promise.all&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;242&quot; data-origin-height=&quot;38&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BQUpy/btsFQUZIKma/eAqmqavyEG2piOpaKnGD1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BQUpy/btsFQUZIKma/eAqmqavyEG2piOpaKnGD1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BQUpy/btsFQUZIKma/eAqmqavyEG2piOpaKnGD1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBQUpy%2FbtsFQUZIKma%2FeAqmqavyEG2piOpaKnGD1K%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;242&quot; height=&quot;38&quot; data-origin-width=&quot;242&quot; data-origin-height=&quot;38&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;먼저 실행한 데이터 통신&amp;nbsp; -&amp;gt; 5초 뒤 다음 데이터 통신이 완료됨&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;-&amp;gt; Promise.all을 사용하면 모든 데이터 통신을 병렬적으로 동시에 수행 가능하다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710662681524&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const [movie, videos] = await Promise.all([getMovie(id), getVideos(id)]);&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;237&quot; data-origin-height=&quot;38&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRxeps/btsFQcmgt70/6LvXQ9mUNmM33lia9S7ko1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRxeps/btsFQcmgt70/6LvXQ9mUNmM33lia9S7ko1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRxeps/btsFQcmgt70/6LvXQ9mUNmM33lia9S7ko1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRxeps%2FbtsFQcmgt70%2F6LvXQ9mUNmM33lia9S7ko1%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;237&quot; height=&quot;38&quot; data-origin-width=&quot;237&quot; data-origin-height=&quot;38&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;-&amp;gt; ❗하지만 이렇게되면 두 데이터 통신이 전부 끝나야지만 데이터를 확인할 수 있다. 분리할 수 있는 다른 대안이 필요하다.&lt;/b&gt;&lt;/u&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;u&gt;5. Suspense&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1. 2가지 데이터를 병렬적으로 통신하기 위해 컴포넌트를 분리(각 컴포넌트는 async)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2. Suspense를 이용하여 fallback에 loading 상태동안 보여줄 요소를 전달&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3. 데이터 통신을 마치면 해당 컴포넌트로 교체됨&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710666627661&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 MovieDetail({
  params: { id },
}: {
  params: { id: string };
}) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Suspense fallback={&amp;lt;h1&amp;gt;Loading movie info&amp;lt;/h1&amp;gt;}&amp;gt;
        &amp;lt;MovieInfo id={id} /&amp;gt;
      &amp;lt;/Suspense&amp;gt;
      &amp;lt;Suspense fallback={&amp;lt;h1&amp;gt;Loading movie videos&amp;lt;/h1&amp;gt;}&amp;gt;
        &amp;lt;MovieVideos id={id} /&amp;gt;
      &amp;lt;/Suspense&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;u&gt;&lt;b&gt;-&amp;gt; ❗만약 데이터 통신에 실패하거나 에러가 발생한다면 어떻게 에러 처리를 해야 할까?&lt;/b&gt;&lt;/u&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;u&gt;6. Error Handling&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;로딩 컴포넌트와 똑같이 해당 폴더 내부에 error.tsx를 작성하면, 에러 발생시 해당 페이지를 자동으로 보여주게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;나머지 html요소는 영향이 없고, 웹 사이트가 멈추지 않고, 해당 페이지만 error페이지로 보여진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 애플리케이션이 멈추지 않고 다른 작업을 동시에 할 수 있다는 것이다. 만약 로딩, 에러 상태가 발생했다고 해서 전체 애플리케이션이 멈추는 것처럼 보이는 것은 치명적이며 사용자에게 좋지 않다. 따라서 부분적으로 로딩, 에러 상태를 보여주는 것이 좋다.&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;145&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OGtCL/btsFQPYFQGm/LDmtek8E0UpPFVCbSCrJDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OGtCL/btsFQPYFQGm/LDmtek8E0UpPFVCbSCrJDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OGtCL/btsFQPYFQGm/LDmtek8E0UpPFVCbSCrJDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOGtCL%2FbtsFQPYFQGm%2FLDmtek8E0UpPFVCbSCrJDK%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;145&quot; height=&quot;89&quot; data-origin-width=&quot;145&quot; data-origin-height=&quot;89&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;275&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2rQIT/btsFQsJabfN/DmQRPQeRbuBkrhO8UtKou0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2rQIT/btsFQsJabfN/DmQRPQeRbuBkrhO8UtKou0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2rQIT/btsFQsJabfN/DmQRPQeRbuBkrhO8UtKou0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2rQIT%2FbtsFQsJabfN%2FDmQRPQeRbuBkrhO8UtKou0%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;275&quot; height=&quot;289&quot; data-origin-width=&quot;275&quot; data-origin-height=&quot;289&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;+ 읽어보면 좋을 참고 자료 :&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710668433740&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;Suspense, Error Boundary로 비동기 로딩, 에러 로직 공통화하기(feat. Next.js, React-Query)&quot; data-og-description=&quot;Suspense, Error Boundary를 사용하여 선언적으로 깔쌈하게 비동기 로딩, 에러 로직을 공통화합니다.&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@kingyong9169/react-declarative-error-loading-handling&quot; data-og-url=&quot;https://velog.io/@kingyong9169/react-declarative-error-loading-handling&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/TdwNj/hyVyfOPQn7/UGDkkcFNPlQeodu8PFBQ81/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/uJFXG/hyVADuiJGw/bGqjgGD1H76KATSpmCpNJ0/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/bHtcb3/hyVAzZK1PP/PHFlO4QSZN2ZB120A2Inrk/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot;&gt;&lt;a href=&quot;https://velog.io/@kingyong9169/react-declarative-error-loading-handling&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@kingyong9169/react-declarative-error-loading-handling&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/TdwNj/hyVyfOPQn7/UGDkkcFNPlQeodu8PFBQ81/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/uJFXG/hyVADuiJGw/bGqjgGD1H76KATSpmCpNJ0/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/bHtcb3/hyVAzZK1PP/PHFlO4QSZN2ZB120A2Inrk/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720');&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;Suspense, Error Boundary로 비동기 로딩, 에러 로직 공통화하기(feat. Next.js, React-Query)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Suspense, Error Boundary를 사용하여 선언적으로 깔쌈하게 비동기 로딩, 에러 로직을 공통화합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;u&gt;7. Dynamic Metadata(동적 메타데이타)&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;각 페이지마다 메타데이타 내용을 변경하고 싶을 경우 다음과 같이 generateMetadata를 설정해 주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;컴포넌트에 전달된 id props을 활용해 영화정보를 가져와서 title 정보로 메타데이타를 변경시켜 준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;metadata를 업데이트 하기 위해 getMovie API를 실행하는건 좋지 않다고 생각할 수 있지만, 이전 버전이 아닌 최신 버전은 하위 컴포넌트에서 호출한 getMovie를 캐싱하기 때문에 두번째 호출한 fetch에서는 캐싱된 데이터를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710677419143&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Params {
  params: { id: string };
}

// metadata를 업데이트 하기 위해 getMovie API를 실행하는건 좋지 않다고 생각할 수 있지만,
// 이전 버전이 아닌 최신 버전에서는 하위 컴포넌트에서 호출한 getMovie를 캐싱하기 때문에
// 두번째 호출한 fetch에서는 캐싱된 데이터를 사용한다.
export async function generateMetadata({ params: { id } }: Params) {
  //컴포넌트와 같이 props을 받을 수 있음(id)
  const movie = await getMovie(id);
  return {
    title: movie.title,
  };
}

export default async function MovieDetail({
  params: { id },
}: {
  params: { id: string };
}) {&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 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&lt;u&gt;8. prefetch props&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt; movie 페이지는 영화정보가 굉장히 많아 데이터가 로드되는데 오래걸리기 때문에 사용자가 비디오 목록을 확인하는데 오래 걸린다. 이 Link 부분에 prefetch props를 추가해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710724408697&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Link prefetch href={`/movies/${id}`}&amp;gt;
        {title}
      &amp;lt;/Link&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이렇게 하면 NextJS는 해당 페이지의 데이터를 미리 로드하여 사용자가 더 빠르게 데이터를 확인할 수 있게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Network탭을 열어놓고 스크롤을 내리면 사용자가 링크를 클릭하지 않아도 미리 자동적으로 해당 페이지의 데이터를 받아오고 있는것을 확인할 수 있다. 해당페이지에 들어가면 로딩스피너는 더이상 확인할 수 없고 미리 로드한 데이터를 더 빠르게 확인 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;모든 페이지를 prefetch하라는 것은 아니다! DB가 죽을 수도 있다.. 하지만 필요시 적절히 사용할 수 있는 멋진 기능인 것 같다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>JavaScript/Next.js</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/165</guid>
      <comments>https://junvelee.tistory.com/165#entry165comment</comments>
      <pubDate>Sun, 17 Mar 2024 18:52:32 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Route groups, Meta Data, dynamic routes 간단 정리</title>
      <link>https://junvelee.tistory.com/164</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;u&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1. Route groups&lt;/b&gt;&lt;/span&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt; 폴더이름에 ()괄호를 넣어주면 url은 변하지 않고 페이지를 묶어줄 수 있다. &amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;routes를 그룹화하여 logical groups로 만들 수 있다. 이렇게 관련된 페이지들을 그룹화 하면 좀 더 직관적으로 파악이 가능하다.&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;320&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rmTqu/btsFQVc5aWj/5JFdqZXew1V4uYJF6xa4W0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rmTqu/btsFQVc5aWj/5JFdqZXew1V4uYJF6xa4W0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rmTqu/btsFQVc5aWj/5JFdqZXew1V4uYJF6xa4W0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrmTqu%2FbtsFQVc5aWj%2F5JFdqZXew1V4uYJF6xa4W0%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;320&quot; height=&quot;192&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&lt;u&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2. Meta Data&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 메타 데이터는 병합된다(다른 page에서는 title, layout에는 description 사용할 경우 병합되어 나옴)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- page나 layout 에서만 메타데이터를 내보낼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 컴포넌트에서는 메타데이터를 내보낼 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 메타 데이터는 서버 컴포넌트에서만 있을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- title 등에 template 옵션으로 공통으로 띄울 문자열 지정이 가능하다. default는 기본값.&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;836&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kGRFK/btsFRcySawQ/uxrdZI2lf6QhchlFu8orv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kGRFK/btsFRcySawQ/uxrdZI2lf6QhchlFu8orv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kGRFK/btsFRcySawQ/uxrdZI2lf6QhchlFu8orv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkGRFK%2FbtsFRcySawQ%2FuxrdZI2lf6QhchlFu8orv1%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;578&quot; height=&quot;123&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;178&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 공식문서에서 여러가지 옵션들 확인 가능하다.&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;608&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfiahI/btsFRismBWa/h98nGRpyihAwxkSfzYAJsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfiahI/btsFRismBWa/h98nGRpyihAwxkSfzYAJsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfiahI/btsFRismBWa/h98nGRpyihAwxkSfzYAJsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfiahI%2FbtsFRismBWa%2Fh98nGRpyihAwxkSfzYAJsk%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;608&quot; height=&quot;297&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;figure id=&quot;og_1710577295105&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;Optimizing: Metadata | Next.js&quot; data-og-description=&quot;Use the Metadata API to define metadata in any layout or page.&quot; data-og-host=&quot;nextjs.org&quot; data-og-source-url=&quot;https://nextjs.org/docs/app/building-your-application/optimizing/metadata&quot; data-og-url=&quot;https://nextjs.org/docs/app/building-your-application/optimizing/metadata&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/btPVJs/hyVyeoIgAU/iDKDAswTsLYYp4DGnBUxp0/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441,https://scrap.kakaocdn.net/dn/b0SboA/hyVycqSn9l/ksuCF4LOy7KxQBp1K26Hp0/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/app/building-your-application/optimizing/metadata&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nextjs.org/docs/app/building-your-application/optimizing/metadata&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/btPVJs/hyVyeoIgAU/iDKDAswTsLYYp4DGnBUxp0/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441,https://scrap.kakaocdn.net/dn/b0SboA/hyVycqSn9l/ksuCF4LOy7KxQBp1K26Hp0/img.png?width=843&amp;amp;height=441&amp;amp;face=0_0_843_441');&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;Optimizing: Metadata | Next.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Use the Metadata API to define metadata in any layout or page.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nextjs.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;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;u&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3. dynamic routes&lt;/span&gt;&lt;/u&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;폴더명/[id] 폴더 생성/page.tsx 으로 동적 라우팅 가능 -&amp;gt; [ ] 대괄호 필수 (리액트 동적라우팅 /movie/:id와 같지만 hook이 필요 없다.)&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;291&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rEJlS/btsFP8KLhKE/9yLjB9bPQZDqpU082GTkOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rEJlS/btsFP8KLhKE/9yLjB9bPQZDqpU082GTkOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rEJlS/btsFP8KLhKE/9yLjB9bPQZDqpU082GTkOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrEJlS%2FbtsFP8KLhKE%2F9yLjB9bPQZDqpU082GTkOk%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;291&quot; height=&quot;120&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;120&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;/movies/어떤주소가 와도 해당 page 띄워줌&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;322&quot; data-origin-height=&quot;37&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kHQDr/btsFRCD8n8z/Dm1uvAzK4eY6acKIUB41VK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kHQDr/btsFRCD8n8z/Dm1uvAzK4eY6acKIUB41VK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kHQDr/btsFRCD8n8z/Dm1uvAzK4eY6acKIUB41VK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkHQDr%2FbtsFRCD8n8z%2FDm1uvAzK4eY6acKIUB41VK%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;322&quot; height=&quot;37&quot; data-origin-width=&quot;322&quot; data-origin-height=&quot;37&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;-&amp;gt; 페이지에서 받는 /movie/123424 id를 받아와 보자&lt;/b&gt;&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;452&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bugcV4/btsFQcflwYg/SoF3joE0oa4Uma15VxVTkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bugcV4/btsFQcflwYg/SoF3joE0oa4Uma15VxVTkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bugcV4/btsFQcflwYg/SoF3joE0oa4Uma15VxVTkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbugcV4%2FbtsFQcflwYg%2FSoF3joE0oa4Uma15VxVTkK%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;101&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;101&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;props을 받아서 console.log 해주면 &lt;b&gt;❗브라우저 console에 찍히지 않고 서버에서 찍히는걸 확인할 수 있다.&lt;/b&gt;&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;442&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFsUfF/btsFO2ddJD7/kezM3F1zCqnOquX5lrFon1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFsUfF/btsFO2ddJD7/kezM3F1zCqnOquX5lrFon1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFsUfF/btsFO2ddJD7/kezM3F1zCqnOquX5lrFon1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFsUfF%2FbtsFO2ddJD7%2FkezM3F1zCqnOquX5lrFon1%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;442&quot; height=&quot;47&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;47&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;서버에서 렌더링되기 때문이다. id는 내가 중괄호로 설정한 이름이다 [ id ] 다른이름도 가능. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;searchParams 는 주소창에 &lt;b&gt;/movie/123424?region=kr &lt;/b&gt;이런식으로 오면 아래와 같이 확인 가능하다. 검색 페이지 구현시 유용하게 사용한다.&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;568&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/msRIe/btsFOhhCaBU/qb9cl1LjA264M9vyYNCkM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/msRIe/btsFOhhCaBU/qb9cl1LjA264M9vyYNCkM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/msRIe/btsFOhhCaBU/qb9cl1LjA264M9vyYNCkM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmsRIe%2FbtsFOhhCaBU%2Fqb9cl1LjA264M9vyYNCkM0%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;63&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;63&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt; &lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;/movie/123424?region=kr&amp;amp;page=2 결과&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&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;392&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zrAWp/btsFQxKhm3f/N6h93JfxPkKKddkjQjSIS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zrAWp/btsFQxKhm3f/N6h93JfxPkKKddkjQjSIS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zrAWp/btsFQxKhm3f/N6h93JfxPkKKddkjQjSIS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzrAWp%2FbtsFQxKhm3f%2FN6h93JfxPkKKddkjQjSIS1%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;392&quot; height=&quot;96&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;96&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: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;아래와 같이 정보를 얻을 수 있다.&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;798&quot; data-origin-height=&quot;131&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oaPpI/btsFQRoseTg/g3pF97s99iU5JPt4oEikKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oaPpI/btsFQRoseTg/g3pF97s99iU5JPt4oEikKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oaPpI/btsFQRoseTg/g3pF97s99iU5JPt4oEikKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoaPpI%2FbtsFQRoseTg%2Fg3pF97s99iU5JPt4oEikKk%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;573&quot; height=&quot;94&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;131&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>
      <category>JavaScript/Next.js</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/164</guid>
      <comments>https://junvelee.tistory.com/164#entry164comment</comments>
      <pubDate>Sat, 16 Mar 2024 19:34:16 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] Next.js Routing과 Hydronation, 'use Client' 알아보기</title>
      <link>https://junvelee.tistory.com/163</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;[Next.js]&amp;nbsp;Next.js&amp;nbsp;Routing과&amp;nbsp;Hydronation,&amp;nbsp;'use&amp;nbsp;Client'&amp;nbsp;알아보기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Next.js에 대해 공부해보면서 알게된 내용들을 간단히 정리해 보고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;먼저 React는 라이브러리이고, Next.js는 프레임워크이다. 학습하면서 차이가 있었던 것은 리액트는 라이브러리 이기 때문에 폴더 구조, 이름, 라우팅, CSS, 하나부터 열까지 모든 선택과 결정을 내가 해야 했었다. 어떻게 보면 하나 하나 전부 고민해야 하고 여러가지를 공부하고 선택해야 하는 번거로움이 있었지만 내가 원하는 대로, 필요할 때 원하는 패키지와 개발 방식으로 자유롭게 개발할 수 있다는 장점이 있었다. Next.js같은 경우는 프레임워크기 때문에 그들이 정해놓은 룰과 규칙이 있었고, 라우팅 방식이나 폴더구조, 파일이름, CSS까지 그 규칙을 준수해야지만 개발이 가능했다. 하지만 나보다 더 멋진 개발팀이 짜놓은 규칙과 틀 안에서 보다 편리해진 기능으로 개발한다는 것이 어떻게 보면 개인적으로 안심도 되고 리액트에 비해 편리해진 기능들도 많았다. Next.js 프레임워크는 현재 리액트 메타 프레임워크 1위로 급부상할만큼 많은 인기를 끌고 있지만 한편으로는 13,14 등 최신 버전이 아직 베타 수준이고 아직 불안정하다는 여론도 많은 것 같다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Next.js 13,14 버전 이후의 app 디렉토리가 등장하면서 편리해진 기능들이 많은 것같다. 어떤 사이드 이펙트가 있을지는 아직 잘 모르겠지만.... 그래도 계속해서 새로운 시도를 해보고 시야를 넓히는건 개발에 큰 도움이 될테니 차근차근 배우면서 간단히 정리해 보고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;1. Next.js 설치(수동 설치)&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. create next-app을 사용하지 않고 간단히 프로젝트를 생성해 본다. react, react-dom, next를 최신버전으로 설치해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710507168858&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install react@latest react-dom@latest next@latest&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. package.json에 &quot;dev&quot; : &quot;next dev&quot; 추가&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710507225450&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;scripts&quot;: {
    &quot;dev&quot;: &quot;next dev&quot;,
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. src폴더 생성/app폴더/ 내부에 page.tsx 생성(13버전 app 디렉토리)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4. npm run dev로 앱을 실행시키면, typescript를 따로 설치하지 않아도 앱 실행과 동시에 typescript 패키지와, 폴더 구조까지 생성해 준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710507323291&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm run dev&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;2. Router&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Next.js에서 라우팅은 파일시스템을 통해 폴더 구조대로 url이 생성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;13 이전 버전에서는 pages구조를 사용하여 index.tsx, home.tsx 등 파일명으로 라우팅이 됐었다. -&amp;gt; /&amp;nbsp; 또는 /home 으로 생성됨&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710512883194&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;├── /pages
│   ├── api
│   │     └── hello.ts
│   ├── _app_.tsx
│   ├── _document.tsx
│   ├── index.tsx  ----&amp;gt; /
│   └── page1.tsx  ----&amp;gt; /age1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;13버전의 app 디렉토리 구조를 사용할 때는 aap/폴더명/page.tsx 방식으로 라우팅 한다. -&amp;gt; /폴더명 으로 생성됨&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710512869096&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;├── /app
│   ├── api(API Routes 지원 여부 불확실)
│   ├── page1 ----&amp;gt; /page1
│   │  ├──── page2  ----&amp;gt; /page1/page2
│   │  │    └── page.tsx
│   │  ├─── page.tsx //page명은 반드시 page.tsx 필수
│   │  ├─── layout.tsx
│   ├── layout.tsx
│   └── page.tsx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이때 폴더명으로 라우팅이 되며, 폴더 내부 페이지명은 반드시 page.tsx로 설정해 주어야 라우팅이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;참고로 app 디렉토리로 구성할 경우에도, 모든 컴포넌트들은 서버 컴포넌트로 렌더링된다(RSC:React Server Component)&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;3. CSR vs SSR&amp;nbsp;&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;먼저 SSR과 CSR에 대한 이해가 부족하다면 다음 포스팅을 통해 공부하고 오도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710512472777&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;CSR(Client Side Rendering)과 SSR(Server Side Rendering)의 차이점&quot; data-og-description=&quot;CSR(Client Side Rendering)과 SSR(Server Side Rendering)의 차이점 1. 브라우저 렌더링 브라우저가 서버로부터 요청해 받은 내용을 브라우저 화면(View)에 표시해주는 작업을 말한다. Chorme 같은 경우, 브라우저 &quot; data-og-host=&quot;junvelee.tistory.com&quot; data-og-source-url=&quot;https://junvelee.tistory.com/162&quot; data-og-url=&quot;https://junvelee.tistory.com/162&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bWXp1q/hyVymfQNlE/58f5hUzT39Uj3C3D6uxODk/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/vZBQI/hyVBHilHdM/MYWJnLz1zaVVSKP4ZeyfsK/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bgovLR/hyVxsAHTsl/YM37yKaH6xcksce1bz6CRK/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot;&gt;&lt;a href=&quot;https://junvelee.tistory.com/162&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://junvelee.tistory.com/162&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bWXp1q/hyVymfQNlE/58f5hUzT39Uj3C3D6uxODk/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/vZBQI/hyVBHilHdM/MYWJnLz1zaVVSKP4ZeyfsK/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bgovLR/hyVxsAHTsl/YM37yKaH6xcksce1bz6CRK/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720');&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;CSR(Client Side Rendering)과 SSR(Server Side Rendering)의 차이점&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CSR(Client Side Rendering)과 SSR(Server Side Rendering)의 차이점 1. 브라우저 렌더링 브라우저가 서버로부터 요청해 받은 내용을 브라우저 화면(View)에 표시해주는 작업을 말한다. Chorme 같은 경우, 브라우저&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;junvelee.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&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; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CSR(Client Side Rendering)의 단점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1) 사용자 경험성이 떨어진다 : CSR은 HTML문서가 비어있고, JS에 의해 HTML요소가 추가되는 형태이다. -&amp;gt; 초기 렌더링이나 새로고침 시 유저가 페이지를 처음 봤을 땐 빈 화면을 보게된다. JS가 다운로드되고 실행되면 그제서야 화면이 보이기 때문에 초기 렌더링이 오래걸린다. -&amp;gt; 만약 사용자의 네트워크가 느릴 경우, JS파일이 다운로드되고 실행될 때 까지 기다려야만 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2) SEO(검색엔진)에 취약 하다 : 구글 검색엔진은 빈 HTML을 보게 되므로 정보를 얻을 수 없다(구글 검색엔진은 간혹 JS를 실행시킨다고 하지만 대부분의 검색엔진은 JS까지 실행시키지 않고 HTML를 분석한다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이와같은 CSR의 단점으로 최근 SSR의 필요성이 높아진것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;SSR(Server &lt;b&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Side&lt;/span&gt;&lt;/b&gt; Rendering)의 장점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1) SEO에 유리 : SSR은 서버에서 렌더링하여 완성된 HTML을 클라이언트에 전달한다. 이 때문에 모든 내용을 HTML이 가지고 있어 SEO에 유리하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2) 초기 렌더링 빠름 : 네트워크가 느리거나, JS가 실행되기 전에도 이미 사용자는 HTML을 통해 웹 페이지 내용을 확인할 수 있다. 초기 렌더링 시에도 유저가 빈화면을 볼 일이 없기 때문에 초기렌더링이 빠르다. 즉 모든컴포넌트 UI를 빌드하는데 JS에 의존적이지 않다.(다만 동적인 반응은 JS가 다운로드 된 후 일어나기 때문에 격차는 발생할 수 있다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Next.js의 경우 SSR이지만 그 단점을 좀 더 보완&lt;/b&gt;시켰다. 아래에서 확인해 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;4. Hydration&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;SSR의 경우 모든 페이지를 서버에서 렌더링 하기 때문에 서버로부터 완성된 HTML을 받아 온다. 때문에&amp;nbsp; &lt;span style=&quot;text-align: start;&quot;&gt;페이지 이동 시 새 페이지를 다시 요청하여&amp;nbsp;로딩 속도가 오래걸리고 깜빡임이 발생했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;Next.js에서는 Hydration과정을 통해 이를 줄일수 있도록 하였다. &lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;간단히 요약하면 다음과 같다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자가 url 접속 -&amp;gt; 서버에서 렌더링된 HTML 전달 -&amp;gt; 클라이언트에서 HTML을 받아 바로 사용자에게 보여줌&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;gt; 이와 함께 프레임워크가 즉시 JS를 load해서 초기 HTML 위에 React 컴포넌트로 초기화 시킴 -&amp;gt; React app을 생성함&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Hydration은 단순한 HTML문서를 -&amp;gt; React app으로 초기화하는 작업을 뜻하며 클라이언트에서 이루어진다. 이 과정을 통해, 사용자는 초기 렌더링 시 빠르게 HTML문서를 확인 가능하면서도, 클라이언트 쪽에서 즉시 JS를 리액트 컴포넌트로 초기화하여 -&amp;gt; 페이지 이동시에도 reload없이 CSR과 같이 부드럽게 페이지를 이동시킬 수 있다. SSR의 단점이었던 페이지 이동시 느린 로딩 속도를 보완한 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;5.&amp;nbsp;&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;'use Client'&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 이전까지는 Next.js에서 모든 컴포넌트가 서버 컴포넌트(RSC)였기 때문에 서버에서 렌더링 되고, 또 모든 컴포넌트가 클라이언트 쪽에 JS번들로 전달되어 Hydration 되었다. 이말은 곧 &lt;b&gt;클라이언트쪽에 넘겨지는 JS파일들이 많다는 뜻이고, 그만큼 페이지 이동시에도 (서버에서 새 페이지 렌더링 + 받는 JS파일이 많음) 로딩 속도가 많이 빠르지 못한&lt;/b&gt; 부분이 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;❗주의) 클라이언트 컴포넌트 또한 서버에서 렌더링되는 것은 같다. 다만 클라이언트 쪽에도 JS를 전달하여 렌더링 -&amp;gt; Hydration 된다.(클라이언트 컴포넌트라고 해서 클라이언트에서만 렌더링되는 것이 아니라 '둘 다'에서 렌더링 된다.)&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Next.js 13버전에서도 app 디렉토리를 구성하면 기본적으로 모두 서버 컴포넌트가 되며 서버에서 렌더링 된다. 하지만 이번에 'use Client'가 등장하면서 선택적으로 클라이언트 컴포넌트(RCC)로 만들어 특정 요소만 클라이언트에 전달하여 Hydrate 할 수 있게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;즉, 오직 &lt;b&gt;&quot;use Client&quot;를 선언한 클라이언트 컴포넌트만 클라이언트 쪽에(전달된다)서 Hydrate&lt;/b&gt;되는 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이로 인해 달라진 점은, 서버 컴포넌트와 클라이언트를 선택적으로 적용 가능하게 되었고, JS 동적인 기능이 필요한 컴포넌트만 클라이언트 컴포넌트로 선언하여 서버 -&amp;gt; 클라이언트로 JS번들을 전달하여 Hydration(JS로 컴포넌트화)시킨다. 이렇게 하면 서버 컴포넌트는 더 이상 클라이언트에 JS번들이 전달되지 않고(서버 컴포넌트는 동적인 기능이 없기때문에 클라이언트에 전달될 필요가 없다), 클라이언트가 받는 JS번들은 오직 클라이언트 컴포넌트밖에 없기 때문에 이전에 비해 전달되는 JS파일들이 적고 페이지 로딩 속도가 더 빨라진다(페이지 이동, 새로고침 시 로딩 속도 문제 보완).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;+ 어떤 컴포넌트를 클라이언트 컴포넌트('use Client')로 선언할지는 고민하지 않아도 된다. onClick, useState 등의 hooks, Link 등 reload, 동적인 동작을 할 경우 자동으로 'use Client'를 선언해야 한다고 에러를 띄워준다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;+ 서버 컴포넌트와 클라이언트 컴포넌트가 나뉘어짐으로서 서버컴포넌트는 더이상 클라이언트로 전달되지 않기 때문에 보안성이 높다.(API key, DB와 통신 가능 등)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;6.&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt; 'Client Component' 내부에&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;&amp;nbsp;&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;'Server Component' ?&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇다면 서버 컴포넌트와 클라이언트 컴포넌트를 섞어서 사용할 경우, 클라이언트 컴포넌트는 클라이언트로 전달된다고 했는데 클라이언트 컴포넌트가 서버 컴포넌트를 감싸고 있을 경우에는 어떻게 될까? 의문이 들 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;기본적으로 클라이언트 컴포넌트의 자식은 모두 클라이언트 컴포넌트 모듈로 간주되어 클라이언트로 같이 전달된다. 하지만 이번에 변경되어 &lt;b&gt;서버 컴포넌트를 클라이언트 컴포넌트의 props으로 전달&lt;/b&gt;하여 자식으로 배치시키면 가능하다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;자세한 내용은 &lt;a style=&quot;color: #000000;&quot; href=&quot;https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#supported-pattern-passing-server-components-to-client-components-as-props&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식문서&lt;/a&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: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;u&gt;&amp;lt;참조&amp;gt;&lt;/u&gt;&lt;/b&gt;&lt;b&gt;&lt;u&gt;&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #9d9d9d; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공식문서 및 nomadcoders의 Next.js 시작하기 강의로 공부한 후 정리한 내용입니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>JavaScript/Next.js</category>
      <category>CSR</category>
      <category>hydration</category>
      <category>next.js</category>
      <category>server component</category>
      <category>SSR</category>
      <category>use Client</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/163</guid>
      <comments>https://junvelee.tistory.com/163#entry163comment</comments>
      <pubDate>Fri, 15 Mar 2024 23:18:30 +0900</pubDate>
    </item>
    <item>
      <title>CSR(Client Side Rendering)과 SSR(Server Side Rendering)의 차이점</title>
      <link>https://junvelee.tistory.com/162</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;CSR(Client&amp;nbsp;Side&amp;nbsp;Rendering)과&amp;nbsp;SSR(Server&amp;nbsp;Side&amp;nbsp;Rendering)의&amp;nbsp;차이점&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;1. 브라우저 렌더링&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 브라우저가 서버로부터 요청해 받은 내용을 브라우저 화면(View)에 표시해주는 작업&lt;span style=&quot;text-align: start;&quot;&gt;을 말한다.&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Chorme 같은 경우, 브라우저 엔진 내부에 렌더링 엔진(Blink)과 자바스크립트 엔진(V8) 이 존재한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;렌더링 엔진에서는 HTML, CSS를 해석하고 비트맵 형식으로 웹 페이지를 화면에 그리는 역할을 하고,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;자바스크립트 엔진에서는 자바스크립트 코드를 해석(*인터프리터)하고 실행하여 웹 페이지에 동적인 기능을 추가하고 상호작용 가능하게 한다.(자바스크립트=인터프리터, 타입스크립트=컴파일)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;*&lt;a style=&quot;color: #000000;&quot; href=&quot;https://hwon-da.tistory.com/11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참조 : JavaScript는 인터프리터 언어?&amp;nbsp; &lt;/a&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;figure id=&quot;og_1710406399307&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;#00. JavaScript는 인터프리터 언어?&quot; data-og-description=&quot;결론 : JavaScript는 (해석 엔진에 따라 컴파일하기도 하는) 인터프리터 언어로 볼 수 있다. Q. JavaScript는 인터프리터 언어라는데 맞나요? A. 결론부터 말씀드리자면 인터프리터 언어로 분류되지만 &quot; data-og-host=&quot;hwon-da.tistory.com&quot; data-og-source-url=&quot;https://hwon-da.tistory.com/11&quot; data-og-url=&quot;https://hwon-da.tistory.com/11&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dlMni5/hyVAGYa2Tu/SqyIOaKgrhNg8RxuO9UilK/img.png?width=800&amp;amp;height=535&amp;amp;face=0_0_800_535,https://scrap.kakaocdn.net/dn/cfohax/hyVAFkGrEf/0sVOZoMUeH56XAFt6u6MMK/img.png?width=800&amp;amp;height=535&amp;amp;face=0_0_800_535,https://scrap.kakaocdn.net/dn/yQUnC/hyVADNVm8I/EKh4FyIFTlAJT0ek5ok6Uk/img.png?width=1992&amp;amp;height=1334&amp;amp;face=0_0_1992_1334&quot;&gt;&lt;a href=&quot;https://hwon-da.tistory.com/11&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hwon-da.tistory.com/11&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dlMni5/hyVAGYa2Tu/SqyIOaKgrhNg8RxuO9UilK/img.png?width=800&amp;amp;height=535&amp;amp;face=0_0_800_535,https://scrap.kakaocdn.net/dn/cfohax/hyVAFkGrEf/0sVOZoMUeH56XAFt6u6MMK/img.png?width=800&amp;amp;height=535&amp;amp;face=0_0_800_535,https://scrap.kakaocdn.net/dn/yQUnC/hyVADNVm8I/EKh4FyIFTlAJT0ek5ok6Uk/img.png?width=1992&amp;amp;height=1334&amp;amp;face=0_0_1992_1334');&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;#00. JavaScript는 인터프리터 언어?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;결론 : JavaScript는 (해석 엔진에 따라 컴파일하기도 하는) 인터프리터 언어로 볼 수 있다. Q. JavaScript는 인터프리터 언어라는데 맞나요? A. 결론부터 말씀드리자면 인터프리터 언어로 분류되지만&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hwon-da.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;figure id=&quot;og_1710406429819&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;컴파일이란 무엇이며, 자바스크립트는 인터프리터 언어인가?&quot; data-og-description=&quot;컴파일이란 무엇인가? 컴파일은 우리가 작성한 소스 코드를 오브젝트 코드로 변환시키는 과정이다. 인간이 알아듣기 쉬운 프로그래밍 언어인 High Level Language를 기계가 알아들을 수 있는 0과 1로 &quot; data-og-host=&quot;devlog-of-yein.tistory.com&quot; data-og-source-url=&quot;https://devlog-of-yein.tistory.com/6&quot; data-og-url=&quot;https://devlog-of-yein.tistory.com/6&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bkuRPG/hyVACIfI3o/NaUbqSiboLQYHCuCzd2f90/img.png?width=800&amp;amp;height=396&amp;amp;face=0_0_800_396,https://scrap.kakaocdn.net/dn/d50STd/hyVAMKR3dv/k14O3zXQEMjbORjq5iL1k0/img.png?width=800&amp;amp;height=396&amp;amp;face=0_0_800_396,https://scrap.kakaocdn.net/dn/BqkJq/hyVAOPsjif/sHqy4yk5FfpUp2dnOzShFK/img.png?width=1255&amp;amp;height=622&amp;amp;face=0_0_1255_622&quot;&gt;&lt;a href=&quot;https://devlog-of-yein.tistory.com/6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://devlog-of-yein.tistory.com/6&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bkuRPG/hyVACIfI3o/NaUbqSiboLQYHCuCzd2f90/img.png?width=800&amp;amp;height=396&amp;amp;face=0_0_800_396,https://scrap.kakaocdn.net/dn/d50STd/hyVAMKR3dv/k14O3zXQEMjbORjq5iL1k0/img.png?width=800&amp;amp;height=396&amp;amp;face=0_0_800_396,https://scrap.kakaocdn.net/dn/BqkJq/hyVAOPsjif/sHqy4yk5FfpUp2dnOzShFK/img.png?width=1255&amp;amp;height=622&amp;amp;face=0_0_1255_622');&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;컴파일이란 무엇인가? 컴파일은 우리가 작성한 소스 코드를 오브젝트 코드로 변환시키는 과정이다. 인간이 알아듣기 쉬운 프로그래밍 언어인 High Level Language를 기계가 알아들을 수 있는 0과 1로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;devlog-of-yein.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;브라우저의 렌더링 과정은 다음 포스팅을 참조하도록 하자.&lt;/span&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710405813875&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;브라우저의 구성 요소와 렌더링 과정&quot; data-og-description=&quot;브라우저의 렌더링 원리 브라우저는 사용자 인터페이스, 브라우저 엔진, 렌더링 엔진, 네트워크, 자바스크립트 인터프리터, UI백엔드, 스토리지로 구성되어 있다. 브라우저가 화면을 렌더링 할 &quot; data-og-host=&quot;junvelee.tistory.com&quot; data-og-source-url=&quot;https://junvelee.tistory.com/135&quot; data-og-url=&quot;https://junvelee.tistory.com/135&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cceHXk/hyVxx2RAzi/KEbSktewWopWcZ5ORiBfX0/img.png?width=800&amp;amp;height=383&amp;amp;face=0_0_800_383,https://scrap.kakaocdn.net/dn/bh9OTh/hyVADf5S4o/5pyYEEKffZ2BFPqZuRqLU0/img.png?width=800&amp;amp;height=383&amp;amp;face=0_0_800_383,https://scrap.kakaocdn.net/dn/xm41A/hyVxstJDJn/R5EVxQoJdrOTHfTwv7Q270/img.png?width=1280&amp;amp;height=613&amp;amp;face=0_0_1280_613&quot;&gt;&lt;a href=&quot;https://junvelee.tistory.com/135&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://junvelee.tistory.com/135&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cceHXk/hyVxx2RAzi/KEbSktewWopWcZ5ORiBfX0/img.png?width=800&amp;amp;height=383&amp;amp;face=0_0_800_383,https://scrap.kakaocdn.net/dn/bh9OTh/hyVADf5S4o/5pyYEEKffZ2BFPqZuRqLU0/img.png?width=800&amp;amp;height=383&amp;amp;face=0_0_800_383,https://scrap.kakaocdn.net/dn/xm41A/hyVxstJDJn/R5EVxQoJdrOTHfTwv7Q270/img.png?width=1280&amp;amp;height=613&amp;amp;face=0_0_1280_613');&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;브라우저의 렌더링 원리 브라우저는 사용자 인터페이스, 브라우저 엔진, 렌더링 엔진, 네트워크, 자바스크립트 인터프리터, UI백엔드, 스토리지로 구성되어 있다. 브라우저가 화면을 렌더링 할&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;junvelee.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt; &lt;span style=&quot;text-align: start;&quot;&gt;브라우저 렌더링은 크게&amp;nbsp;&lt;/span&gt;&lt;b&gt;클라이언트 사이드 렌더링(CSR)&lt;/b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;과 서&lt;/span&gt;&lt;b&gt;버 사이드 렌더링(SSR)&lt;/b&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;방식으로 나누어진다.&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2. 클라이언트 사이드 렌더링(CSR)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;span style=&quot;text-align: start;&quot;&gt;CSR은 &quot;Client-Side Rendering&quot;의 약어로,&amp;nbsp;&lt;/span&gt;&lt;u&gt;클라이언트 측에서 페이지를 렌더링하는 방식&lt;/u&gt;&lt;span style=&quot;text-align: start;&quot;&gt;을 말한다.&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 사용자가 웹 사이트에 요청을 보내면 -&amp;gt; 서버로부터 빈 HTML페이지 + 모든 소스 코드들(JS포함)을 전달 받는다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;= 웹 페이지에 필요한 많은 JS, 소스파일들을 다운로드 하고 해석하여 실행하기 까지 &lt;u&gt;&lt;b&gt;초기 렌더링 속도가 오래 걸린다.&lt;/b&gt;&lt;/u&gt; 사용자는 JS파일을 모두 다운로드 할 때 까지 빈 화면을 보고있어야 한다(새로고침 시에도)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 초기에 웹 페이지와 관련된 데이터를 모두 받기 때문에 -&amp;gt; 페이지 이동시 추가적으로 필요한 데이터만 서버로부터 json형식으로 받고 -&amp;gt;&amp;nbsp; JS를 해석하여 동적으로 HTML을 생성해서 UI를 업데이트 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;= &lt;b&gt;&lt;u&gt;네이티브앱과 같이 한 페이지 내에서 깜빡임 없이 부드러운 사용자 경험을 얻을 수 있다.&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 검색엔진(SEO)은 서버의 HTML파일을 분석하는데, CSR에서는 초기 HTML문서의 body가 빈 페이지이고, 필요시 마다 JS로 동적으로 HTML을 생성하기 때문에 = &lt;b&gt;&lt;u&gt;SEO에 취약하다.&lt;/u&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;(이전 크롤러들은 자바스크립트를 실행시키지 않았었기에 SEO 최적화가 필수적이었다. 구글이 그 트렌드를 바꾸고 있다고 한다.) &lt;/span&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcSmW5/btsFOVwM3Hx/A8N7HqocjTzxK65Sk0MSRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcSmW5/btsFOVwM3Hx/A8N7HqocjTzxK65Sk0MSRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcSmW5/btsFOVwM3Hx/A8N7HqocjTzxK65Sk0MSRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcSmW5%2FbtsFOVwM3Hx%2FA8N7HqocjTzxK65Sk0MSRK%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;707&quot; height=&quot;398&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 사용자가 웹 사이트에 요청을 보낸다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. CDN이 HTML 파일과 JS로 접근 할 수 있는 링크를 클라이언트로 보낸다(&lt;b&gt;CDN : aws의 cloudflare를 생각하면 됨. 엔드 유저의 요청에 '물리적'으로 가까운 서버에서 요청에 응답하는 방식))&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 클라이언트는 HTML과 JS를 다운로드 받는다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4. 브라우저가 자바스크립트를 다운로드 받는다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5. 다운로드가 완료된 JS가 실행이 되며 데이터를 위한 API가 호출이 된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;6. 서버가 API로 부터의 요청에 응답한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;7. API로부터 받아온 데이터를 placeholer 자리에 넣어주면, 페이지가 상호작용이 가능해진다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;CSR의 장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;높은 사용자 경험&lt;/b&gt;: CSR은 클라이언트 측에서 데이터를 받아와 렌더링하기 때문에 페이지 이동 속도가 빠르고, 깜빡임이 적어 사용자 경험이 높다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;캐싱 가능&lt;/b&gt;: 클라이언트에서 캐시를 사용하여 적은 양의 데이터만 다시 요청하여 처리하는 것이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;적은 서버 부하&lt;/b&gt;: CSR에서는 클라이언트에서 데이터를 처리하기 때문에 서버 부하가 적다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;CSR의 단점&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;느린 초기 로딩 속도:&lt;/b&gt; CSR은 페이지를 렌더링하기 위해 필요한 JavaScript 파일을 먼저 다운로드한 후에 데이터를 받아와야 한다. 이로 인해 초기 로딩 속도가 느리게 느껴질 수 있다. (HTML은 JavaScript 파일을 포함하는데, 이 JavaScript 파일이 다운로드되고 실행될 때까지 렌더링되지 않은 상태로 남아 있다. 따라서 JavaScript 파일이 다운로드되고 실행될 때까지 페이지가 완전히 렌더링되지 않은 상태가 되며 이로 인해 초기 페이지 로딩 시간이 증가할 수 있다. 특히 JavaScript 파일이 크거나 네트워크 연결이 느린 경우에는 브라우저가 JavaScript 파일을 다운로드하고 실행하는데 시간이 걸릴 수 있으며, 그동안 사용자는 비어 있는 화면이나 로딩 스피너를 볼 수 있다)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;SEO에 불리함&lt;/b&gt;: CSR에서는 초기 HTML 파일에 콘텐츠가 포함되어 있지 않기 때문에 검색 엔진이 페이지를 크롤링할 때 콘텐츠를 인식하지 못할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;높은 개발 난이도(런닝커브)&lt;/b&gt;: CSR은 대규모의 복잡한 웹 애플리케이션에서 많이 사용되며, 이를 구현하기 위해서는 높은 개발 난이도와 복잡성이 요구된다. 특히, 상태 관리와 라우팅 등을 구현하기 위해서는 추가적인 라이브러리나 프레임워크를 사용해야 한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;낮은 보안성&lt;/b&gt;: CSR에서는 클라이언트에서 데이터를 처리하기 때문에 보안성이 낮을 수 있다. 클라이언트 측에서 데이터를 조작하거나 해킹 등의 공격이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;CSR의 사용권장 예시&lt;/b&gt;&lt;/span&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;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 네트워크가 빠를 때&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버의 성능이 좋지 않을 때&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;사용자에게 보여줘야 하는 데이터의 양이 많을 때(로딩스피너 가능)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;메인 스크립트가 가벼울 때&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;SEO의 영향을 비교적 덜 받는 웹 사이트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;웹 어플리케이션에 사용자와 상호작용할 경우가 많을 때&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3. 서버 사이드 렌더링(SSR)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; &lt;span style=&quot;text-align: start;&quot;&gt;SSR은 &quot;Server-Side Rendering&quot;의 약어로,&amp;nbsp;&lt;/span&gt;&lt;u&gt;서버 측에서 페이지를 렌더링하는 방식&lt;/u&gt;&lt;span style=&quot;text-align: start;&quot;&gt;이다.&amp;nbsp;&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; text-align: start;&quot;&gt; 1. 사용자가 웹 사이트에 요청을 보내면 -&amp;gt; 서버에서는 데이터들을 기반으로 즉시 렌더링 가능한 초기페이지 HTML를 먼저 완성 시킨다. -&amp;gt; 완성된 HTML 파일과 함께, 동적으로 제어 가능한 JS번들 등을 클라이언트에 전달한다&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; text-align: start;&quot;&gt;= &lt;b&gt;&lt;u&gt;초기 렌더링이 빠르다. / 반면에 완성된 HTML파일은 즉시 렌더링 되지만, JS는 다운로드하고 실행하는데에 시간이 걸리기 때문에 동적인 기능을 수행하는데 까지의 격차가 생길 수 있다. 예를 들어 사용자가 UI를 클릭해도 동적인 조작이 일어나지 않을 수 있다(기억하고 있음).&lt;/u&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 페이지 이동 시에는 다시 서버로부터 새 HTML 페이지를 요청하고 -&amp;gt; 완성된 HTML 페이지를 전달 받기 때문에&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;= &lt;u&gt;&lt;b&gt;깜빡임이 발생하고, 사용자 경험성이 떨어진다.&lt;/b&gt;&lt;/u&gt; 또한 페이지 이동 시 마다 새 HTML문서를 서버에서 처리하기 때문에 &lt;u&gt;&lt;b&gt;서버요청이 많고, 부하가 증가할 수 있다.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. HTML문서에 모든 컨텐츠가 담겨 있기 때문에 SEO 검색엔진에 더 효율적이다.&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxOhec/btsFNl387nT/8AXzNlqnc8lbm8emFwmbm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxOhec/btsFNl387nT/8AXzNlqnc8lbm8emFwmbm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxOhec/btsFNl387nT/8AXzNlqnc8lbm8emFwmbm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxOhec%2FbtsFNl387nT%2F8AXzNlqnc8lbm8emFwmbm0%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;629&quot; height=&quot;354&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 사용자가 웹 사이트에 요청을 보낸다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. Server는 &amp;lsquo;Ready to Render&amp;rsquo; 즉시 렌더링 가능한 html 파일을 만든다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 클라이언트에 전달하는 순간 이미 렌더링 준비가 되었기 때문에 HTML이 즉시 렌더링이 된다. 하지만 사이트에서 조작은 불가능하다.(JavaScript가 읽히기 전)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4. 브라우저가 자바스크립트를 다운 받는다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5. 다운로드가 이루어지고 있는 상태에서 사용자는 컨텐츠를 볼 수 있지만 사이트를 조작할 수 없다. 이때 사용자의 조작을 기억하고 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;6. 브라우저가 JavaScript FrameWork를 실행한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;7. JS까지 성공적으로 컴파일되었기 때문에, 아까 기억하고 있던 사용자의 조작이 실행되고 웹 페이지는 상호작용이 가능해진다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;SSR의 장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;빠른 초기 로딩 속도&lt;/b&gt;: SSR은 서버 측에서 데이터를 받아와 렌더링하기 때문에 초기 로딩 속도가 빠르다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;SEO에 유리함&lt;/b&gt;: SSR에서는 초기 HTML 파일에 콘텐츠가 포함되어 있기 때문에 검색 엔진이 페이지를 크롤링할 때 콘텐츠를 인식할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;높은 보안성&lt;/b&gt;: SSR에서는 서버 측에서 데이터를 처리하기 때문에 보안성이 높다. 클라이언트 측에서 데이터를 조작하거나 해킹 등의 공격이 어려워진다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;서버 부하를 분산 가능&lt;/b&gt;: SSR에서는 서버 측에서 데이터를 처리하기 때문에 서버 부하가 분산될 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;낮은 런닝 커브&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;SSR의 단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;느린 페이지 이동 속도&lt;/b&gt;: SSR은 페이지 이동할 때마다 서버에서 데이터를 받아와 렌더링해야 하기 때문에 페이지 이동 속도가 느리다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;낮은 사용자 경험&lt;/b&gt;: SSR에서는 페이지 이동 속도가 느리기 때문에 사용자 경험이 낮을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;어려운 캐싱&lt;/b&gt;: SSR에서는 캐시를 사용하는 것이 어려울 수 있다. 매번 새로운 데이터를 불러와야 하기 때문에 서버 부하가 증가할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;낮은 개발 난이도&lt;/b&gt;: SSR은 일반적인 웹 개발 방식과 유사하기 때문에 개발 난이도가 낮다. 하지만, 대규모의 복잡한 웹 애플리케이션에서는 추가적인 복잡성이 요구될 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;SSR을 사용 권장&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;네트워크가 느릴 때 (CSR은 한번에 모든 것을 불러오지만 SSR는 각 페이지마다 나누어 불러오기 때문이다)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;SEO(Search engine Optimization) 검색 엔진 최적화가 필요할 때&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;최초 로딩이 빨라야 하는 사이트를 개발할 때&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;메인 스크립트가 크고 로딩이 엄청 느릴 때&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;(CSR은 메인스크립트가 로딩이 끝나면 API로 데이터 요청을 보내지만, SSR은 한번의 요청에 아예 렌더가 가능한 페이지가 돌아온다)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;웹 사이트가 상호작용이 별로 없을 때&lt;/span&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;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이상으로 SSR과 CSR에 대하여 알아봤다. React를 사용하면서 &lt;u&gt;CSR의 치명적인 단점인 SEO와 초기렌더링 속도&lt;/u&gt;를 극복하기 위한 방안으로 최근에는 React meata-Framework들을 사용한다는 것을 알았다. 그 중 압도적인 만족도를 기록하고 있는 Next.js같은 경우는 SSR이면서도 그의 단점을 많이 보완시켰다고 할 수 있을 것 같다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Next.js는 SSR를 지원하며 초기 렌더링 속도와 SEO에서 높은 성능을 보이면서도 SSG까지도 구현 가능하다. 또한 &lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; text-align: start;&quot;&gt;Next.js 13버전에서는&lt;span&gt; 다양한 기능들이 추가되며 새로운 기술들을 접목시킬 수 있게 되었다. 그 중에서도 app 디렉토리가 도입되면서 app 디렉토리의 모든 컴포넌트는 &lt;u&gt;React Server Components로서 공식적으로 지원되게 되었고, RSC(Server Component)와 RCC(Client Component)를 선택할 수 있다는 것이 가장 인상적&lt;/u&gt;이었다. 컴포넌트를 어느쪽에서 렌더링을 시킬지 결정할 수 있기 때문에 상황에 따라 개발이 가능하며 이것은 앱 성능에 큰 영향을 미칠 것이다.(하지만 RSC와 SSR&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;은 서버에서 처리한다는 공통점 외에는 HTML문서가 아닌 컴포넌트라는 점 등 각각 해결하고자하는 목표도 다르고, 일어나는 시점과 최종 산출물도 다른&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;완전히 별개의 개념이라고 한다). &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; text-align: start;&quot;&gt;&lt;span&gt;어찌됐든 Next.js를 공부하면서 React Sever Components를 이해하기 위해서는 기본적으로 CSR과 SSR에 대한 공부가 필요했다. 다음에는 RSC와 RCC에 대해 더 공부해 보도록 해야겠다. 아래 자료들은 Next.js의 13버전과 React Server Components에 대한 소개와 평가들이니 더 공부해 보고 싶을 때 읽어보면 좋을 것 같다. React와 함께 Type Script...Next.js... 공부할 것들이 한참 남았다.. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710513684593&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 Routing과 Hydronation, 'use Client' 알아보기&quot; data-og-description=&quot;[Next.js] Next.js Routing과 Hydronation, 'use Client' 알아보기 Next.js에 대해 공부해보면서 알게된 내용들을 간단히 정리해 보고자 한다. 먼저 React는 라이브러리이고, Next.js는 프레임워크이다. 학습하면서 &quot; data-og-host=&quot;junvelee.tistory.com&quot; data-og-source-url=&quot;https://junvelee.tistory.com/163&quot; data-og-url=&quot;https://junvelee.tistory.com/163&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wwWc9/hyVBJArQ3J/5KY98XOMy7fG2cqeGzZXM1/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/pLGwI/hyVylH0prU/4jZVtEEtkeKnumkwcZbhI1/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418&quot;&gt;&lt;a href=&quot;https://junvelee.tistory.com/163&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://junvelee.tistory.com/163&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wwWc9/hyVBJArQ3J/5KY98XOMy7fG2cqeGzZXM1/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418,https://scrap.kakaocdn.net/dn/pLGwI/hyVylH0prU/4jZVtEEtkeKnumkwcZbhI1/img.png?width=800&amp;amp;height=418&amp;amp;face=0_0_800_418');&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 Routing과 Hydronation, 'use Client' 알아보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[Next.js] Next.js Routing과 Hydronation, 'use Client' 알아보기 Next.js에 대해 공부해보면서 알게된 내용들을 간단히 정리해 보고자 한다. 먼저 React는 라이브러리이고, Next.js는 프레임워크이다. 학습하면서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;junvelee.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1710410090907&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;[번역] React Server vs Client Component in Next.js 13&quot; data-og-description=&quot;원 글 링크Next.js 에서, 너는 리액트 서버 컴포넌트와 클라이언트 컴포넌트를 사용할 수 있다. app 경로에서 기본적으로 모든 컴포넌트들은 서버 컴포넌트이다. 이 게시글에서, 우리는 리액트 서&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@brgndy/React-Server-vs-Client-Component-in-Next.js-13-%ED%95%B4%EC%84%9D&quot; data-og-url=&quot;https://velog.io/@brgndy/React-Server-vs-Client-Component-in-Next.js-13-해석&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cqrGok/hyVxvjIaHe/REoVtw7SVcdYsiil3DfZ6k/img.png?width=1650&amp;amp;height=800&amp;amp;face=0_0_1650_800,https://scrap.kakaocdn.net/dn/yps1T/hyVxqvZeYb/Kd6mzcNwJ8z3SnKYPU8n1K/img.png?width=1650&amp;amp;height=800&amp;amp;face=0_0_1650_800,https://scrap.kakaocdn.net/dn/sJtFE/hyVAJHmVsr/UKAkhtdZWI65Y65o483pCK/img.png?width=2082&amp;amp;height=958&amp;amp;face=0_0_2082_958&quot;&gt;&lt;a href=&quot;https://velog.io/@brgndy/React-Server-vs-Client-Component-in-Next.js-13-%ED%95%B4%EC%84%9D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@brgndy/React-Server-vs-Client-Component-in-Next.js-13-%ED%95%B4%EC%84%9D&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cqrGok/hyVxvjIaHe/REoVtw7SVcdYsiil3DfZ6k/img.png?width=1650&amp;amp;height=800&amp;amp;face=0_0_1650_800,https://scrap.kakaocdn.net/dn/yps1T/hyVxqvZeYb/Kd6mzcNwJ8z3SnKYPU8n1K/img.png?width=1650&amp;amp;height=800&amp;amp;face=0_0_1650_800,https://scrap.kakaocdn.net/dn/sJtFE/hyVAJHmVsr/UKAkhtdZWI65Y65o483pCK/img.png?width=2082&amp;amp;height=958&amp;amp;face=0_0_2082_958');&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;[번역] React Server vs Client Component in Next.js 13&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;원 글 링크Next.js 에서, 너는 리액트 서버 컴포넌트와 클라이언트 컴포넌트를 사용할 수 있다. app 경로에서 기본적으로 모든 컴포넌트들은 서버 컴포넌트이다. 이 게시글에서, 우리는 리액트 서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1710410096640&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) 서버 컴포넌트(React Server Component)에 대한 고찰&quot; data-og-description=&quot;이번에 회사에서 신규 웹 프로젝트를 진행하기로 결정했는데, 정말 뜬금 없게도 앱 개발자인 내가 이 프로젝트를 리드하게 되었다. 사실 억지로 떠맡게 된 것은 아니고, 새로운 웹 기술 스택을 &quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@2ast/React-%EC%84%9C%EB%B2%84-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8React-Server-Component%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0&quot; data-og-url=&quot;https://velog.io/@2ast/React-서버-컴포넌트React-Server-Component에-대한-고찰&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dmPZcC/hyVxxhxkvQ/T3IgtTcIucQwhFfgUwpXbk/img.png?width=700&amp;amp;height=350&amp;amp;face=0_0_700_350,https://scrap.kakaocdn.net/dn/6D1xB/hyVALkTPmt/VI74klJO1t6kQvOIlZAyg1/img.png?width=700&amp;amp;height=350&amp;amp;face=0_0_700_350,https://scrap.kakaocdn.net/dn/it3s0/hyVxr2GdJ4/80PsBCCBr4pZ5wYjKiRZf0/img.jpg?width=2160&amp;amp;height=2880&amp;amp;face=558_958_1435_1916&quot;&gt;&lt;a href=&quot;https://velog.io/@2ast/React-%EC%84%9C%EB%B2%84-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8React-Server-Component%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@2ast/React-%EC%84%9C%EB%B2%84-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8React-Server-Component%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dmPZcC/hyVxxhxkvQ/T3IgtTcIucQwhFfgUwpXbk/img.png?width=700&amp;amp;height=350&amp;amp;face=0_0_700_350,https://scrap.kakaocdn.net/dn/6D1xB/hyVALkTPmt/VI74klJO1t6kQvOIlZAyg1/img.png?width=700&amp;amp;height=350&amp;amp;face=0_0_700_350,https://scrap.kakaocdn.net/dn/it3s0/hyVxr2GdJ4/80PsBCCBr4pZ5wYjKiRZf0/img.jpg?width=2160&amp;amp;height=2880&amp;amp;face=558_958_1435_1916');&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) 서버 컴포넌트(React Server Component)에 대한 고찰&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이번에 회사에서 신규 웹 프로젝트를 진행하기로 결정했는데, 정말 뜬금 없게도 앱 개발자인 내가 이 프로젝트를 리드하게 되었다. 사실 억지로 떠맡게 된 것은 아니고, 새로운 웹 기술 스택을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1710410151739&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;[Frontend] React와 Next.js의 차이? / Next.js의 필요성 / Next.js 13버전 변경점&quot; data-og-description=&quot;React와 Next.js의 차이 React는 Javascript 기반의 SPA 웹 프레임워크입니다. 컴포넌트를 활용하여 UI를 쉽고 효율적으로 만들 수 있습니다. 이 글에서 강조하고자 하는 내용은 리액트는 CSR(Client Side Render&quot; data-og-host=&quot;yeongjaekong.tistory.com&quot; data-og-source-url=&quot;https://yeongjaekong.tistory.com/32&quot; data-og-url=&quot;https://yeongjaekong.tistory.com/32&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ba2XGS/hyVxwiBXtK/lgtE0sDTy6VsfPkKKZg1D0/img.png?width=800&amp;amp;height=730&amp;amp;face=0_0_800_730,https://scrap.kakaocdn.net/dn/lBoXC/hyVAChbRcp/IDq1XiyJIkyrbpjwlA2kV1/img.png?width=800&amp;amp;height=730&amp;amp;face=0_0_800_730,https://scrap.kakaocdn.net/dn/bvdPIm/hyVxvxig5W/yQDVPa7zdQ70uWQUUtcGd0/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032&quot;&gt;&lt;a href=&quot;https://yeongjaekong.tistory.com/32&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://yeongjaekong.tistory.com/32&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ba2XGS/hyVxwiBXtK/lgtE0sDTy6VsfPkKKZg1D0/img.png?width=800&amp;amp;height=730&amp;amp;face=0_0_800_730,https://scrap.kakaocdn.net/dn/lBoXC/hyVAChbRcp/IDq1XiyJIkyrbpjwlA2kV1/img.png?width=800&amp;amp;height=730&amp;amp;face=0_0_800_730,https://scrap.kakaocdn.net/dn/bvdPIm/hyVxvxig5W/yQDVPa7zdQ70uWQUUtcGd0/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032');&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;[Frontend] React와 Next.js의 차이? / Next.js의 필요성 / Next.js 13버전 변경점&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;React와 Next.js의 차이 React는 Javascript 기반의 SPA 웹 프레임워크입니다. 컴포넌트를 활용하여 UI를 쉽고 효율적으로 만들 수 있습니다. 이 글에서 강조하고자 하는 내용은 리액트는 CSR(Client Side Render&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;yeongjaekong.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1710410196528&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;React 의 RSC, RCC 에 대하여 (with Next.js)&quot; data-og-description=&quot;React 18 버전이 출시 된 후 Next.js 에서는 app dir 기능이 도입되어 React 의 RSC, RCC 기능을 사용할 수 있게 되었습니다. 이번 포스트에서는 최근 화두인 RSC, RCC 에 대해 한번 정리해보고자 합니다. RSC &quot; data-og-host=&quot;funveloper.tistory.com&quot; data-og-source-url=&quot;https://funveloper.tistory.com/214&quot; data-og-url=&quot;https://funveloper.tistory.com/214&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/crTimD/hyVxygoNUN/kfyHpvv70SFefMPXmj4pXk/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/eZgjc/hyVxCb0QZG/Seefipaqe6GhTjselwIxKk/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/MZuwi/hyVAFydN1k/z7SXUDXMFEKxCbkMSTuxk1/img.png?width=900&amp;amp;height=506&amp;amp;face=0_0_900_506&quot;&gt;&lt;a href=&quot;https://funveloper.tistory.com/214&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://funveloper.tistory.com/214&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/crTimD/hyVxygoNUN/kfyHpvv70SFefMPXmj4pXk/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/eZgjc/hyVxCb0QZG/Seefipaqe6GhTjselwIxKk/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/MZuwi/hyVAFydN1k/z7SXUDXMFEKxCbkMSTuxk1/img.png?width=900&amp;amp;height=506&amp;amp;face=0_0_900_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;React 의 RSC, RCC 에 대하여 (with Next.js)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;React 18 버전이 출시 된 후 Next.js 에서는 app dir 기능이 도입되어 React 의 RSC, RCC 기능을 사용할 수 있게 되었습니다. 이번 포스트에서는 최근 화두인 RSC, RCC 에 대해 한번 정리해보고자 합니다. RSC&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;funveloper.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;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;참고&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710408481442&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;클라이언트 사이드 렌더링(CSR) vs 서버 사이드 렌더링(SSR)&quot; data-og-description=&quot;브라우저 렌더링이란? 브라우저가 서버로부터 요청해 받은 내용을 브라우저 화면(View)에 표시해주는 작업을 말한다. 브라우저가 서버로부터 HTML, CSS, JavaScript 문서를 전달받아 브라우저 엔진이 &quot; data-og-host=&quot;suzzeong.tistory.com&quot; data-og-source-url=&quot;https://suzzeong.tistory.com/139&quot; data-og-url=&quot;https://suzzeong.tistory.com/139&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cgzRux/hyVAIIueBv/buJ6rCLGGF7sE1HFRn9n6k/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/fuiRw/hyVxzsUc2m/I3bYwmTzg7YE9jRuZMhUNk/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/OpwIQ/hyVxB5jt3x/Mw7NGnqiX33FaUJH1JR7A1/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot;&gt;&lt;a href=&quot;https://suzzeong.tistory.com/139&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://suzzeong.tistory.com/139&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cgzRux/hyVAIIueBv/buJ6rCLGGF7sE1HFRn9n6k/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/fuiRw/hyVxzsUc2m/I3bYwmTzg7YE9jRuZMhUNk/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/OpwIQ/hyVxB5jt3x/Mw7NGnqiX33FaUJH1JR7A1/img.png?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720');&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;클라이언트 사이드 렌더링(CSR) vs 서버 사이드 렌더링(SSR)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;브라우저 렌더링이란? 브라우저가 서버로부터 요청해 받은 내용을 브라우저 화면(View)에 표시해주는 작업을 말한다. 브라우저가 서버로부터 HTML, CSS, JavaScript 문서를 전달받아 브라우저 엔진이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;suzzeong.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1710408474522&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;SSR, CSR&quot; data-og-description=&quot;SSR | Server Side Rendering말 그대로 서버쪽에서 렌더링 준비를 끝마친 상태로 클라이어트에 전달하는 방식User가 Website 요청을 보냄.Server는 'Ready to Render'. 즉, 즉시 렌더링 가능한 html파일을 만든다.(&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@kyung-baa/SSR-CSR&quot; data-og-url=&quot;https://velog.io/@kyung-baa/SSR-CSR&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/4XSZD/hyVxo5XaTB/MpmLZsidQkAxX4bOz0sd3k/img.png?width=1680&amp;amp;height=945&amp;amp;face=0_0_1680_945,https://scrap.kakaocdn.net/dn/zpw3l/hyVxygoxnu/6iCMmP1Lkv9fVyKwBbERGk/img.png?width=1680&amp;amp;height=945&amp;amp;face=0_0_1680_945&quot;&gt;&lt;a href=&quot;https://velog.io/@kyung-baa/SSR-CSR&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@kyung-baa/SSR-CSR&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/4XSZD/hyVxo5XaTB/MpmLZsidQkAxX4bOz0sd3k/img.png?width=1680&amp;amp;height=945&amp;amp;face=0_0_1680_945,https://scrap.kakaocdn.net/dn/zpw3l/hyVxygoxnu/6iCMmP1Lkv9fVyKwBbERGk/img.png?width=1680&amp;amp;height=945&amp;amp;face=0_0_1680_945');&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;SSR, CSR&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SSR | Server Side Rendering말 그대로 서버쪽에서 렌더링 준비를 끝마친 상태로 클라이어트에 전달하는 방식User가 Website 요청을 보냄.Server는 'Ready to Render'. 즉, 즉시 렌더링 가능한 html파일을 만든다.(&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&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>웹(Web)</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/162</guid>
      <comments>https://junvelee.tistory.com/162#entry162comment</comments>
      <pubDate>Thu, 14 Mar 2024 19:27:33 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 타입스크립트란 무엇인가? 타입스크립트 동작 원리에 대하여</title>
      <link>https://junvelee.tistory.com/160</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;TypeScript 란 무엇인가?&lt;/u&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. Javascript의 한계&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 언어에는 타입 시스템이 존재하며, 크게 정적 타입 시스템과 동적 타입 시스템으로 나뉘어 진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt1gyw/btsFChPoGDm/Ddj1wqCFfO3EB9aQAR7S51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt1gyw/btsFChPoGDm/Ddj1wqCFfO3EB9aQAR7S51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt1gyw/btsFChPoGDm/Ddj1wqCFfO3EB9aQAR7S51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt1gyw%2FbtsFChPoGDm%2FDdj1wqCFfO3EB9aQAR7S51%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 동적 타입 시스템 = JavaScript, Python&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 타입을 미리 검사하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- &lt;u&gt;개발자의 의도치 않은 타입 실수로 인해 치명적인 오류가 발생할 가능성이 높다.&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;gt; 타입을 미리 검사하지 않기 때문에 타입 오류 시에도 실행이 바로 중단되지 않는다. 때문에 개발자의 타입 실수 시 런타임 중 하루뒤, 한달 뒤 등 예기치 못할 때 갑작스럽게 에러가 발생하는 등 잘 돌아가던 프로그래밍이 갑자기 실행이 안된다던지 치명적인 오류가 발생할 수 있고 디버깅이 힘들다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) 정적 타입 시스템 = C, Java&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 타입을 미리 검사하며, 타입과 관련된 문제 발생 시 즉시 에러를 반환하며 실행이 중단된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 개발자의 타입 실수 시, 즉시 실행이 중단되므로 예상지 못한 실수 발생을 막을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- &lt;u&gt;하지만 모든 변수에 타입을 지정해야 함으로 타이핑양이 굉장히 많아지고 번거롭다(자바스크립트의 장점인 유연함이 x).&lt;/u&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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) Javascript의 한계&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8T2n9/btsFFngIjtR/z1N6qT1PwUxVGri2kz6yW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8T2n9/btsFFngIjtR/z1N6qT1PwUxVGri2kz6yW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8T2n9/btsFFngIjtR/z1N6qT1PwUxVGri2kz6yW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8T2n9%2FbtsFFngIjtR%2Fz1N6qT1PwUxVGri2kz6yW1%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;622&quot; height=&quot;350&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. TS의 타입 시스템 = 점진적 타입 시스템&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 타입스크립트는 독특한 타입 시스템인 &lt;u&gt;'점진적 타입 시스템'&lt;/u&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 정적 + 동적 시스템의 장점들을 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;gt; 정적 타입 시스템과 같이 실행 전 타입을 검사하여 &lt;u&gt;안정성&lt;/u&gt;을 확보하며, 일일히 모든 변수에 타입을 지정하지 않아도 변수에 담기는 초기값을 기준으로 자동으로 변수의 타입을 추론하는 &lt;u&gt;유연함&lt;/u&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjNs5t/btsFDEcjY0V/2CjuCgRfzNDNNpN254KGx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjNs5t/btsFDEcjY0V/2CjuCgRfzNDNNpN254KGx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjNs5t/btsFDEcjY0V/2CjuCgRfzNDNNpN254KGx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjNs5t%2FbtsFDEcjY0V%2F2CjuCgRfzNDNNpN254KGx1%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;따라서 타입스크립트는 점진적 타입 시스템을 채택해서 정적 타입 시스템처럼 프로그램 실행 전에 타입을 올바르게 썼는지 타입 검사를 해 타입 안정성을 확보하면서도 동적 타입 시스템처럼 변수에 우리가 일일히 모두 다 타입을 지정해주지 않아도 되는 유연함까지 확보한 독특한 타입 시스템을 갖추고 있는 똑똑한 언어라는 것이다.&lt;/span&gt;&lt;u&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;TypeScript 의 동작원리&lt;/u&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. 대다수 언어가 동작하는 과정&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFfd4H/btsFCZOFC09/zGzPm7ERkddAMtYbIzQy90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFfd4H/btsFCZOFC09/zGzPm7ERkddAMtYbIzQy90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFfd4H/btsFCZOFC09/zGzPm7ERkddAMtYbIzQy90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFfd4H%2FbtsFCZOFC09%2FzGzPm7ERkddAMtYbIzQy90%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;2. 컴파일 과정&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 컴파일러는 프로그래밍 언어를 바로 바이트코드로 변환하는게 아니라 그 전에 AST(추상 문법 트리)라는 특별한 형태로 먼저 변환한다. AST는 추상 문법 트리 라는 뜻이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 프로그래밍 언어 -&amp;gt; AST 추상 문법 트리 -&amp;gt; 바이트 코드&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OcmxF/btsFDV6io6X/gqkM55IS7vqg93mYHKf4sK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OcmxF/btsFDV6io6X/gqkM55IS7vqg93mYHKf4sK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OcmxF/btsFDV6io6X/gqkM55IS7vqg93mYHKf4sK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOcmxF%2FbtsFDV6io6X%2FgqkM55IS7vqg93mYHKf4sK%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아래는 AST(추상 문법 트리)를 간략하게 나타낸다.&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BvQnI/btsFELhOI9A/igyTWJU6FgiKyTa1jSR9V1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BvQnI/btsFELhOI9A/igyTWJU6FgiKyTa1jSR9V1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BvQnI/btsFELhOI9A/igyTWJU6FgiKyTa1jSR9V1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBvQnI%2FbtsFELhOI9A%2FigyTWJU6FgiKyTa1jSR9V1%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;553&quot; height=&quot;311&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;nbsp;AST(추상 문법 트리)는&amp;nbsp;&lt;span style=&quot;text-align: start;&quot;&gt;코드의 공백이나 주석 탭 등의 코드 실행에 관계없는 그런 요소들은 전부 제거하고 트리 형태의 자료구조에 코드를 쪼개서 저장 해 놓은 그런 형태이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;- 이렇게 코드를 AST로 변환하고 나면 -&amp;gt; 컴파일러가 AST를 -&amp;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 style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. 타입스크립트의 컴파일 과정&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- &lt;span style=&quot;text-align: start;&quot;&gt;우선 다른 언어들과 동일하게 먼저 타입스크립트 코드를 AST로 변환한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;- &lt;span style=&quot;text-align: start;&quot;&gt;그 다음 AST를 -&amp;gt; 바이트코드로 변환하는게 아니라 이 AST를 보고 코드 상 타입 오류가 없는지 타입 검사를 수행한다.&lt;/span&gt;&lt;/span&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAtFkg/btsFFZTWpgQ/R8kjQ3KScDVYFS5XrKJkDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAtFkg/btsFFZTWpgQ/R8kjQ3KScDVYFS5XrKJkDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAtFkg/btsFFZTWpgQ/R8kjQ3KScDVYFS5XrKJkDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAtFkg%2FbtsFFZTWpgQ%2FR8kjQ3KScDVYFS5XrKJkDK%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이때 코드에 타입 오류가 있으면 타입 검사 실패 -&amp;gt; 컴파일이 중단된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 타입 오류가 없는 정상적인 코드라면 타입 검사 성공 -&amp;gt;&amp;nbsp; AST를 바이트코드가 아닌,&amp;nbsp; &amp;lsquo;자바스크립트 코드&amp;rsquo;로 변환하고 컴파일이 종료된다.&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/suYaH/btsFDVZChxe/PAZ2adMmq8VkVZsAreGS41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/suYaH/btsFDVZChxe/PAZ2adMmq8VkVZsAreGS41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/suYaH/btsFDVZChxe/PAZ2adMmq8VkVZsAreGS41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsuYaH%2FbtsFDVZChxe%2FPAZ2adMmq8VkVZsAreGS41%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 이렇게 타입스크립트의 컴파일 결과로 만들어진 자바스크립트 코드를 Node.js나 웹브라우저로 실행하면 앞서 살펴본 대다수의 언어들과 동일한 과정을 거쳐 컴파일 되어 실행된다.&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;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4VTHL/btsFDYaUm5H/sniVpn8oX8zDDdRndrEum0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4VTHL/btsFDYaUm5H/sniVpn8oX8zDDdRndrEum0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4VTHL/btsFDYaUm5H/sniVpn8oX8zDDdRndrEum0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4VTHL%2FbtsFDYaUm5H%2FsniVpn8oX8zDDdRndrEum0%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;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 타입스크립트 코드의 컴파일 과정에 타입 검사가 포함되어 있기 때문에 타입 스크립트 코드를 컴파일 해서 생성한 자바스크립트 코드는 타입 검사를 통과한 &lt;span style=&quot;text-align: start;&quot;&gt;타입 오류가 발생할 가능성이 낮은&lt;/span&gt;&amp;nbsp; 자바스크립트 코드인 것이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;✨ 타입스크립트 컴파일 과정 정리&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;타입스크립트 코드 -&amp;gt; AST 추상 문법 트리 변환 -&amp;gt; 타입 검사(실패시 컴파일 종료) -&amp;gt; 자바스크립트 언어로 변환&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;-&amp;gt; 안전한 자바스크립트 코드 -&amp;gt; AST 추상 문법 트리 -&amp;gt; 바이트 코드 변환 -&amp;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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;+ 타입스크립트 컴파일러에 관하여 실습해 보기&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1709891974019&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;타입스크립트 컴파일러 사용법 (tsc 커맨드)&quot; data-og-description=&quot;Engineering Blog by Dale Seo&quot; data-og-host=&quot;www.daleseo.com&quot; data-og-source-url=&quot;https://www.daleseo.com/tsc/&quot; data-og-url=&quot;https://www.daleseo.com/tsc/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dr2dbF/hyVxChjBCh/IYFiZr3ZkOGfYLfjC8ZjJk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.daleseo.com/tsc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.daleseo.com/tsc/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dr2dbF/hyVxChjBCh/IYFiZr3ZkOGfYLfjC8ZjJk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;타입스크립트 컴파일러 사용법 (tsc 커맨드)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Engineering Blog by Dale Seo&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.daleseo.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>JavaScript/TypeScript</category>
      <author>junvely</author>
      <guid isPermaLink="true">https://junvelee.tistory.com/160</guid>
      <comments>https://junvelee.tistory.com/160#entry160comment</comments>
      <pubDate>Fri, 8 Mar 2024 21:18:18 +0900</pubDate>
    </item>
  </channel>
</rss>