<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jihyun</title>
        <link>https://velog.io/</link>
        <description>https://jihyun-frontend.vercel.app/</description>
        <lastBuildDate>Tue, 27 Sep 2022 07:06:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. jihyun. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/wynter_j" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Next.js와 EmailJS로 백엔드 없이 메일 보내기]]></title>
            <link>https://velog.io/@wynter_j/Next.js%EC%99%80-EmailJS%EB%A1%9C-Contact-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@wynter_j/Next.js%EC%99%80-EmailJS%EB%A1%9C-Contact-%ED%8E%98%EC%9D%B4%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 27 Sep 2022 07:06:02 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요. 정지현 입니다. :)</p>
<p>최근에 포트폴리오 페이지에 간단한 Contact 섹션을 추가 하였는데요.
언제든 저에게 메일을 보낼 수 있도록 하고 싶지만 서버를 24시간 돌리고 싶지는 않아서...😅 javascript API로 바로 메일을 보낼 수 있도록 구현 하였습니다.</p>
<p>방법을 찾던 중 emailjs가 월 500건까지는 무료로 사용이 가능함을 알게 되었고 공식문서도 친절하여서 emailjs로 선택을 했습니다 !
( 만약 파일 첨부와 같은 기능을 사용하려면 돈을 지불해야 합니다. ) </p>
<p>그럼 emailjs 사용법을 간단하게 알아볼게요.</p>
<h2 id="emailjs-사용방법">EmailJS 사용방법</h2>
<h3 id="emailjs-에서-기본-세팅-하기">EmailJS 에서 기본 세팅 하기</h3>
<ol>
<li><p><strong>회원가입</strong>
<a href="https://www.emailjs.com/">https://www.emailjs.com/</a></p>
</li>
<li><p><strong>원하는 이메일 서비스 선택하기.</strong>
<img src="https://velog.velcdn.com/images/wynter_j/post/d2ae2e9f-123b-4960-860b-68623168a937/image.png" alt=""> 서비스를 원하는 이메일을 선택하시면 됩니다.
<img src="https://velog.velcdn.com/images/wynter_j/post/d9b50c03-c4ba-44e9-bb01-1819da370b8a/image.png" alt=""> connect Acount 버튼을 눌러 사용할 이메일 계정을 연결하면 위와 같이 연결된 메일이 보일거에요.  해당 메일이 발신자가 됩니다 !
다 작성 하셨으면 서비스를 생성해주시면 됩니다.</p>
</li>
</ol>
<p>3.** Templates 생성**
  메일 템플릿을 만들어 줄게요. 
  상단 좌측 Email Templates 클릭 후 Create 버튼을 눌러주시면 아래와 같은 화면이 나올거에요.
  <img src="https://velog.velcdn.com/images/wynter_j/post/a35d156c-2418-414a-8602-c1b3a30987ff/image.png" alt=""></p>
<ul>
<li><p>To email : 메일을 받을 주소를 적어주시면 됩니다. 저는 포트폴리오 페이지에 실을거라서 제 개인 메일로 적었어요.</p>
</li>
<li><p>From name : 옵셔널 값입니다. </p>
</li>
<li><p>From email : 보내는 메일 계정이고, emailjs에서는 저희가 연결한 계정이 됩니다.</p>
</li>
<li><p>Replay to : 회신을 보낼 이메일을 명시합니다.</p>
</li>
<li><p>BCC , CC : 숨은 참조, 참조 입니다.  </p>
<p>content에 보시면 
{{ to_name }} {{ from_name }} {{ message }} 중괄호 표시가 있죠? 
중괄호 표현을 사용하여 변수 값을 받을 수 있습니다.
저희 프로젝트에 똑같은 이름으로 변수를 만들어 input을 받고 emailjs에 파라미터로 넘겨주면 각각 맞는 값들이 동적으로 들어오게 됩니다 !</p>
</li>
</ul>
<h3 id="react-nextjs-코드에-적용하기">React (next.js) 코드에 적용하기</h3>
<ol>
<li><p><strong>emailjs SDK 설치</strong></p>
<pre><code class="language-nodejs">npm install @emailjs/browser --save</code></pre>
</li>
<li><p><strong>Form UI를 생성</strong>
 사용자 input을 처리하는 방법을 여러가지가 있지만, emailjs에서 권장하는 방법대로 해볼게요.
 form을 사용했구요 form의 value를 가져오기 위해 useRef를 사용하였습니다.</p>
</li>
</ol>
<pre><code class="language-javascript">
  import { useRef } from &#39;react&#39;
  import emailjs from &#39;@emailjs/browser&#39;
  import style from &#39;./Contact.module.scss&#39;

  const Contact = () =&gt; {
    const form = useRef()

    return (
      &lt;div className={style.contact}&gt;
        // ...
         &lt;form ref={form} onSubmit={onSubmitForm}&gt;
            &lt;label&gt;Name *&lt;/label&gt;
            &lt;inputtype=&quot;text&quot; name=&quot;name&quot; required /&gt;

            &lt;label&gt;Email *&lt;/label&gt;
            &lt;input type=&quot;email&quot; name=&quot;email&quot; required /&gt;

            &lt;label&gt;Message *&lt;/label&gt;
            &lt;textarea name=&quot;message&quot; required /&gt;

            &lt;input
              className={style.submit}
              type=&quot;submit&quot;
              value=&quot;submit&quot;
            /&gt;
          &lt;/form&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    )
  }

  export default Contact
</code></pre>
<ol start="3">
<li><p><strong>메일 보내는 함수 추가</strong></p>
<pre><code class="language-javascript">
import { useRef } from &#39;react&#39;
import emailjs from &#39;@emailjs/browser&#39;
import style from &#39;./Contact.module.scss&#39;

const Contact = () =&gt; {
 const form = useRef()

 // send mail
 const onSubmitForm = (event) =&gt; {
   event.preventDefault()

   try {
     emailjs.sendForm(
       process.env.NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY,
       process.env.NEXT_PUBLIC_MAIL_TEMPLATE_KEY,
       form.current,
       process.env.NEXT_PUBLIC_MAIL_PRIVATE_KEY
     )
     toast.success(&#39;소중한 의견 감사드립니다.&#39;, {
       position: toast.POSITION.TOP_CENTER,
       icon: &#39;💌&#39;,
       hideProgressBar: true,
       className: &#39;toast-message&#39;
     })
   } catch (error) {
     toast.error(&#39;메일 전송에 실패하였습니다. &#39;, {
       position: toast.POSITION.TOP_CENTER,
       icon: &#39;🥲&#39;,
       hideProgressBar: true,
       className: &#39;toast-message&#39;
     })
   }
 }

 return (
   &lt;div className={style.contact}&gt;
     // ...
      &lt;form ref={form} onSubmit={onSubmitForm}&gt;
         &lt;label&gt;Name *&lt;/label&gt;
         &lt;inputtype=&quot;text&quot; name=&quot;name&quot; required /&gt;

         &lt;label&gt;Email *&lt;/label&gt;
         &lt;input type=&quot;email&quot; name=&quot;email&quot; required /&gt;

         &lt;label&gt;Message *&lt;/label&gt;
         &lt;textarea name=&quot;message&quot; required /&gt;

         &lt;input
           className={style.submit}
           type=&quot;submit&quot;
           value=&quot;submit&quot;

         /&gt;
       &lt;/form&gt;
     &lt;/div&gt;
   &lt;/div&gt;
 )
}

export default Contact
</code></pre>
<p>onSubmitForm 함수를 추가해줍니다.
서버 전송 후 새로고침이 되지 않게 preventDefault를 사용합니다.</p>
<p>emailjs.sendForm쪽을 자세히 보면, 기본 형태는 아래와 같습니다. 저는 환경변수를 사용해서 각 키들을 숨겨두었어요.
각각의 키들을 emailjs에서 잘 매칭해서 넣어주기만 하면 되고, 저희는 ref 사용했기 때문에 form.current를 세 번째 인자로 넣어주면 저희가 만들어둔 변수들이 템플릿에 매칭되어서 출력됩니다.</p>
<pre><code class="language-javascript">  emailjs.sendForm(&#39;YOUR_SERVICE_ID&#39;,&#39;YOUR_TEMPLATE_ID&#39;, form.current, &#39;YOUR_PUBLIC_KEY&#39;)
   .then((result) =&gt; {
       console.log(result.text);
   }, (error) =&gt; {
       console.log(error.text);
   });</code></pre>
</li>
</ol>
<hr>
<p>각각의 키들은 요기서 찾을 수 있어요 👀
YOUR_SERVICE_ID <img src="https://velog.velcdn.com/images/wynter_j/post/18a072ec-5762-4c87-8268-5807386cdf3c/image.png" alt=""></p>
<p>YOUR_TEMPLATE_ID</p>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/e2a88011-9ddc-471b-b1bd-7b9eec432588/image.png" alt=""></p>
<p>YOUR_PUBLIC_KEY
<img src="https://velog.velcdn.com/images/wynter_j/post/300a85fd-a5e1-426f-a7d1-b90c47cb9e2e/image.png" alt=""></p>
<p><strong>전체 코드</strong></p>
<pre><code class="language-javascript">import { useRef } from &#39;react&#39;
import emailjs from &#39;@emailjs/browser&#39;
import style from &#39;./Contact.module.scss&#39;

const Contact = () =&gt; {
  const form = useRef()

  const onSubmitForm = (event) =&gt; {
    event.preventDefault()

    try {
      emailjs.sendForm(
        process.env.NEXT_PUBLIC_NEXT_PUBLIC_MAIL_SERVER_KEY,
        process.env.NEXT_PUBLIC_MAIL_TEMPLATE_KEY,
        form.current,
        process.env.NEXT_PUBLIC_MAIL_PRIVATE_KEY
      )
      toast.success(&#39;소중한 의견 감사드립니다.&#39;, {
        position: toast.POSITION.TOP_CENTER,
        icon: &#39;💌&#39;,
        hideProgressBar: true,
        className: &#39;toast-message&#39;
      })
    } catch (error) {
      toast.error(&#39;메일 전송에 실패하였습니다. &#39;, {
        position: toast.POSITION.TOP_CENTER,
        icon: &#39;🥲&#39;,
        hideProgressBar: true,
        className: &#39;toast-message&#39;
      })
    }
  }

  return (
    &lt;div className={style.contact}&gt;
      // ...
      &lt;form ref={form} className={style.form} onSubmit={onSubmitForm}&gt;
          &lt;label&gt;Name *&lt;/label&gt;
          &lt;input className={style.input} type=&quot;text&quot; name=&quot;name&quot; required /&gt;

          &lt;label&gt;Email *&lt;/label&gt;
          &lt;input className={style.input} type=&quot;email&quot; name=&quot;email&quot; required /&gt;

          &lt;label&gt;Message *&lt;/label&gt;
          &lt;textarea className={style.message} name=&quot;message&quot; /&gt;

          &lt;input
            className={style.submit}
            type=&quot;submit&quot;
            value=&quot;submit&quot;
            required
          /&gt;
        &lt;/form&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  )
}

export default Contact
</code></pre>
<h2 id="vercel-배포-시-emailjs-사용하기">vercel 배포 시 emailjs 사용하기</h2>
<p>위의 과정을 잘 마쳤다면 로컬에서 정상적으로 테스트 해볼 수 있을 텐데요.
환경 변수등으로 따로 emailjs 관련 key를 빼두었다면, 빌드 후 프로덕션 환경에서는 메일이 정상적으로 발송되지 않을거에요.</p>
<p>vercel이 해당 변수에 엑세스 할 수 없기 때문이죠.
이럴 땐 배포 대상의 프로젝트에서 직접 환경 변수를 세팅해주면 쉽게 해결 됩니다. 👏</p>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/9139313a-1da2-4ad9-8067-1162010c6363/image.png" alt=""></p>
<p>원하는 값을 key value 형태로 입력해서 등록해주시고, 재배포 진행해주세요!</p>
<p>이제 정상적으로 동작할 겁니다 🎉
<img src="https://velog.velcdn.com/images/wynter_j/post/b7fc4787-6cda-4590-9387-53f4cddf9176/image.png" alt=""></p>
<h3 id="ref">Ref.</h3>
<p><a href="https://www.emailjs.com/docs/examples/reactjs/">https://www.emailjs.com/docs/examples/reactjs/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Bundler] JavaScript 번들러 그리고 Webpack , Parcel , Rollup , Vite... (2)
]]></title>
            <link>https://velog.io/@wynter_j/Bundler-JavaScript-%EB%B2%88%EB%93%A4%EB%9F%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Webpack-Parcel-Rollup-Vite...-2</link>
            <guid>https://velog.io/@wynter_j/Bundler-JavaScript-%EB%B2%88%EB%93%A4%EB%9F%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Webpack-Parcel-Rollup-Vite...-2</guid>
            <pubDate>Sun, 25 Sep 2022 09:29:32 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요. 정지현 입니다 :)</p>
<p>번들러 이해하기 1편에 이어 이번에는 여러 번들러들을 살펴 보려고 합니다.
각 번들러들의 용어나 특징들을 공식문서 위주로 이해해볼게요.</p>
<h1 id="순서">순서</h1>
<ol>
<li><p><del>배경지식</del> </p>
</li>
<li><p><del>번들러가 뭐야 ?</del></p>
</li>
<li><p><del>번들러 더 자세하게 !</del></p>
</li>
</ol>
<p>-------------  <a href="https://velog.io/@wynter_j/Bundler-JavaScript-%EB%B2%88%EB%93%A4%EB%9F%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Webpack-Parcel-Rollup-Vite...-1">👆 번들러 글 1편에 정리되어 있어요    </a>  -------------</p>
<ol start="4">
<li><p>*<em>webpack , rollup , esbuild , vite , parcel 각각 알아보기 *</em></p>
</li>
<li><p><strong>정리</strong></p>
</li>
</ol>
<h1 id="4-webpack--rollup--esbuild--vite--parcel-을-알아보자">4. webpack , rollup , esbuild , vite , parcel 을 알아보자</h1>
<p>JS 프로젝트에서는 모듈화를 위한 많은 번들러가 존재합니다. 
각각의 특징과 핵심 개념 , 장단점을 알아보고 비교해보도록 하겠습니다.</p>
<h2 id="webpack">webpack</h2>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/036c4d31-08ce-4caf-b7c1-5dd58a639673/image.png" alt=""></p>
<p>🔵 <strong>특징</strong></p>
<p><strong>- 오랫동안 사용되어 레퍼런스가 다양해 가장 안정적인 번들러 입니다.</strong>
서드파티 라이브러리 관리나 css 전처리, 이미지 에셋관리 등에 있어서 우수하고 생태계가 가장 풍부하여 다른 번들러들 보다 안정적입니다</p>
<p><strong>- 모든 모듈을 함수로 래핑합니다</strong>
각 모듈을 함수로 감싸고 로더와 모듈 캐시를 구현하는 번들을 생성합니다. 런타임시 각 모듈 함수들이 평가되어 모듈 캐시를 채우게 됩니다. </p>
<p><strong>- JS로 변환하기 위한 로더와 플러그인 설치가 필요합니다.</strong>
웹팩은 자바스크립트밖에 몰라요. 그래서 자바스크립트가 아닌 파일들은 웹팩이 이해할 수 있도록 변경해야 합니다.이 역할을 바로 로더가 해주는거죠. 
로더 :  번들 되기 전 파일 단위를 처리
플러그인 : 번들된 결과물을 추가로 처리. 자바스크립트를 난독화 하는 등의 후처리에 사용.</p>
<p><strong>- 하나의 시작점(entry point)으로부터 의존적인 모듈을 모두 찾아내서 하나의 결과물을 만듭니다.</strong></p>
<p>app.js</p>
<pre><code class="language-javascript">import * as first from &quot;./first.js&quot;
first.printHello() // 3</code></pre>
<p>first.js</p>
<pre><code class="language-javascript">export function printHello() {
  console.log(&#39;Hello&#39;)
}</code></pre>
<p>app.js 부터 시작해 해당 파일에 import된 first.js 파일을 찾은 뒤 하나의 파일로 만드는 방식입니다.</p>
<p>🔵 <strong>핵심 개념</strong></p>
<p><strong>Entry(엔트리)</strong>
엔트리 포인트는 웹팩이 내부 디펜던시 그래프(요거 위에 번들러 프로세스에서 다뤘었죠!)를 생성하기 위해 사용해야 하는 모듈입니다. 쉽게 말하면 의존성 그래프의 시작점을 웹팩에서는 Entry 라고 합니다. </p>
<pre><code class="language-javascript">// webpack.config.js
module.exports = {
  entry: &#39;./src/index.js&#39;
}</code></pre>
<p>엔트리는 최초의 진입점이자 자바스크립트 파일 경로인데요. 웹팩을 실행하면 위의 코드에서 index.js를 대상으로 웹팩이 빌드를 수행하게 됩니다.
웹팩은 엔트리를 통해서 필요한 모듈을 로딩하고 종속성 그래프를 재귀적으로 빌드한 다음에 모든 모듈을 브라우저에 의해 로드되는 작은 수(보통 하나)의 번들로 묶습니다.</p>
<p>엔트리로 지정된 파일에는 당연히 웹 애플리케이션의 전반적인 구조와 내용이 담겨져 있어야 해요. 웹팩이 해당 파일을 가지고 모든 종속성을 이해하고 분석하기 때문에 애플리케이션을 동작시킬 수 있는 내용들이 있어야 합니다 !
SPA 프로젝트에서 app.js 파일 생각해보시면 될 것 같아요.</p>
<p>엔트리는 한 개가 될 수도 있지만 여러개가 될 수도 있어요.</p>
<pre><code class="language-javascript">// 항목을 구분하여 쓰는 경우
module.exports = {
  entry: {
    login: &#39;./src/Login.js&#39;,
     main: &#39;./src/Main.js&#39;},
  output: {
    filename: &#39;bundle.js&#39;,
  },
};

// 배열로 쓰는 경우
module.exports = {
  entry: [&#39;./src/file_1.js&#39;, &#39;./src/file_2.js&#39;],
  output: {
    filename: &#39;bundle.js&#39;,
  },
};</code></pre>
<p>엔트리를 여러개 쓰는 경우는 싱글 페이지 어플리케이션보다 멀티 페이지 어플리케이션에 적합합니다.</p>
<p><strong>Output(출력)</strong>
output 속성은 웹팩으로 번들링을 한 후의 결과물의 파일 경로를 의미합니다.
out의 [name]은 번들의 파일명이 entry의 이름으로 동적 생성할 수 있도록 해줍니다.</p>
<pre><code class="language-javascript">// webpack.config.js

const path = require(&quot;path&quot;);
const webpack = require(&quot;webpack&quot;);

module.exports = {
  mode: &quot;development&quot;,
  entry: {
      wynter : &#39;./src/index.tsx&#39;,
  },
  output: {
    filename: &quot;[name].bundle.js&quot;,
    path: path.resolve(__dirname, &#39;dist&#39;)
  }
};</code></pre>
<pre><code class="language-node.js">npm run build</code></pre>
<p>를 하게 되면 wynter.bundle.js 파일이 생성됩니다 !</p>
<p><strong>Loaders(로더)</strong>
로더는 웹팩이 번들링을 할 때 자바스크립트 파일이 아닌 웹 자원을 변환할 수 있도록 도와줍니다.</p>
<p>웹팩은 모든 파일을 모듈로 바라보는데요. 자바스크립트로 만든 모듈 뿐만 아니라 스타일 , 이미지, 폰트 까지도 전부 모듈로 봅니다.
이것이 가능한 건 웹팩의 로더 덕분인데요. 로더는 타입스크립트 같은 다른 언어를 자바스크립트 문법으로 변환해주거나 이미지를 data url 형식의 문자열로 변환해줍니다. 뿐만 아니라 css 파일을 자바스크립트에서 직접 로딩할 수 있도록 해줍니다. *( 올바른 로더를 적용해주지 않으면 에러가 발생해요 ! )</p>
<pre><code class="language-javascript">const path = require(&quot;path&quot;);
const webpack = require(&quot;webpack&quot;);

module.exports = {
  entry:&#39;./src/index.tsx&#39;,
  module: {
    rules: [
      {
        test: /\.(ts|tsx|js|jsx)$/,
        use: &quot;babel-loader&quot;, // ES5로 변환시켜주는 babel(트랜스파일러) 적용 - babel.config.js에 바벨 설정을 해줍니다.
        exclude: /node_modules/,
      },
      {
        test: /\.scss$/,
        use: [
          &quot;style-loader&quot;, // creates style nodes from JS strings
          &quot;css-loader&quot;, // translates CSS into CommonJS
          &quot;sass-loader&quot; // compiles Sass to CSS, using Node Sass by default
        ],
        exclude: /node_modules/
       },
    ],
  },
};</code></pre>
<p>짠 로더까지 적용을 해보았습니다.</p>
<p><strong>Plugins(플러그인)</strong>
로더와 플러그인은 다릅니다. 플러그인은 웹팩의 기본적인 동작에 추가적인 기능을 제공하는 속성이에요.
로더는 번들 되기 전 파일 단위를 처리, 즉 파일을 해석하고 변환하는 과정에 기여하는 반면에
플러그인은 번들된 결과물을 추가로 처리, 즉 해당 결과물의 형태를 바꾸는 역할을 합니다.</p>
<pre><code class="language-javascript">const HtmlWebpackPlugin = require(&quot;html-webpack-plugin&quot;); // 웹팩으로 빌드한 결과물로 HTML 파일을 생성해주는 플러그인
const path = require(&quot;path&quot;);
const webpack = require(&quot;webpack&quot;);

module.exports = {
  entry:&#39;./src/index.tsx&#39;,
  module: {
    rules: [
      {
        test: /\.(ts|tsx|js|jsx)$/,
        use: &quot;babel-loader&quot;, 
        exclude: /node_modules/,
      },
      {
        test: /\.scss$/,
        use: [
          &quot;style-loader&quot;, 
          &quot;css-loader&quot;,
          &quot;sass-loader&quot; 
        ],
        exclude: /node_modules/
       },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
        template: &#39;public/index.html&#39;,
        // 메타 태그
        meta: {
            &#39;theme-color&#39;: &#39;#4285f4&#39;,
            &#39;description&#39;: &#39;webpack with wynter&#39;,
        },
    }),
    new webpack.ProvidePlugin({ // 자주 사용되는 모듈을 미리 등록하여 매번 작성하지 않게 해줌
      React: &quot;react&quot;,
    }),
  ],
  resolve: {
    alias: {
      &quot;@&quot;: path.resolve(__dirname, &quot;..src/&quot;),
    },
    extensions: [&quot;.js&quot;, &quot;.ts&quot;, &quot;.jsx&quot;, &quot;.tsx&quot;, &quot;.css&quot;, &quot;.json&quot;],
  },
};</code></pre>
<p>짠 플러그인까지 적용을 해보았습니다. 🎉</p>
<p><strong>Mode(모드)</strong>
웹팩 버전 4 부터 mode 라는 개념이 추가되었습니다.</p>
<p>none : 모드 설정 안함
development : 개발 모드
production : 배포 모드</p>
<p>mode를 정의하면 웹팩의 실행 모드가 설정됩니다.
각 실행 모드에 따라 웹팩의 결과물 모습이 달리지는데용. 최적화 또한 mode에 따라 다르게 적용됩니다. </p>
<pre><code>webpack.common.js
webpack.dev.js
webpack.prod.js</code></pre><p>요런식으로 구성 파일을 따로 만들어서 사용할 수도 있어요 !
복잡한 내용은 아니라서 <a href="https://webpack.js.org/configuration/mode/">공식문서</a>로 설명을 대체할게요.</p>
<p><strong><a href="https://webpack.js.org/guides/code-splitting/#root">최적화</a> (Code Splitting / lazy Loading)</strong></p>
<p>코드가 많아지면 번들링된 결과물이 커지게 되면서 브라우저 성능에 영향을 미칩니다. 
웹팩을 통하여 번들된 자바스크립트 파일의 크기를 줄일 수 있는데요, 그 방법은 여러가지가 있습니다.</p>
<p><strong>Code Splitting</strong>
큰 파일을 한 번에 로드하는 것보다 작은 파일 여러개를 동시에 로드 하는 것이 속도면으로 유리합니다.
웹팩에서는 자동으로 중복되는 코드를 판단하여 별도의 청크로 분할하도록 설정할 수 있습니다.
Chunk란, 특정 스크립트와 모두의 부분집합이 되는 파일입니다. </p>
<p>코드를 분할하는 기준 각 프로젝트마다 달라집니다. 라우트 이동에 따라서 불러오는 컴포넌트를 기준으로 Chunk를 나눌 수도 있고, api를 호출하는 기준으로 나눌 수도 있겠죠. 
또한 코드를 분할하는 방법도 크게 세 가지로 나뉩니다.</p>
<ol>
<li><strong>optimization.splitChunks 사용</strong>
웹팩 설정에서 optimization을 추가해주기만 하면 됩니다.
<a href="https://webpack.js.org/guides/code-splitting/#root">공식문서에 최적화 종류와 예제(lodash 종속성 제거)가 너무 잘 나와있어요 👀</a><pre><code class="language-javascript">module.exports = {
 optimization: {
   splitChunks: { chunks: &#39;all&#39; },
 },
}</code></pre>
</li>
</ol>
<ol start="2">
<li><p><strong>엔트리를 여러개로 분리</strong>
 작은 프로젝트에서는 쓸만 한 방법이지만 복잡하거나 큰 프로젝트에서는 좋지 않습니다.</p>
</li>
<li><p>** Dynamic import**
해당 글에 웹팩을 사용하여 React 번들 사이즈를 줄이는 방법이 자세히 나와 있습니다.👀  - <a href="https://www.codemzy.com/blog/react-bundle-size-webpack-code-splitting">https://www.codemzy.com/blog/react-bundle-size-webpack-code-splitting</a></p>
<p>동적 import는 조건에 따라 코드를 불러오는 건데요. React나 Vue에서 널리 사용됩니다.
React에서는 React.lazy를 이용하여 동적으로 컴포넌트를 불러올 수 있습니다. React.lazy()를 사용하면 웹팩은 해당 경로에 대해 별도의 번들을 생성합니다.</p>
</li>
</ol>
<p>참고로 현재 빌드된 결과를 시각적으로 확인할 수 있는 <a href="https://www.npmjs.com/package/webpack-bundle-analyzer">webpack-bundle-analyzer</a> 플러그인도 있으니 활용해보면 좋을 것 같습니다.</p>
<p>🔵 <strong>장점</strong></p>
<ul>
<li>다중 리소스를 지원합니다. - CSS, 이미지 같은 파일도 번들링 할 수 있는 다양한 플러그인이 있어요.</li>
<li>on-demand loading을 지원합니다.</li>
<li>각 모듈을 함수로 감싸기 때문에 안정적입니다. - 전역 스코프에 있던 변수를 지역으로 변경해주기 때문에 충돌 없이 모듈화를 시킬 수 있습니다.</li>
<li>최적화가 가능합니다. - 코드 스플리팅을 이용하여 코드 파일을 청크로 분할해 로드 시간을 줄일 수 있습니다. 또한 mode 옵션을 production으로 설정만 하면 웹팩 내장 플러그인이 프로덕션 모드로 동작하여 최적화 시켜줍니다.</li>
<li>HMR 기능을 통해 일부 모듈의 변경만 감지하여 페이지 갱신 없이 변경사항을 브라우저에 렌더링 할 수 있습니다. - webpack-dev-server 플러그인만 설치하면 해당 옵션이 활성화 돼요.</li>
</ul>
<p>🔵 <strong>단점</strong></p>
<ul>
<li>쪼끔 복잡합니다. 설정을 많이 해야하기 때문에 러닝커브가 있어요.</li>
<li>ES6 모듈 형태로 빌드 결과물을 출력할 수 없어요.</li>
<li>플러그인에 지나치게 의존하면 번들러가 느려질 수 있습니다.</li>
</ul>
<h2 id="rollup">rollup</h2>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/28539848-00e0-4532-9956-68db52b8d7b2/image.jpeg" alt=""></p>
<p>🔵 <strong>특징</strong></p>
<ul>
<li><p>** ES6 모듈 형식으로 빌드 결과물을 생성할 수 있는 번들러 입니다.**
  라이브러리나 패키지에 활용하기 유리합니다. (vue로 롤업을 이용해서 번들링을 진행하고 있어요.)
  일단 트리쉐이킹이 가능하다는 것이 라이브러리에 가장 적합한 번들러인 것 같습니다. 사용자가 라이브러리 코드 일부만 사용했는데 전체 결과가 번들 결과물에 포함된다면 불필요하게 용량을 증가시키겠죠?
  웹팩은 ES6 모듈에서만 지원 가능합니다.</p>
</li>
<li><p><strong>자체 로더가 아니라 ES6를 사용합니다.</strong>
따라서 트리 쉐이킹이 가능합니다. 사실 왜 ES6를 사용하는게 트리 쉐이킹에 용이한지 이해가 안되었는데, 공식문서에 자세히 나와있네요. 후욱 ^^..</p>
<p>CommonJS를 사용하는 경우에는 전체 도구 또는 라이브러리를 가져와야 합니다. 그런데 ES 모듈을 사용하면 필요한 함수만 가져와서 쓸 수 있어요. (문법을 생각해보면 당연한 이야기네요)
롤업은 명시적 import , export를 사용하기 때문에 컴파일된 출력 코드에서 트리 쉐이킹을 하여 최소한의 것들만 번들링 할 수 있습니다.</p>
</li>
<li><p><strong>코드를 동일한 수준으로 올리고(Scope Hoisting) 한 번에 번들링 합니다.</strong>
  한 번에 하기때문에 속도는 웹팩보다 빠르고 번들링 결과물도 가볍습니다. 그러나 변수 충돌에 있어서는 웹팩보다 덜 안정적입니다.</p>
</li>
<li><p><strong>진입점을 다르게 설정하여 번들링 가능합니다.</strong>
  진입점이 다르기 때문에 중복해서 번들링될 수 있는 부분을 알아내고, 독립된 모듈로 분리가 가능합니다. 따라서 코드 스플리팅 측면에서 다른 번들러와 비교해 강점을 보입니다.</p>
</li>
</ul>
<p>🔵 <strong>핵심 개념</strong></p>
<p>롤업의 설정 파일은 선택 사항이지만 권장 됩니다.
웹팩 못지않게 많은 플러그인들이 존재하구요. 플러그인을 통해 번들링 전에 코드를 트랜스파일링 하거나, 써드 파티 모듈을 찾는데 사용할 수 있습니다.</p>
<p>**[설정 파일 주요 항목]
**</p>
<ul>
<li><p><strong>input</strong> 
주요 진입점 입니다.</p>
</li>
<li><p><strong>output</strong> 
 빌드 결과물을 설정합니다. 아래 항목들을 포함합니다.</p>
<ol>
<li><p>file : 생성된 결과물이 위치할 곳을 표시합니다.</p>
</li>
<li><p>format : 롤업은 여러 출력 형식을 제공합니다. </p>
<pre><code class="language-javascript">// CommonJS 스펙을 준수한 모듈로 번들링
// Node.js 에서만 쓸 용도의 라이브러리를 만들 때 용이
export default {
 input: &#39;./src/main.js&#39;,
 output: {
     file: &#39;./build/bundle.min.js&#39;,
     format: &#39;cjs&#39;,  // build시 common js 모듈이 나온다
     name: &#39;bundle&#39;
 }
}
</code></pre>
</li>
</ol>
<p>// ES Module 스펙을 준수한 모듈로 번들링
export default {</p>
<pre><code>input: &#39;./src/main.js&#39;,
output: {
    file: &#39;./build/bundle.min.js&#39;,
    format: &#39;es&#39;,  // build시 es 모듈이 나온다
    name: &#39;bundle&#39;
}</code></pre><p>}</p>
<p>// 브라우저 전용으로 모듈을 번들링
export default {</p>
<pre><code>input: &#39;./src/main.js&#39;,
output: {
    file: &#39;./build/bundle.min.js&#39;,
    format: &#39;iife&#39;, 
    name: &#39;bundle&#39;
}</code></pre><p>}</p>
<pre><code>
3. name : 생성된 번들 이름을 나타내는 전역 변수 이름입니다.
</code></pre></li>
</ul>
<p><strong>[트랜스파일링 설정]</strong>
최신 버전의 ES 를 사용하기 위해 바벨 설정을 해줍니다.</p>
<pre><code class="language-node">npm install @babel/core @babel/preset-env rollup-plugin-babel --save-dev
</code></pre>
<pre><code class="language-javascript">import babel from &#39;rollup-plugin-babel&#39;;

export default {
    input: &#39;./src/main.js&#39;,
    output: {
        file: &#39;./build/bundle.min.js&#39;,
        format: &#39;iife&#39;,
        name: &#39;bundle&#39;
    },
    plugins: [
        babel({
            exclude: &#39;node_modules/**&#39;
        })
    ]
}</code></pre>
<p>🔵 <strong>장점</strong></p>
<ul>
<li>트리쉐이킹이 가능합니다. </li>
<li>번들링한 결과물의 크기가 비교적 작습니다.</li>
<li>기본 설정이 비교적 간단합니다.</li>
<li>코드 스플리팅 측면에서 다른 번들러와 비교해 강점을 보입니다.</li>
</ul>
<p>🔵 <strong>단점</strong></p>
<ul>
<li>input,output이 많아질수록 복잡해질 수 있습니다. (롤업은 다른 번들러와 비교했을때 중복 제거에 특화되어 있기때문에 진입점이 여러개 있을 때 이 부분이 두드러집니다. 하지만 너무 많아지면 설정이 복잡해지겠죠.)</li>
<li>트랜스파일을 하기 위해 플러그인을 사용해야 합니다.</li>
</ul>
<h2 id="esbuild">esbuild</h2>
<p>떠오르는 차세대 자바스크립트 번들러 라고 합니다.esbuild는 웹팩보다 100배 빠르다고 하는데요.
esbuild가 빠른 이유 중 하나는 GO 로 작성 되었다는 점입니다. 
JavaScript는 인터프리터 언어이기 때문에 한줄한줄 기계어로 변환을 합니다. 반면에 GO는 컴파일 단계에서 미리 소스 코드를 전부 기계어로 변환해놓습니다. 
또한 JavaScript는 싱글 스레드 기반이라 한 파일씩 순차적으로 처리되지만 GO의 경우에는 멀티 스레드 기반으로 동작 할 수 있습니다.
즉 esbuild는 코드 파싱과 출력, 소스맵 생성을 모두 병렬로 처리 하기 때문에 빠른 속도를 보장합니다.</p>
<p>🔵 <strong>특징</strong>
다른 번들러들과 다르게 많은 개발자 편의를 제공하지 않습니다. esbuild는 애초부터 자바스크립트를 위한 번들러 입니다. 그저 빌드 도구일 뿐이라 타입 체킹이나 HMR등 번들링과 상관 없는 기능들은 일체 없는 것이죠.</p>
<p>그래서 esbuild는 보통 프레임워크를 기반으로 하는 웹 개발 보다는 바닐라 스크립트 형태의 라이브러리등에 적합했습니다. 2020년에는 esbuild를 통해 개발 모드를 지원하고 실제 번들은 Webpack을 통해 제공하는 Snowpack 이라는 번들러가 나오기도 했습니다. </p>
<p>아래는 esbuild 에서 현재 제공하는 기능들입니다.</p>
<p>Extreme speed without needing a cache
ES6 and CommonJS modules
Tree shaking of ES6 modules
An API for JavaScript and Go
TypeScript and JSX syntax
Source maps
Minification
Plugins</p>
<p>🔵 <strong>핵심 개념</strong></p>
<p><strong>build script 구성 살펴보기</strong></p>
<p>비교적 간단합니다 !</p>
<pre><code class="language-javascript">// build.js
#!/usr/bin/env node

require(&quot;esbuild&quot;)
  .build({
      entryPoints: [&#39;./src/index.ts&#39;],
    outfile: &#39;dist/index.js&#39;,
    bundle: true,
    minify: true,
    platform: &#39;browser&#39;,
    format: &#39;esm&#39;,
    sourcemap: true,
    target: &#39;es6&#39;,
    plugins: [nodeExternalsPlugin()],
    logLevel: &quot;info&quot;, 
  })
  .catch(() =&gt; process.exit(1));</code></pre>
<p>entryPoints: 번들링 알고리즘이 들어가게 되는 애플리케이션의 entry 포인트입니다.
outfile: 번들의 결과물입니다. 하나의 파일만 (문자열만) 가능합니다.
bundle: 번들링 여부 입니다.
minify: minification (자바스크립트 파일 축소) 여부입니다.
platform: 번들링된 파일이 어느 환경에서 실행될지를 설정 합니다.
format: 생성된 파일의 형태를 나타낸다. iife, cjs , esm 가능합니다.
sourcemap: 디버깅을 용이하게 해주는 소스맵 제공 여부를 설정합니다.
target: 어떤 플랫폼의 버전에서 사용할 수 있을지 명시합니다.
logLever : esbuild가 터미널에 경고 및 오류 메세지를 출력하는 수준을 설정합니다.</p>
<p><strong>부분 컴파일 (Incremental Compilation)</strong>
코드가 변경 될 때, 같은 파일을 반복적으로 컴파일해야하는 경우, 부분 컴파일을 사용하면 성능 저하없이 효율적으로 빌드를 수행 할 수 있습니다. 이는 esbuild가 변경된 소스에 대해서만 작업을 수행하기 때문입니다.</p>
<p>🔵 <strong>장점</strong></p>
<ul>
<li>속도가 빠릅니다. (엄청난 장점이죠)</li>
<li>메모리를 효율적으로 사용합니다. </li>
</ul>
<p>🔵 <strong>단점</strong></p>
<ul>
<li>d.ts 생성이 지원되지 않습니다. (별도의 타입 체킹이 이루어지지 않습니다.)</li>
<li>AST(Abstract Syntax Tree) 변환 작업이 지원되지 않습니다. AST 변환을 위해서는 플러그인이 필요합니다.</li>
<li>코드 분할 및 CSS 관련 처리가 아직은 미비합니다.</li>
</ul>
<p>타입체킹 같은 경우에는 별도로 tsc의 타입체킹 기능을 사용하거나, IDE에서 제공하는 타입 체킹을 사용하는 방법으로 보완할 수 있을 것 같습니다. </p>
<h2 id="vite">vite</h2>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/79d194cf-5634-4e8f-8c7b-2ca73e5e7dcc/image.jpeg" alt=""></p>
<p>🔵 <strong>특징</strong>
Vue.js를 개발한 에반 유는 앞서 언급했던 Snowpack의 단점을 보완한 vite를 제작합니다. 처음에는 Vue를 위해 만들어졌으나 지금은 React등 다른 프레임워크와 라이브러리에도 지원 가능합니다. 
esbuild와 다른 번들 도구에서 제공하는 기능들 (ex. 코드 스플리팅, 개발서버)을 하나로 모은 프론트엔드 번들 도구라고 생각하면 될 것 같습니다.</p>
<ul>
<li><p><strong>Dependencies와 SourceCode를 분리하여 빌드합니다.</strong>
<img src="https://velog.velcdn.com/images/wynter_j/post/dc447b40-b527-4afc-a710-9877169c296c/image.png" alt=""></p>
<p>dependencies는 대부분 개발하는 동안 변화가 거의 없는 의존성 모듈들 입니다. vite는 COMMONJS 모듈들을 ESM으로 변환하고 번들링을 진행하는데요, 사전 번들링 작업은 esbuild를 통해 이루어 집니다. </p>
<p>그러나 sourceCode는 우리가 작성 중이 코드로써 변화가 잦습니다 . 하지만 모든 코드가 동시에 로드될 필요는 없는데요. Vite는 브라우저의 요청에 따라 필요한 소스 코드를 변환해서 제공하면 됩니다. (브라우저가 번들러 작업의 일부를 인계 받는다고 생각하시면 됩니다. )</p>
<p>정리하면, esbuild로 미리 트랜스파일링 해놓은 뒤, 로컬에서 개발 서버를 띄우면 소스 코드를 불러오면서 의존성이 있는 패키지만 가져옵니다. 한 번 빌드한 결과는 캐싱을 해두어 다음 개발 빌드 때 바로 뜨게 됩니다.</p>
</li>
<li><p><strong>ESM을 사용하여 매우 빠릅니다.</strong>
Vite는 ESM을 사용하여 매우 빠른데요. vite는 Native ESM을 이용해 소스 코드를 제공하도록 하고 있습니다. 즉, 브라우저가 곧 번들러라는 입니다. vite는 그저 브라우저의 판단 아래 특정 모듈에 대한 소스코드를 요청하면 이를 전달할 뿐입니다. </p>
</li>
<li><p><strong>기본 ES 모듈보다 매우 빠른 Hot Module Replacement 제공합니다.</strong>
번들러가 아닌 ESM을 이용해서 제공하기 때문에 , 어떤 모듈이 수정되면 vite는 그저 수정된 모듈과 관련된 부분만을 교체할 뿐이고, 브라우저에서 해당 모듈을 요청하면 교체된 모듈을 전달 할 뿐입니다. 이 과정에서 ESM을 이용하기 때문에 앱 사이즈가 커져도 HMR을 포함한 갱신 시간에는 영향을 끼치지 않습니다.</p>
</li>
<li><p><strong>Vite는 TypeScript , CSS로더 , HMR을 제공하면서도 복잡한 설정이 필요 없습니다.</strong></p>
</li>
</ul>
<p>🔵 <strong>장점</strong></p>
<ul>
<li>ESM을 이용하여 소스 코드를 제공합니다.
모듈 수정 시 모듈과 관련된 부분만 교체 가능합니다.</li>
<li>번들링 속도에서 큰 메리트가 있습니다.</li>
</ul>
<p>🔵 <strong>단점</strong></p>
<ul>
<li>배포를 위해서는 기존 번들 과정이 필요합니다. 아직 ESM을 프로덕션에 배포하는 것은 비효율적인 부분이 있기 때문입니다. 또한 트리쉐이킹이나 코드 스플리팅과 같은 최적화 기능을 제공하지 않아요. 따라서 기존의 번들링 기법을 최대한 활용하게 되고 내부적으로는 Rollup을 사용하고 있습니다.</li>
<li>아직까지는 SSR 지원 폭이 좁고 안정성이 떨어집니다.</li>
</ul>
<h2 id="parcel">parcel</h2>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/eb683f50-26ea-4f25-885c-351669f076dc/image.jpeg" alt=""></p>
<p>🔵 <strong>특징</strong></p>
<ul>
<li><p><strong>설정이 필요 없는( zero-configuration ) 웹 애플리케이션 번들러 입니다.</strong>
다른 빌더와 다르게 엔트리 포인트를 지정해 주는 것이 아니라 애플리케이션 진입을 위한 HTML 파일 자체를 읽기때문에 별도의 설정 없이도 빌드가 가능합니다.
동적 import()문을 사용해서 출력 번들을 분할할 수 있습니다.  이를 통해 초기 로드시 필요한 것들만 로드할 수 있습니다. 즉, 모든 자산을 한 번에 로드할 필요가 없으며 웹 애플리케이션을 사용하는 사용자는 더 빠르게 로드되는 페이지를 경험할 수 있습니다.</p>
</li>
<li><p>** Assets 기반으로 번들링을 합니다.**
  entry point가 없고 HTML 파일을 읽으면서 JS, CSS, 이미지 에셋등을 직접 참조 합니다. 비슷한 유형의 에셋은 같은 번들로 출력하고 다른 유형은 자식 번들로 만들어 부모 번들에 참조합니다. </p>
<ul>
<li><strong>속도가 빠릅니다.</strong>
캐싱을 하므로 최고 빌드보다는 두 번째 빌드 속도부터 불꽃 튀게 빠릅니다. 전체 캐싱을 지원하고 병렬 처리를 지원하여 속도가 웹팩보다 빠릅니다.</li>
</ul>
</li>
<li><p><strong>자동 변환</strong>
Babel, PostCSSm PostHTML을 사용하는 코드는 자동으로 변환 됩니다.  즉, .babelrc, .postcssrc, .posthtml 같은 설정 파일들을 자동을 읽어와서 세팅을 해줍니다.</p>
</li>
<li><p><strong>HMR</strong></p>
</li>
<li><p><strong>코드 스플리팅</strong></p>
</li>
<li><p><strong>난독화</strong></p>
</li>
</ul>
<p>🔵 <strong>장점</strong></p>
<ul>
<li>애플리케이션의 크기가 커질수록 속도면에서 유의미한 차이를 보입니다.</li>
<li>별도의 설정파일 없이 다양한 변환을 지원합니다.</li>
</ul>
<p>🔵 <strong>단점</strong></p>
<ul>
<li>Assets 유형으로 번들을 생성하기 때문에 JS 안에 CSS를 포함하도록 하려면 별도의 컴포넌트를 사용해야 합니다. </li>
<li>웹팩이나 롤업에 비해 좁은 생태계를 가지고 있고 안정성이 비교적 떨어집니다.</li>
</ul>
<hr>
<h1 id="정리">정리</h1>
<p>번들러별 지원 범위에 대해 참고하기 좋은 사이트가 있어요.(<a href="https://bundlers.tooling.report/">https://bundlers.tooling.report/</a>)
해당 사이트와 오늘 이해한 것 기준으로 정리를 해볼게요.</p>
<blockquote>
<p>웹팩 vs 롤업 vs 바이트 vs 파셀</p>
</blockquote>
<p><strong>webpack</strong> 
광범위한 개발 레퍼런스를 활용하고 많은 서드파티를 필요로 하는 복잡한 어플리케이션이라면.</p>
<p><strong>rollup</strong> 
ES6 모듈 형식으로 빌드 결과물을 출력하여 라이브러리나 패키지에 활용하고 싶다면. 트리 쉐이킹과 같이 효율성을 고려해야 하는 프로젝트라면.</p>
<p><strong>vite</strong>
SPA를 생성하기 위한 Vue CLI/CRA를 대체할 거리를 찾고있다면.</p>
<p><strong>parcel</strong> 
복잡한 설정을 피하고 간단한 애플리케이션을 만들고 싶다면. </p>
<hr>
<p>갈수록 설명이 추상적이고 짧아지는 느낌이네요.😅
아무래도 웹팩의 생태계가 더 커서 훨씬 더 많은 설명과 사례들을 참고할 수 있어서 그런 것 같습니다.</p>
<p>지금은 이론상으로만 각 번들로 들을 비교해 본 거라 각각의 장단점들이 크게 와닿지는 않는 것 같아요. 여러 프로젝트에 직접 사용해 보고 트러블슈팅도 경험해 보아야 확실히 알 수 있겠죠?</p>
<h2 id="ref">Ref.</h2>
<p><strong>webpack</strong>
공식문서 - <a href="https://webpack.js.org/guides/code-splitting/#root">https://webpack.js.org/guides/code-splitting/#root</a></p>
<p>웹팩 번들 사이즈 줄이기 - <a href="https://www.codemzy.com/blog/react-bundle-size-webpack-code-splitting">https://www.codemzy.com/blog/react-bundle-size-webpack-code-splitting</a></p>
<p>웹팩 심화 - <a href="https://jeonghwan-kim.github.io/series/2020/01/02/frontend-dev-env-webpack-intermediate.html#5-%EC%A0%95%EB%A6%AC">https://jeonghwan-kim.github.io/series/2020/01/02/frontend-dev-env-webpack-intermediate.html#5-%EC%A0%95%EB%A6%AC</a></p>
<p><a href="https://dev.to/underscorecode/javascript-bundlers-an-in-depth-comparative-is-webpack-still-the-best-bundler-in-2021-59jk">https://dev.to/underscorecode/javascript-bundlers-an-in-depth-comparative-is-webpack-still-the-best-bundler-in-2021-59jk</a></p>
<p><a href="https://juneyr.dev/2019-02-20/webpack-babel">https://juneyr.dev/2019-02-20/webpack-babel</a></p>
<p><strong>rollup</strong>
롤업 환경 설정 - <a href="https://so-so.dev/tool/rollup/rollupjs-config/#why-not-webpack">https://so-so.dev/tool/rollup/rollupjs-config/#why-not-webpack</a></p>
<p><a href="https://blog.openreplay.com/the-ultimate-guide-to-getting-started-with-the-rollup-js-javascript-bundler">https://blog.openreplay.com/the-ultimate-guide-to-getting-started-with-the-rollup-js-javascript-bundler</a></p>
<p><strong>vite</strong>
공식문서👍 - <a href="https://vitejs-kr.github.io/guide/why.html#the-problems">https://vitejs-kr.github.io/guide/why.html#the-problems</a></p>
<p>vite &amp; svelte - <a href="https://yozm.wishket.com/magazine/detail/1620/">https://yozm.wishket.com/magazine/detail/1620/</a></p>
<p><strong>parcel</strong>
공식문서 - <a href="https://ko.parceljs.org/getting_started.html">https://ko.parceljs.org/getting_started.html</a>
<a href="https://d2.naver.com/helloworld/2838729">https://d2.naver.com/helloworld/2838729</a></p>
<p><strong>esbuild</strong>
공식문서👍  - <a href="https://blog.logrocket.com/getting-started-esbuild/">https://blog.logrocket.com/getting-started-esbuild/</a></p>
<p><a href="https://esbuild.github.io/">https://esbuild.github.io/</a></p>
<p><a href="https://fe-developers.kakaoent.com/2022/220707-webpack-esbuild-loader/">https://fe-developers.kakaoent.com/2022/220707-webpack-esbuild-loader/</a></p>
<p><a href="https://velog.io/@joyact/esbuild#-%EB%B6%80%EB%B6%84-%EC%BB%B4%ED%8C%8C%EC%9D%BC-incremental-compilation">https://velog.io/@joyact/esbuild#-%EB%B6%80%EB%B6%84-%EC%BB%B4%ED%8C%8C%EC%9D%BC-incremental-compilation</a></p>
<p>*<em>번들러 비교
*</em><a href="https://sambalim.tistory.com/137">https://sambalim.tistory.com/137</a></p>
<p><a href="https://blog.linewalks.com/archives/8190">https://blog.linewalks.com/archives/8190</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Bundler] JavaScript 번들러 그리고 Webpack , Parcel , Rollup , Vite... (1)]]></title>
            <link>https://velog.io/@wynter_j/Bundler-JavaScript-%EB%B2%88%EB%93%A4%EB%9F%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Webpack-Parcel-Rollup-Vite...-1</link>
            <guid>https://velog.io/@wynter_j/Bundler-JavaScript-%EB%B2%88%EB%93%A4%EB%9F%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Webpack-Parcel-Rollup-Vite...-1</guid>
            <pubDate>Wed, 21 Sep 2022 06:38:47 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요. 정지현 입니다 :)</p>
<p>많은 JavaScript 프로젝트에서 모듈화를 위해 다양한 번들러를 사용하고 있습니다. 
CRA를 사용하다 보면 굳이 웹팩 설정까지 건들 일이 없었는데, 프로젝트가 고도화될수록 번들러 설정을 구성해야 하는 상황을 마주치게 되더라구요.
프론트엔드 개발자로서 모듈과 번들러를 이해하고 빌드 최적화까지 고려할 수 있어야 더 똑똑하게 개발할 수 있겠쬬 ?</p>
<p>오늘은 왜 우리가 번들러를 사용해야 하는지부터 번들러의 프로세스, 번들러의 종류들을 살펴볼게요.</p>
<h1 id="순서">순서</h1>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/6910553c-ba62-4c9b-a8fb-ece487388ee0/image.png" alt=""></p>
<ol>
<li><p><strong>배경지식</strong> 
자바스크립트의 모듈화</p>
</li>
<li><p><strong>번들러가 뭐야 ?</strong> 
번들러의 기능
갑자기 분위기 Babel (트랜스파일러)</p>
</li>
<li><p>*<em>번들러 더 자세하게 ! *</em>
번들러 프로세스 정리</p>
</li>
<li><p><strong>webpack, Rollup, Parcel, Vite 특징 알아보기  👉 <a href="https://velog.io/@wynter_j/Bundler-JavaScript-%EB%B2%88%EB%93%A4%EB%9F%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Webpack-Parcel-Rollup-Vite...-2">[Bundler] JavaScript 번들러 그리고 Webpack , Parcel , Rollup , Vite... (2)</a></strong></p>
</li>
<li><p><strong>정리</strong></p>
</li>
</ol>
<hr>
<h1 id="1-배경지식">1. 배경지식</h1>
<h3 id="자바스크립트의-모듈화">자바스크립트의 모듈화</h3>
<blockquote>
<p>개발하는 애플리케이션의 크기가 커지면 파일을 여러개로 분리하게 됩니다. 
이때 분리된 파일 각각을 &#39;모듈(module)&#39;이라고 부릅니다. </p>
</blockquote>
<p>** ES5, ES6의 [ export (name,default) | import ] *<em>, *</em>commonJS의 [ module.exports | require ] **문법을 사용하여 쉽게 모듈을 만들 수 있어요. 
플러그인 파일이나 잘개 쪼개진 자바스크립트 코드 조각을 재사용하기 위해서 각각의 파일을 등록하고, 등록된 파일을 자바스크립트에서 불러와서 사용할 수 있게 됩니다.</p>
<p>그렇다면 왜 모듈화가 필요할까요 ? </p>
<ul>
<li><strong>기능의 분리가 가능하고 인터페이스가 단순해집니다.</strong>
하나의 파일에 많은 기능들을 작성하게 되면 코드 의미 파악이 어려워지고 관리가 어려워 집니다. 그렇기 때문에 하나의 파일로 관리하는 것이 아니라 각 기능 별로 파일을 분리해서 관리 하는 것이 필요합니다. </li>
</ul>
<ul>
<li><strong>각 모듈은 자신만의 스코프를 보장해줍니다.</strong>
한 파일 내에 모든 코드를 관리하면 변수나 함수가 중복되거나 다른 기능의 코드끼리 영향을 줄 수 있습니다. 따라서 기능 별로 코드를 분리하여 여러 파일로 나누면 서로 분리된 파일끼리는 영향을 주고받지 않습니다.</li>
</ul>
<ul>
<li><p>*<em>모듈 재사용으로 개발과 유지보수가 용이해집니다. *</em>
예를 들어 공통된 기능이나 UI를 사용하는 부분이 있다면 우리는 이를 공통 컴포넌트로 분리하여 어디서든 사용할 수 있습니다. </p>
</li>
<li><p><strong>디버깅, 테스트시 용이성을 제공합니다.</strong>
특히 단위테스트에 용이합니다. 단위 테스트란 하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트입니다. 해당 부분만 독립적으로 테스트하기 때문에 어떤 코드를 리팩토링하더라도 빠르게 문제 여부를 파악할 수 있습니다.</p>
</li>
</ul>
<pre><code>사실 자바스크립트는 원래 웹페이지 내 보조 작업을 처리하기 위한 언어였기 때문에 다른 언어와 달리 모듈 시스템이 없었습니다. 
초창기 자바스크립트는 주로 웹 서버에서 실행되었고 브라우저는 서버로부터 전달받은 HTML/CSS를 단순히 렌더링만 하는 수준이었죠. 
그런데 자바스크립트로 더 복잡한 작업들을 처리하고자 하는 니즈가 생기게 됨에 따라 자바스크립트는 빠르게 진화하기 시작하였고 모듈시스템도 등장을 하게 되었어요.</code></pre><p><img src="https://velog.velcdn.com/images/wynter_j/post/6d9da374-24ce-431c-9fbe-73f9aa56114e/image.png" alt=""></p>
<pre><code>엄청나죠..? 자바스크립트의 변천사도 굉장히 흥미롭답니다. 
다음에 자바스크립트의 동작 원리와 함께 정리해 봐야겠어요.</code></pre><h1 id="2-번들러가-뭐야-">2. 번들러가 뭐야 ?</h1>
<h3 id="번들러의-기능">번들러의 기능</h3>
<blockquote>
<p>번들러는 의존성이 있는 모듈 코드를 하나 혹은 여러개의 파일로 만들어주는 도구이다.</p>
</blockquote>
<p>React, Angular, Vue와 같은 JS 프레임워크가 등장하면서 웹 사이트를 구축하기 위한 파일들이 점점 많아졌습니다. 이렇게 <strong>많은 모듈들을 하나로 묶는 과정은 어렵습니다</strong>. 
변수 또는 함수명이 중복되는 경우나 모듈 간의 종속성 때문에 배포하기 전에 많은 문제가 발생할 수 있고 많은 시간을 소모하게 됩니다.
그리고** 모든 브라우저에서 모듈 시스템을 지원하는 것은 아닙니다.** 크롬 브라우저 버젼 61부터는 모듈 시스템을 지원하고 있으나 , 지원하지 않는 브라우저도 있습니다. 브라우저에 무관하게 모듈을 사용 할 수는 없을까요 ?</p>
<p>또한 한 페이지에서 사용하는 JS 파일들이 엄청나게 많다고 했을 때, 웹 페이지가 로드될 때 JS 파일 모두를 네트워크를 통해 받아와야 합니다. 이 때 한 번에 요청하는 수가 많아져 <strong>네트워크 병목 현상</strong>이 발생할 수 있어요. 네트워크 속도가 빠르다고 해서 웹 페이지가 완벽하게 로드되는 시간까지 빠른 건 아닙니다. 웹 페이지를 구성하는 js, css , html , 이미지 파일들이 많을 수록 웹 서버에 요청하고 응답을 받는 시간이 길어지게 되는거죠.</p>
<p>모듈 번들러는 위의 문제들을 해결하고 애플리케이션을 최적화 해줍니다.</p>
<p><strong>✅ 번들러의 기능(1) - 모듈 코드를 하나 혹은 여러개의 파일로 묶어주는 도구</strong>
모듈 번들러는 모듈의 의존 관계를 분석하여 브라우저가 인식할 수 있는 자바스크립트 코드로 변환합니다.</p>
<p><strong>[효과]</strong></p>
<ul>
<li><p><strong>모듈 단위로 개발하여 유지 보수성을 높일 수 있다.</strong>
  번들러를 사용하지 않을 때는 각각의 JS 파일을 사용하기 위해 파일의 종속성을 고려하여 많은 스크립트 태그를 추가해야 했는데, 번들러는 파일끼리의 종속성을 알아서 확인하여 묶어줍니다.</p>
</li>
<li><p><strong>한 번에 많은 요청을 하지 않아도 된다.</strong>
모듈 번들러는 JS 모듈을 브라우저에서 실행할 수 있는 단일 JS 파일로 번들링 해줍니다. 따라서 한 번의 네트워크 요청으로 우리는 웹 페이지를 로드할 수 있게 됩니다.</p>
</li>
</ul>
<p><strong>✅ 번들러의 기능(2)  - 최적화</strong>
번들러는 성능 향상을 위해 추가 기능을 제공합니다.</p>
<ul>
<li><p><strong>Tree Shaking</strong>
필요 없는 코드를 제거하고 번들 파일의 크기, 번들링 시간을 줄여줍니다.</p>
</li>
<li><p><strong>HMR (Hot Module Replacement)</strong>
코드가 변경되면 감지하고 브라우저에 최신 코드를 반영하여 자동으로 모듈을 교체합니다. 개발자는 새로고침을 하지 않아도 반영된 것을 빠르게 확인할 수 있으며 변경 사항만 업데이트 하기 때문에 개발 속도가 빨라집니다.</p>
</li>
<li><p><strong>Code Splitting</strong>
JS를 청크로 분할하고, 청크가 필요한 경로에만 제공하여 성능을 향상시킵니다. </p>
<p>모듈 번들러가 의존성 있는 모듈끼리 번들링해서 클라이언트에게 보내 HTTP request 통신 횟수를 최소화 하여 유저의 로딩 시간을 줄였습니다. 그런데 이렇게 되면 하나의 번들 파일의 크기가 너무 커지지 않을까요? 큰 번들을 브라우저에서 파싱하고 컴파일 해야하니 로딩 시간이 더 길어지지 않을까요 ? 맞습니다!
그래서 이러한 문제를 인지하여 코드 스플리팅이라는 개념이 생겼습니다. 하나의 큰 번들을 여러 개의 번들로 쪼개고 필요한 경로에만 제공하여 최적화를 시킵니다. </p>
</li>
<li><p><strong>Transformations</strong>
트랜스파일러를 사용하여 ES6 버전 이상의 스크립트를 사용 가능하게 해줍니다. </p>
<h4 id="갑자기-분위기-babel-트랜스파일러">&gt; 갑자기 분위기 Babel (트랜스파일러)</h4>
<p> ES6나 JSX등의 최신 고급 문법은 구형 브라우저에서 이해하지 못하는 호환성 문제가 존재합니다. 트랜스파일러는 최신 문법을 구형 문법으로 변환해줍니다. 가장 유명한 게 Babel이죠. 그런데 갑자기 웬 트렌스파일러 얘기냐구요?</p>
<p>실무 환경에서는 바벨을 직접 사용하는 것보다 웹팩으로 통합해서 사용하는 경우가 많기 때문이에요. 트랜스파일러는 원본 코드를 구형 버전의 JS로 변환해주어 번들러에 전달해줍니다.
또한 변환 전후의 추상화 수준이 다른 빌드와는 다르게 트랜스파일은 추상화 수준을 그대로 유지한답니다. 
ex. 타입스크립트 → 자바스크립트 , JSX → 자바스크립트 , Sass -&gt; css</p>
</li>
</ul>
<pre><code class="language-javascript">  module: {
    rules: [
      {
        test: /\.(ts|tsx|js|jsx)$/,
        use: &quot;babel-loader&quot;,
        exclude: /node_modules/,
      },
      {
        test: /\.scss$/,
        use: [
          &quot;style-loader&quot;, // creates style nodes from JS strings
          &quot;css-loader&quot;, // translates CSS into CommonJS
          &quot;sass-loader&quot; // compiles Sass to CSS, using Node Sass by default
        ],
        exclude: /node_modules/
       },
    ],
  },</code></pre>
<p>웹팩 config 일부 인데요.  babel-loader 보이시죠? 
웹팩은  babel-loader, css-loader 같은 로더를 사용합니다. 롤업은 플러그인을 사용하고, 파셀은 별도 설정이 없어요.
각 번들러에 대해서는 아래에서 더 살펴볼게요.</p>
<hr>
<p><strong>[ 번들러의 기능 요약 ]</strong></p>
<p> 쉽게 말해 지정한 메인 파일에서 시작하여 자바스크립트의 require과 import(ES6)문을 참고하여 프로젝트의 모든 의존성을 조사하고 로더를 이용해 처리한 후 번들로 묶은 자바스크립트 파일을 생성하는 것입니다.</p>
<p>모듈 번들러의 핵심 작업은 여러 JS 파일을 하나로 결합하여 단일 파일을 만드는 것입니다. 따라서 브라우저는 하나의 단일 파일을 로드하는 것 만으로도 애플리케이션이 동작합니다. JS뿐만 아니라 CSS, 이미지, 글꼴 등 여러 리소스에 대해서도 번들링 할 수 있습니다. 지금은 번들링 뿐만 아니라 빌드 과정에서의 최적화 등도 지원해주고 있어요.</p>
<h1 id="3-번들러-더-자세하게-알아보자-">3. 번들러 더 자세하게 알아보자 !</h1>
<h2 id="번들러-프로세스">번들러 프로세스</h2>
<p>번들링 되는 과정을 이해해 봅시다.</p>
<pre><code>번들러 작동 원리에 대해 잘 쓰여진 글과 발표를 참고하여 정리하였습니다.
시간이 된다면 원문을 읽어 보시는 게 도움이 많이 될거에요 👀</code></pre><ul>
<li><a href="https://www.freecodecamp.org/news/lets-learn-how-module-bundlers-work-and-then-write-one-ourselves-b2e3fe6c88ae/">https://www.freecodecamp.org/news/lets-learn-how-module-bundlers-work-and-then-write-one-ourselves-b2e3fe6c88ae/</a></li>
<li><a href="https://snipcart.com/blog/javascript-module-bundler">https://snipcart.com/blog/javascript-module-bundler</a></li>
<li><a href="https://slides.com/lucianomammino/unbundling-the-javascript-module-bundler-dublinjs#/16">https://slides.com/lucianomammino/unbundling-the-javascript-module-bundler-dublinjs#/16</a></li>
</ul>
<p>번들러는 일반적으로 entry file에서 시작하여 해당 파일에 필요한 모든 항목들을 묶습니다. </p>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/849478f9-8ba2-4a1f-97c6-2e1300406e5c/image.png" alt=""></p>
<p>✅ 이러한 번들러의 작업은 두 단계로 나뉩니다.</p>
<ol>
<li>의존성 그래프 생성 (Mapping a Dependency Graph)</li>
<li>번들링 (Bundling)</li>
</ol>
<p>인데요. 각각 자세히 살펴볼게요.</p>
<h3 id="의존성-그래프-생성">의존성 그래프 생성</h3>
<p>의존성 해결의 목표는 entry point에서 시작하여(예를 들어 app.js) 모든 코드의 종속성(작동에 필요한 다른 코드 조각)을 해결하고 그래프로 구성하는 것입니다. </p>
<p>의존성 그래프 생성을 위해서는 파일의 이름과 식별자, 파일의 경로, 파일의 코드, 파일의 의존성 정보가 필요합니다. 그래프는 각 파일의 종속성을 재귀적으로 파악하여 구축됩니다. JS에서 이러한 데이터를 가장 쉽게 나타낼 수 있는 방법은 객체입니다.</p>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/b2b6eb32-b95a-4b38-9cf8-b0b3174cec1e/image.png" alt=""></p>
<p>이 정보를 바탕으로 엔트리 파일 중심의 관계성 맵을 그리게 되는데요. 각 파일에 고유한 ID를 부여하면서 종속성을 탐색합니다.
이 때 생성되는 것이 <strong>module map</strong> 입니다.</p>
<p>require(&#39;./utils&#39;) 처럼 상대 경로로 import 를 할 때, 모든 것이 패키징 되어 있다면 번들러는 ./utils 파일이 무엇인지 어떻게 알 수 있을까요 ?
해답은 module map 입니다.각 모듈에 대해 고유한 ID값을 가지고 있기 때문에 런타임때 올바른 모듈을 고를 수 있게 되는거죠.
<img src="https://velog.velcdn.com/images/wynter_j/post/1f26d9c2-ae3f-485d-a23d-ebae4eb3196b/image.png" alt=""></p>
<p>마지막으로 모든 의존성을 추출하고, 모든 파일간의 관계를 나타내는 의존성 그래프를 생성합니다.</p>
<p>의존성 그래프를 생성하는 과정이 필요한 이유는 아래와 같습니다.</p>
<ol>
<li>모듈이 의존성 순서를 구성할 수 있게 해주고, 브라우저가 요청했을 때 관련된 함수를 검색할 때 필수적이기 때문입니다.</li>
<li>이름이 중복되어서 충돌나는 것을 막아줍니다. 번들러가 모든 파일의 의존성에 대한 소스맵을 가지고 있기 때문입니다.</li>
<li>사용하지 않는 불필요한 파일을 제거 할 수 있습니다.</li>
</ol>
<h3 id="번들링-bundling">번들링 (Bundling)</h3>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/35fa60c4-d6cf-4091-a614-6f0e597477ec/image.png" alt=""></p>
<p>아웃풋을 만드는 단계를 Packing 이라고 부릅니다. 
이 과정에서는 의존성 그래프를 활용하여 여러 코드 파일들을 통합합니다. 필요한 함수와 module.exports 객체를 주입하고, 브라우저에게 줄 수 있는 static한 결과물을 만듭니다.</p>
<p>즉, 번들링 과정을 통해 모듈을 하나의 실행 가능한 에셋으로 만들게 되는 겁니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/wynter_j/post/c75bcc87-bd23-412a-b6b1-185ecb77dbb5/image.jpeg" alt="">후욱... 넘무 어렵네요. 사실 지금 정리한 거는 번들러의 동작 원리의 큰 개념 정도이구요. 파고 들면 알아야 할 개념들이 더 많답니다. 그럼에도 가장 중요한 것은, 의존성 그래프의 의의를 이해 할 수 있느냐 인 것 같습니다.</p>
<h1 id="4-webpack-rollup-parcel-vite-특징-알아보기">4. webpack, Rollup, Parcel, Vite 특징 알아보기</h1>
<p>_다음 챕터에 계속
_</p>
<h1 id="5-정리">5. 정리</h1>
<p>오늘은 번들러의 기능과 실행 원리에 대하여 알아보았습니다.</p>
<p>사실 번들러를 똑똑하게 쓰려면 자신의 프로젝트를 이해하고 번들러를 사용하는 목적을 이해하며, 해당 번들러의 구성이나 플러그인등을 아는 것이 더 중요할 수 있습니다. 이와 관련해서는 각 번들러의 공식 문서들이 너무너무 잘 되어 있기 때문에 참고하여 프로젝트에 활용해본다면 더욱 성장할 수 있겠죠 ?</p>
<p>프론트 개발을 막 시작했을 때에는 웹팩이나 바벨에 대해 이해하는 건 멀게만 느껴지고 피하고만 싶었는데요. 그래도 개발을 하면서 알고 싶은 욕심이 생기고 실천에 옮기고 있는 것 같아서 즐겁습니다.</p>
<p>다음에는 CRA없이 프로젝트 세팅하기에 대하여 정리해보도록 할게요 !</p>
<h2 id="ref">Ref.</h2>
<p>번들러에 대한 이해 -</p>
<ul>
<li><a href="https://ui.toast.com/fe-guide/ko_BUNDLER">https://ui.toast.com/fe-guide/ko_BUNDLER</a></li>
</ul>
<p>번들러에 대한 이해 (영문) -</p>
<ul>
<li><a href="https://www.innoq.com/en/articles/2021/12/what-does-a-bundler-actually-do/">https://www.innoq.com/en/articles/2021/12/what-does-a-bundler-actually-do/</a></li>
</ul>
<p>번들러 작동 방식을 더 이해하고 싶다면 - </p>
<ul>
<li><a href="https://www.freecodecamp.org/news/lets-learn-how-module-bundlers-work-and-then-write-one-ourselves-b2e3fe6c88ae/">https://www.freecodecamp.org/news/lets-learn-how-module-bundlers-work-and-then-write-one-ourselves-b2e3fe6c88ae/</a></li>
<li><a href="https://slides.com/lucianomammino/unbundling-the-javascript-module-bundler-dublinjs#/66/0/8">https://slides.com/lucianomammino/unbundling-the-javascript-module-bundler-dublinjs#/66/0/8</a></li>
</ul>
<p>번들러를 만들어 보자 ( 작동 방식 이해 심화 ) - </p>
<ul>
<li><a href="https://engineering.linecorp.com/ko/blog/write-you-a-webpack-for-great-good/">https://engineering.linecorp.com/ko/blog/write-you-a-webpack-for-great-good/</a></li>
</ul>
<p>웹팩과 바벨을 더 이해하고 싶다면 -</p>
<ul>
<li><a href="https://berkbach.com/%EC%9B%B9%ED%8C%A9-webpack-%EA%B3%BC-%EB%B0%94%EB%B2%A8-babel-%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-react-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0-fb87d0027766">https://berkbach.com/%EC%9B%B9%ED%8C%A9-webpack-%EA%B3%BC-%EB%B0%94%EB%B2%A8-babel-%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-react-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0-fb87d0027766</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JavaScript] 이벤트 루프]]></title>
            <link>https://velog.io/@wynter_j/JavaScript-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84</link>
            <guid>https://velog.io/@wynter_j/JavaScript-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84</guid>
            <pubDate>Tue, 20 Sep 2022 03:31:17 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요. 정지현 입니다 :)
오늘은 간단하게 이벤트 루프에 대해 이해한 것들을 정리해볼게요.</p>
<h2 id="서론-배경지식">서론 (배경지식)</h2>
<h4 id="✅-자바스크립트의-특징">✅ 자바스크립트의 특징</h4>
<blockquote>
<p>자바스크립트는 <strong>싱글 쓰레드</strong> 기반이며 
논 블로킹 방식의 비동기적인 동시성 언어이다.</p>
</blockquote>
<p>싱글 스레드 언어는 동시에 하나의 작업만을 처리할 수 있어요. 
즉, 브라우저에 내장된 자바스크립트 엔진은 한 번에 한 개의 테스크만 처리합니다.</p>
<p>하지만! 실제로 웹페이지가 실행되는 것만 보아도 많은 작업이 동시에 처리되고 있는 것처럼 보이는데요. 예를 들어 웹브라우저가 사용자의 인풋을 처리함과 동시에 여러개의 HTTP 요청을 처리하기도 하는 것처럼 말이죠. 또, 우리는 setTimeout() 함수로 특정 시간을 기다림과 동시에 다른 코드를 동작시키는 작업들도 할 수 있습니다.</p>
<p><em>분명 자바스크립트는 싱글 스레드인데 어떻게 동시성을 지원하는걸까요 ?</em>
(동시성: 여러 작업이 마치 동시에 일어나는 것처럼 보이는 것)</p>
<p>위의 질문에 해답이 바로, <strong>Event Loop</strong> 입니다.</p>
<h2 id="이벤트-루프">이벤트 루프</h2>
<blockquote>
<p>자바스크립트는 이벤트 루프 기반의 비동기 방식으로 동시성을 지원한다.</p>
</blockquote>
<h4 id="✅-용어-정리-js의-memory-heap--call-stack">✅ 용어 정리 (JS의 Memory Heap &amp; Call Stack)</h4>
<p>Memory Heap - 참조 타입(객체 등) 데이터들이 저장되는 공간입니다. 변수나 상수들에 사용되는 메모리를 저장하는 영역 입니다.</p>
<p>Call Stack - Primary Type(원시 타입) 데이터들이 저장되는 공간입니다. 실행 콘텍스트를 통해 현재 어떤 함수가 동작하고 있는지, 그 함수 내에서 어떤 함수가 동작하는지, 다음에는 어떤 함수가 호출되어야 하는지 등을 제어합니다. </p>
<h4 id="✅-web-api-application-programming-interface">✅ Web API (Application Programming interface)</h4>
<p>이벤트 루프를 이해하기 전에 web API에 대해 알고 가야 합니다.</p>
<p>브라우저는 JS엔진이 제공하지 못하는 기능들을 Web API로 제공합니다. (예를 들어, setTimeout은 JS엔진인 V8에 내장되어 있지 않아요.)
사실 우리는 Web API의 도움을 항상 받고 있습니다. DOM, Ajax, setTimeout(), Event Handler 등과 같이 웹 브라우저에서 제공하는 기능들이 바로 Web API 입니다. </p>
<p>JS엔진 Call Stack에서 실행된 비동기 함수는 Web API를 호출하고, Web API는 콜백함수를 Callback Queue에 집어 넣습니다.</p>
<p>순서대로 다시 정리해보면,</p>
<ol>
<li>JS 엔진의 Call Stack에서 실행된 비동기 함수가 비동기 작업을 요청</li>
<li>해당 비동기 함수는 Web API를 호출</li>
<li>Web API는 브라우저에게 해당 비동기 작업에 대한 정보와 콜백 함수를 넘김</li>
<li>브라우저는 이러한 요청들을 별도에 쓰레드에 위임</li>
</ol>
<p>이렇게 정리할 수 있을 것 같습니다.</p>
<h4 id="✅-이벤트-루프-왜-중요할까">✅ 이벤트 루프 왜 중요할까?</h4>
<blockquote>
<p>이벤트 루프는 메인 스레드의 동작을 관리합니다.</p>
</blockquote>
<p>브라우저 동작의 대부분이 메인 스레드에서 싱글 스레드로 실행이 됩니다. 
싱글 스레드에서 하나의 작업을 하고 있다면 다른 작업은 지연시키기 때문에 하나의 작업이 굉장히 길어진다면 다른 작업은 실행될 수 없겠죠? </p>
<p>그러므로 싱글 스레드의 작업 관리는 매우 중요합니다. 이러한 작업 관리를 해주는 게 이벤트 루프 입니다.</p>
<h4 id="✅-이벤트-루프-동작-원리">✅ 이벤트 루프 동작 원리</h4>
<p>이제 간단한 코드 예제를 보며 이벤트 루프의 동작 순서를 이해해볼게요.</p>
<pre><code class="language-javascript">function response() {
  return setTimeout(() =&gt; {
    return &quot;Hi!&quot;
    }, 1000))
}

response()</code></pre>
<ol>
<li><p>response 함수가 실행되고( = JS콜스택에 추가되고) setTimeout을 반환합니다.</p>
<p>이 때 setTimeout은 Web API가 제공하기 때문에 메인 쓰레드를 막지 않고 작업을 딜레이 시킬 수 있어요.
<img src="https://velog.velcdn.com/images/wynter_j/post/fc271244-5697-4351-a835-c61e947889a6/image.png" alt=""></p>
</li>
<li><p>setTimeout 함수의 콜백 함수인 화살표 함수가 Web API에 저장됩니다.      </p>
</li>
</ol>
<ol start="3">
<li><p>Web API에서는 두 번째 인자인 1000ms 만큼 기다리는 타이머가 실행됩니다</p>
<p>그 동안 JS의 call Stack은 setTimeout 함수와 response 함수를 pop 합니다. (그럼 콜스택이 비어있는 상태가 되겠죠?)
<img src="https://velog.velcdn.com/images/wynter_j/post/7bf34b42-66b7-4d31-8645-d2bb0a794649/image.png" alt=""></p>
</li>
<li><p>콜백 함수는 콜스택에 바로 저장되지 않고 큐로 이동합니다.</p>
<p>모든 비동기 API들은 작업이 완료되면 콜백 함수를 태스크 큐에 추가 합니다.
<img src="https://velog.velcdn.com/images/wynter_j/post/3126329e-fe6c-450c-8ae5-a3950dcadab4/image.png" alt=""></p>
<p>여기서 잠깐! <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#zero_delays">MDN에서 0의 지연 시간</a>에 대해 이렇게 설명하고 있어요.
&quot; setTimeOut 지연시간을 0 으로 지정하는 것이 콜백을 0밀리초 후에 호출한다는 뜻이 아니다. 0의 지연시간을 지정하고 호출하더라도 콜백 함수는 즉시 실행되지 않는다. 즉, 실제 실행 시점은 큐에서 대기 중인 작업의 수에 따라 다르다. setTimeout에 특정 지연 시간을 지정하더라도, 큐에서 대기 중인 모든 메시지의 처리는 기다려야 한다. &quot;</p>
<p>즉, 우리의 예시에서도 1000ms가 지났다고 함수가 바로 실행되는 것이 아니라 1000ms 후에 큐로 이동한다는 것이죠. 실제 실행 시점은 큐에서 대기중인 작업의 수에 달려있는 겁니다.</p>
</li>
</ol>
<ol start="5">
<li><p>드디어 이벤트 루프가 작업을 수행합니다.
콜스택이 비어 있을 때 ( = 이전에 실행된 함수가 모두 값을 리턴했고 스택에서 pop 되었을 때) 콜스택에 큐의 첫 번째 아이템이 추가됩니다.</p>
<p>예제 코드의 콜백 함수가 콜스택에 추가되고, 호출(invoke)되고 , 값을 반환한 뒤 비로소 스택에서 pop 됩니다.
<img src="https://velog.velcdn.com/images/wynter_j/post/95acc47b-ef5b-49dc-aaec-10f14141876e/image.png" alt=""></p>
</li>
</ol>
<p> 실제로 시뮬레이션 해 볼 수 있는 좋은 사이트가 있네요.
 직접 실행하며 예측 해보는 연습을 해보면 좋을 것 같습니다.
<a href="http://latentflip.com/loupe">http://latentflip.com/loupe</a></p>
<hr>
<h2 id="정리">정리</h2>
<p>예제로 다룬 setTimeout 뿐만 아니라 다른 비동기 함수들이나 Node.js의 IO 관련 함수등 모든 비동기 방식의 API들은 이벤트 루프를 통해 콜백 함수를 실행시킵니다. 
그렇기 때문에 이벤트 루프에 대해서 꼭 이해하고 있어야겠죠 ?</p>
<p>오늘은 이벤트 루프의 기본적인 동작 원리만 살펴보았습니다. 
다음에 더 심화로 공부해볼 것은 <strong>Promise와 이벤트 루프</strong> , <strong>큐의 우선순위</strong> 입니다 🙌</p>
<p>! 해당 주제 함께 공부한 신디 덕분에 수월하게 했어요 🙂 </p>
<h3 id="ref">Ref.</h3>
<p>저는 능력 부족으로 예제를 이미지 파일로 첨부하였는데요. 해당 사이트에서 동일한 예제를 gif로 확인하실 수 있습니다. 
<a href="https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif">https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif</a></p>
<p>MDN
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop">https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop</a></p>
<p>Video
<a href="https://vimeo.com/96425312">https://vimeo.com/96425312</a></p>
<p>ETC
<a href="https://meetup.toast.com/posts/89">https://meetup.toast.com/posts/89</a>
<a href="https://tecoble.techcourse.co.kr/post/2021-08-28-event-loop/">https://tecoble.techcourse.co.kr/post/2021-08-28-event-loop/</a></p>
]]></description>
        </item>
    </channel>
</rss>