<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>기록하는 습관</title>
        <link>https://velog.io/</link>
        <description>덕업일치를 지향하는 개발자</description>
        <lastBuildDate>Fri, 23 Feb 2024 05:53:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>기록하는 습관</title>
            <url>https://velog.velcdn.com/images/dev_oreeyo/profile/924c67e6-23b2-4b8f-ab78-ec6b76bd28b8/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 기록하는 습관. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_oreeyo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[enum 보다는 union type ]]></title>
            <link>https://velog.io/@dev_oreeyo/enum-%EB%B3%B4%EB%8B%A4%EB%8A%94-union-type</link>
            <guid>https://velog.io/@dev_oreeyo/enum-%EB%B3%B4%EB%8B%A4%EB%8A%94-union-type</guid>
            <pubDate>Fri, 23 Feb 2024 05:53:24 GMT</pubDate>
            <description><![CDATA[<p>이번 글에서는 enum 대신에 union type을 써야한다는 내용에 대해 써보겠습니다.</p>
<h3 id="얻어갈-수-있는-내용🎯">얻어갈 수 있는 내용🎯</h3>
<ol>
<li>enum 타입의 컴파일 과정과 런타임에 미치는 영향</li>
<li>Tree-shaking</li>
<li>굳이 enum 타입을 쓰는 방법</li>
<li>enum 타입 말고 union type을 써야하는 이유</li>
</ol>
<br>

<h3 id="타입스크립트에서-정적-타입-자체는-런타임에-직접적인-영향을-주지-않습니다🙅♂️">타입스크립트에서 정적 타입 자체는 런타임에 직접적인 영향을 주지 않습니다.🙅‍♂️</h3>
<br>

<p>타입스크립트에서 타입 정보는 컴파일 타임에만 사용되고,
컴파일된 JavaScript 코드에서는 제거되는데요</p>
<p>이는 타입스크립트의 타입 시스템이 런타임에 존재하지 않는다는 것을 의미합니다.</p>
<p><strong>즉, 런타임에는 모든 타입이 사라지고, 순수한 JavaScript 코드만 남게 된다는거죠.</strong></p>
<blockquote>
<p>그런데 말입니다.</p>
</blockquote>
<p>*<em>enum과 같은 특정 타입스크립트 구문은 런타임에도 영향을 줄 수 있는 코드로 변환됩니다.🤯 *</em></p>
<p>예를 들어, 
enum은 컴파일 과정에서 JavaScript 객체로 변환되므로,
이 객체는 런타임에 실제로 존재하게 됩니다. </p>
<p>정적 타입 정보가 아니라, 
타입스크립트의 구조적 특성이 컴파일된 코드에 남아 있음을 의미하게 되는거죠.
<br></p>
<p>이러한 변환이 때때로 Tree-shaking, 
<strong>즉, 불필요한 코드를 제거하는 프로세스를 방해할 수 있습니다.</strong></p>
<blockquote>
<p>Tree-shaking이 뭐에요?? (<del><strong>나무 흔들기 ??</strong></del>)</p>
</blockquote>
<p>Tree-shaking이란 
간단하게 말해 사용하지 않는 코드를 삭제하는 기능을 말합니다.</p>
<p><em>나무를 흔들면 죽은 잎사귀들이 떨어지는 모습에서 따온 이름입니다.</em></p>
<p>Tree-shaking을 통해 export했지만 
아무 데서도 import하지 않은 모듈이나 사용하지 않는 코드를 삭제해서 
번들 크기를 줄여 페이지가 표시되는 시간을 단축할 수 있습니다. </p>
<br>

<blockquote>
<p>그렇다면 enum은 뭔가요?? (<del><strong>이놈 ??</strong></del>)</p>
</blockquote>
<p>enum은 TypeScript가 자체적으로 구현하는 기능입니다.</p>
<p>enum은 열거형 변수로 
정수를 하나로 합칠 때 편리한 기능입니다. </p>
<p>임의의 숫자나 문자열을 할당할 수 있으며 
하나의 유형으로 사용해서 버그를 줄일 수 있습니다.</p>
<hr>
<p><strong>Tree-shaking</strong>은 
ES2015 모듈 문법(import/export)을 사용하는 모듈에서 가장 효과적으로 작동합니다.</p>
<p>ES2015 모듈은 정적 구조를 가지고 있어서,
<strong>빌드 도구</strong>(예: Webpack, Rollup)가 사용되지 않는 코드를 
쉽게 식별하고 제거할 수 있게 해줍니다.</p>
<blockquote>
<p>하지만 TypeScript의 enum은 정적 구조를 갖지 못합니다.</p>
</blockquote>
<p>enum은 객체로 변환되어 각 열거형 멤버에 대해 속성을 추가하는 방식으로 작성되는데요.</p>
<p>__이 과정에서 생성된 코드는 
Tree-shaking이 제대로 작동하지 않을 수 있는 부수 효과를 만들어낼 수 있습니다.
__</p>
<br>
예를 들어, TypeScript에서 다음과 같은 enum을 정의했다고 가정해 보겠습니다.

<pre><code class="language-typescript">// status.ts
export enum Status {
  Active = &#39;ACTIVE&#39;,
  Inactive = &#39;INACTIVE&#39;,
  Pending = &#39;PENDING&#39;
}
</code></pre>
<br>
이 enum을 컴파일한 JavaScript 코드는 대략 다음과 같습니다.

<pre><code class="language-javascript">// 컴파일된 JavaScript
export var Status;
(function (Status) {
    Status[&quot;Active&quot;] = &quot;ACTIVE&quot;;
    Status[&quot;Inactive&quot;] = &quot;INACTIVE&quot;;
    Status[&quot;Pending&quot;] = &quot;PENDING&quot;;
})(Status || (Status = {}));
</code></pre>
<p>JavaScript에 존재하지 않는 것을 구현하기 위해
TypeScript 컴파일러는 IIFE(즉시 실행 함수)를 포함한 코드를 생성합니다.</p>
<p>하지만 Rollup과 같은 번들러는 
IIFE를 <strong>&#39;사용하지 않는 코드&#39;</strong> 라고 판단할 수 없어서 Tree-shaking이 되지 않습니다.</p>
<p>결국 Status를 import하고 실제로는 사용하지 않거나 일부만 사용하더라도
<strong>최종 번들에는 포함되는 것입니다.</strong></p>
<p><strong>각 enum 멤버가 이 enum 객체에 속성으로 추가</strong> 되기 때문입니다.</p>
<br>

<p>다음은 enum을 사용하는 예시 코드입니다</p>
<pre><code class="language-typescript">// main.ts
import { Status } from &#39;./status&#39;;

console.log(Status.Active);
</code></pre>
<p>결과 번들에서는 Status enum의 모든 멤버가 포함되어 있을 겁니다.
Inactive와 Pending은 사용되지 않았지만,
Tree-shaking은 이를 번들에서 제거하지 못하기 때문이죠.
<br>
이와 대조적으로, 
enum 대신 객체 리터럴이나 상수를 사용하면,
Tree-shaking이 더 효과적으로 작동할 수 있습니다. </p>
<p>예를 들어서 코드로 보여주자면,</p>
<pre><code class="language-typescript">// status.ts
export const ACTIVE = &#39;ACTIVE&#39;;
export const INACTIVE = &#39;INACTIVE&#39;;
export const PENDING = &#39;PENDING&#39;;
</code></pre>
<p>그리고 이를 불러와서 사용하는 쪽에서는,</p>
<pre><code class="language-typescript">// main.ts
import { ACTIVE } from &#39;./status&#39;;

console.log(ACTIVE);
</code></pre>
<p>이 경우, INACTIVE와 PENDING은 사용되지 않으므로
Tree-shaking에 의해 제거될 수 있습니다. </p>
<p>모듈 내에서 각 상수는 개별적으로 존재하므로,
사용되지 않는 것들은 최종 번들에서 제외될 수 있습니다.</p>
<p>이러한 이유로,
번들 크기를 최소화하고자 할 때는 TypeScript의 enum 사용을 피하고,
대신 객체 리터럴이나 상수를 사용하는 것이 좋습니다.</p>
<blockquote>
<p>그러면 enum 은 무조건 나쁜걸까?</p>
</blockquote>
<p>무조건이라는건 없죠.</p>
<p>타입스크립트 개발팀에서는
개발자 편의를 위해 enum 을 추가했을텐데요.
많은 언어에는 enum 이 내장되어 있죠.</p>
<p>만약에
자바스크립트에 enum 이 내장되어 있었다면
enum 을 적극적으로 사용하라고 했을겁니다.</p>
<p>enum 이 주는 편의 기능 중에 하나는 자동 완성인데,
Fruit. 을 입력하면 모든 속성을 나열해주죠.</p>
<p>우리는 속성 이름을 몰라도
Fruit 라는 단어만 기억하고 있으면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/dev_oreeyo/post/b3a69080-2fa1-4d01-a704-b642b1bf0165/image.png" alt=""></p>
<p>enum 을 사용하면서도 
런타임에 영향을 주지 않는 한 가지 방법이 있는데요.</p>
<h3 id="바로-const-enum-을-사용하는-것입니다">바로 const enum 을 사용하는 것입니다.</h3>
<pre><code class="language-typescript">const enum Fruit {
  Apple,
  Banana,
  Orange,
}</code></pre>
<p>const enum 을 사용하면 컴파일 후에 객체가 생성되지 않습니다. 
<br></p>
<blockquote>
<p>하지만 그럼에도 불구하고 enum 대신에 union type 을 쓰는걸 추천드립니다.</p>
</blockquote>
<p>그 이유는 생산성과 관련이 있는데요,
enum 은 값을 입력하기 위해서는 import 코드를 작성해야 합니다. 
하지만 union type 은 import 를 할 필요가 없죠.
<br></p>
<p>enum 타입 예시</p>
<pre><code class="language-typescript">// enum 으로 정의한 경우 import 가 필요합니다

// status.enum.ts 파일
export enum Status {
  Active = &#39;ACTIVE&#39;,
  Inactive = &#39;INACTIVE&#39;,
  Pending = &#39;PENDING&#39;
}

// main.ts 파일
import { Status } from &#39;./status.enum&#39;;

function logStatus(status: Status) {
  console.log(status);
}

logStatus(Status.Active); // &#39;ACTIVE&#39;를 출력합니다.</code></pre>
<br>

<p>union 타입 예시</p>
<pre><code class="language-typescript">// main.ts 파일
type Status = &#39;ACTIVE&#39; | &#39;INACTIVE&#39; | &#39;PENDING&#39;;

function logStatus(status: Status) {
  console.log(status);
}

logStatus(&#39;ACTIVE&#39;); // &#39;ACTIVE&#39;를 출력합니다.</code></pre>
<br>

<p>그리고 다음처럼 타입 정보를 알고 있는 상태라면
union type 도 enum type처럼 자동 완성이 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/dev_oreeyo/post/ee878178-e131-4c13-bf7c-dd0c1b01341a/image.png" alt=""></p>
<h3 id="결론--enum-보단-union-타입-씁시다">결론 : enum 보단 union 타입 씁시다.</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[Command not found : tsc]]></title>
            <link>https://velog.io/@dev_oreeyo/Command-not-found-tsc</link>
            <guid>https://velog.io/@dev_oreeyo/Command-not-found-tsc</guid>
            <pubDate>Mon, 19 Feb 2024 10:32:14 GMT</pubDate>
            <description><![CDATA[<br>

<p>npm 명령어로 typescript 컴파일러를 설치했는데도 불구하고
<strong>Command not found : tsc</strong> 가 출력되는 상황이였는데요.</p>
<p>구글링 해보고 path 환경변수 수정해주고
별 짓을 다 했는데도 안되던 상황이였습니다.</p>
<p>파일경로가 잘못된건가 싶어 계속 수정도 해보구요.</p>
<p>tsc 실행 파일이 위치한 디렉토리가 
시스템의 PATH 환경 변수에 자동으로 추가되지 않았기 때문에 발생한 문제로 보고,
다음 단계대로 해봤습니다.
<br></p>
<blockquote>
<ol>
<li>npm의 전역 설치 위치 찾기</li>
</ol>
</blockquote>
<p>먼저, npm이 전역 패키지를 설치하는 위치를 확인하기 위해
다음 명령어를 사용하여 해당 위치를 찾았습니다.</p>
<pre><code class="language-shell">npm config get prefix</code></pre>
<p>이 명령어는 npm의 전역 설치 경로를 출력해주는데요.
macOS 또는 Linux 시스템에서 이 경로는 일반적으로 
/usr/local~~ <strong>또는</strong>
사용자의 홈 디렉토리 내의 .npm-global 폴더일 수 있습니다.</p>
<blockquote>
<ol start="2">
<li>PATH에 npm의 전역 설치 위치 추가</li>
</ol>
</blockquote>
<p>찾은 경로에 /bin을 추가하여 tsc 실행 파일이 있는 정확한 경로를 알아봅니다.
예를 들어, 
npm의 전역 설치 경로가 /Users/yourusername/.npm-global이라면,
실행 파일 경로는 /Users/yourusername/.npm-global/bin이 됩니다.</p>
<p>해당 경로를 PATH 환경 변수에 추가하려면, 터미널에서 다음과 같이 입력합니다 
(bash 또는 zsh 셸을 사용하는 경우):</p>
<pre><code class="language-shell">~/.bash_profile 인 경우

echo &#39;export PATH=&quot;$PATH:/Users/yourname/.npm-global/bin&quot;&#39; &gt;&gt; ~/.bash_profile

~/.zshrc 인 경우
echo &#39;export PATH=&quot;$PATH:/Users/yourname/.npm-global/bin&quot;&#39;
</code></pre>
<p>여기서 /Users/yourusername/.npm-global/bin은 
실제 npm의 전역 설치 경로에 해당합니다.</p>
<blockquote>
<ol start="3">
<li>변경사항 적용</li>
</ol>
</blockquote>
<p>변경한 프로파일 파일을 적용하기 위해 터미널 세션을 재시작하거나, 
다음 명령어로 즉시 적용할 수 있습니다</p>
<pre><code class="language-shell">source ~/.bash_profile

또는

source ~/.zshrc
</code></pre>
<p>이 과정을 통해 tsc 명령어를 사용할 때 발생할 수 있는 PATH 관련 문제를 해결할 수 있고,
tsc 명령어가 시스템의 어디에서나 실행될 수 있게 됩니다.<br><br></p>
<h3 id="이제까지-첫번째-방법이였구요">이제까지 첫번째 방법이였구요.</h3>
<br>


<h3 id="두번째-방법으로는-더-간단한게-있더라구요">두번째 방법으로는 더 간단한게 있더라구요.</h3>
<br>


<p>HomeBrew 를 설치해서 brew 명령어로 해보라는 글을 봤는데요.</p>
<pre><code class="language-bash">brew install typescript </code></pre>
<p>해당 명령어로 다시 설치해보고 tsc를 실행시켰는데 됐습니다.
<br></p>
<p><del>npm 명령어랑 무슨 차이지....?</del></p>
<br>
<br>

<h4 id="궁금해서-찾아본-결과">궁금해서 찾아본 결과</h4>
<p><strong>npm i typescript -g</strong> 명령어와 <strong>brew install typescript</strong> 명령어 
둘 다 TypeScript를 시스템에 설치하지만, </p>
<p>두 명령어는 설치 과정과 환경 설정에 있어 
몇 가지 중요한 차이점이 있었습니다.</p>
<blockquote>
<p>설치 방식의 차이</p>
</blockquote>
<p><strong>npm i typescript -g</strong> 명령어는 
Node.js의 패키지 관리자인 npm을 사용하여 
TypeScript를 전역적으로 설치합니다. </p>
<p>이 방법으로 설치할 경우, 
TypeScript 컴파일러(tsc)는 일반적으로 
<em><strong>Node.js가 설치된 디렉토리 내의 전역 패키지 위치에 설치됩니다.</strong></em>
<br></p>
<p><strong>brew install typescript</strong> 명령어는 
Homebrew를 사용하여 TypeScript를 설치합니다. 
Homebrew는 macOS (또는 Linux) 용 패키지 관리자로, 
소프트웨어를 설치, 관리, 제거하는 데 사용됩니다. 
Homebrew를 사용하여 설치한 패키지는 일반적으로 /usr/local 경로에 설치되며, 
<em><strong>Homebrew가 관리하는 경로에 자동으로 추가됩니다.</strong></em></p>
<br>

<blockquote>
<p>환경 변수 설정의 차이</p>
</blockquote>
<h3 id="npm-i-typescript--g-를-사용하여-설치한-경우">npm i typescript -g 를 사용하여 설치한 경우,</h3>
<p>tsc 실행 파일의 경로를 시스템의 PATH 환경 변수에 직접 추가해야 할 수 있습니다.
<em><strong>특히 npm의 전역 패키지가 설치되는 위치가 
기본 시스템 PATH에 포함되지 않았을 때 필요합니다.</strong></em>
<br></p>
<h3 id="brew-install-typescript를-사용하여-설치한-경우">brew install typescript를 사용하여 설치한 경우,</h3>
<p>Homebrew는 <em><strong>자동으로</strong></em>  설치한 패키지의 실행 파일 경로를 PATH 환경 변수에 추가합니다.
<strong>따라서 사용자가 수동으로 경로를 추가할 필요가 없으며,</strong>
설치 직후 tsc 명령어를 사용할 수 있습니다.</p>
<br>

<h3 id="결론적으로">결론적으로,</h3>
<p>brew install typescript 명령어가 
npm i typescript -g 명령어보다 
macOS에서 더 직관적이고 문제없이 작동하는 경향이 있다는 것 입니다.</p>
<p>Homebrew를 통한 설치가 시스템 환경 변수 설정을 자동으로 관리해 주기 때문에,
사용자가 수동으로 경로를 설정할 필요가 없어서 더 편리합니다.
<br>
<br></p>
<h3 id="mac에서는-명령어는-제발-homebrew-설치해서-사용합시다"><strong><del>mac에서는 명령어는 제발 HomeBrew 설치해서 사용합시다.</del></strong></h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[file-loader 와 url-loader]]></title>
            <link>https://velog.io/@dev_oreeyo/file-loader-%EC%99%80-url-loader</link>
            <guid>https://velog.io/@dev_oreeyo/file-loader-%EC%99%80-url-loader</guid>
            <pubDate>Wed, 07 Feb 2024 06:09:08 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dev_oreeyo/post/5362f056-604f-425a-9ccf-fe87546567c4/image.png" alt=""></p>
<p>이번 글에서는 webpack 로더의 종류인</p>
<p>file-loader 와 url-loader에 대해서 알아보도록 하겠습니다.</p>
<br>
👨‍💻 얻어갈 수 있는 내용


<ul>
<li>file-loader 와 url-loader는 어디서, 어떻게 사용되는걸까?</li>
<li>file-loader 와 url-loader의 차이는 무엇이며, 둘 중에 뭐를 사용해야될까?<br>


</li>
</ul>
<h3 id="webpack-로더"><strong>Webpack 로더</strong></h3>
<p>웹팩은 JavaScript 모듈 번들러로 시작했지만, </p>
<p>시간이 지나면서 CSS, 이미지, 폰트 등과 같은 </p>
<p>다양한 타입의 리소스들을 처리할 필요성이 커졌는데요.
<br></p>
<p>로더 (loaders) 라는 옵션을 사용하게되면</p>
<p>Webpack이 다른 포멧의 파일을 처리하고,</p>
<p>이를 애플리케이션에서</p>
<p>사용할 수 있는 모듈로 변환 할 수 있게됩니다.
<br></p>
<p>로더의 종류 에는</p>
<p><strong>file-loader</strong> 와 <strong>url-loader</strong> 가 있는데,</p>
<p>리소스를 다루는 방식에 있어서</p>
<p>서로 다른 접근 방식을 가지고 있습니다.</p>
<br>

<pre><code class="language-javascript">// webpack.config.js 형식

module.exports = {
  // 모듈
  module: {
    // 규칙
    rules: [
      // 로더 설정
      {
        test: /파일_포멧_정규식/,
        use: [&#39;로더&#39;]
      },
      // 로더 추가 설정...
    ]
  }
}</code></pre>
<br>


<h3 id="file-loader"><strong>file-loader</strong></h3>
<br>
이름 그대로 파일을 로딩해주는 녀석 입니다.

<p>file-loader 는 파일을 output 디렉토리로 복사하고,</p>
<p>파일의 경로를 반환해줍니다.</p>
 <br>

<p>이를 통해 Webpack이 파일을 모듈로 처리할 수 있게 해주고</p>
<p>주로 이미지, 폰트 등과 같은 대용량 리소스를 다룰 때 사용됩니다.
<br></p>
<p>파일을 그대로 output 디렉토리에 복사하고,</p>
<p>최종 번들에는 해당 파일의 최종 URL 경로가 포함되는데요.</p>
 <br>

<p>NPM 명령을 사용해 모듈을 번들링 하면</p>
<p>JS 파일 뿐만 아니라, 이미지 파일까지 모두 번들링 되며</p>
<p>번들링 된 결과물은 배포 디렉토리 (dist) 안에 생성됩니다.</p>
<pre><code class="language-shell">npm run bundle</code></pre>
 <br>

<p>밑에 이미지를 보면,
dist 폴더 안에 결과물이 생성된걸 볼 수 있습니다.
<img src="https://velog.velcdn.com/images/dev_oreeyo/post/eb4db57a-e341-4bf4-adba-1005d0844831/image.png" alt=""></p>
 <br>
 본격적으로 file-loader 설정 코드를 보도록 하겠습니다.
  <br>

<pre><code class="language-javascript">const path = require(&#39;path&#39;);

module.exports = {
  // Entry point 설정
  entry: &#39;./src/index.js&#39;,
  // Output 설정
  output: {
    path: path.resolve(__dirname, &#39;dist&#39;),
    filename: &#39;bundle.js&#39;
  },
  module: {
    rules: [
      {
        test: /\\.(png|svg|jpg|jpeg|gif)$/i,
        use: [
          {
            loader: &#39;file-loader&#39;,
            options: {
              outputPath: &#39;images&#39;, // 이미지가 복사될 서브디렉토리
              name: &#39;[name].[ext]&#39;  // 파일 이름 형식
            }
          }
        ]
      }
    ]
  }
};</code></pre>
<br>

<p><strong>옵션설명</strong> 📝</p>
<ul>
<li><p><strong>test</strong>: 
이미지 파일을 식별하기 위한 정규식입니다.
여기서는 png, jpeg, jpg, gif, svg 형식의 이미지 파일을 대상으로 하는거죠.</p>
</li>
<li><p><strong>loader</strong>: 사용할 로더를 지정합니다. 위 경우에는 file-loader 가 사용됩니다.</p>
</li>
<li><p><strong>options</strong>: 로더에 전달할 추가 옵션을 지정합니다.</p>
</li>
<li><p><strong>name</strong> : name 속성을 사용하여 출력 파일의 이름 형식을 지정할 수 있습니다.</p>
</li>
<li><ul>
<li>[contenthash] 는 파일의 내용을 기반으로 생성된 고유 해시 코드.</li>
</ul>
</li>
<li><ul>
<li>[ext] 는 파일 확장자.</li>
</ul>
</li>
<li><ul>
<li>[name] 은 원본 파일 이름.</li>
</ul>
</li>
</ul>
<br>

<p>이 웹팩 설정 코드는,</p>
<p>확장자가 png, jpeg, jpg, gif, svg  인 파일을 발견하면 file-loader를 적용하라는 의미인데요.
<br></p>
<p>이미지 파일은 dist/images 폴더로 복사됩니다.</p>
<p>이 경로는 outputPath 옵션을 통해 지정되고,</p>
<p>output.path 설정에 따라서 상대적이게 됩니다.</p>
 <br>

<h3 id="근데-왜-굳이-해시코드로-파일-이름을-생성할까요"><strong>근데 왜 굳이 해시코드로 파일 이름을 생성할까요?</strong></h3>
<br>
웹 브라우저는 해시 코드가 포함된 파일 이름을 보고

<p>해당 파일이 변경되었는지 아닌지를 판단하는데요.
<br>
만약 해시 코드가 이전과 다르면,</p>
<p>브라우저는 새로운 파일을 다운로드하고 캐싱합니다.</p>
<p>이렇게 해서 불필요한 네트워크 요청을 줄이고 성능을 향상시킬 수 있는거죠.
<br></p>
<h3 id="public-경로-설정"><strong>Public 경로 설정</strong></h3>
<p>파일을 사용할 때, 
‘파일명.확장자&#39;를 &#39;dist/파일명.확장자’ 로 변경하여 사용할 때도 있는데요.</p>
<p>file-loader가 하는 역할 중 하나입니다.</p>
<pre><code class="language-javascript">module.exports = {
    module: {
        rules: [
              {
            test: /\\.(png|jpe?g|gif|svg|webp)$/i,
            use: {
                  loader: &#39;file-loader&#39;,
                  options: {
                    publicPath: &#39;./dist/&#39;,
                    name: &#39;[name].[contenthash].[ext]&#39;,
                   },
                 },
               },
        ],
    },
}</code></pre>
<p>번들링 된 결과로 처리된 앱을 웹 브라우저에서 확인하면</p>
<p>동적으로 생성된 이미지 모듈 코드가 다음과 같이 나오는걸 볼 수 있습니다.</p>
<pre><code>&lt;img 
  src=&quot;&lt;http://localhost:8080/project/01/dist/632b3c3b709912325de272d52ec0b0aa.png&gt;&quot; 
  alt=&quot;6시에 퇴근하려는데 에러를 발견한 개발자&quot; /&gt;</code></pre><p>이미지 요소의 src 속성을 보면 웹 주소(URI)를 확인할 수 있는데,</p>
<p>위와 같이 전체 도메인 경로가 사용된 걸 볼 수 있습니다.</p>
 <br>

<p>이제 Webpack 구성 파일에 publicPath 설정을 추가해서</p>
<p>공용 디렉토리 (모든 리소스의 기본 위치) 를 설정해보겠습니다.
<br></p>
<pre><code class="language-javascript">// webpack.config.js

module.exports = {
  output: {
    // ...
    publicPath: &#39;dist/&#39;
  }
}</code></pre>
<br>
이렇게 설정한 후에 다시 모듈을 번들링 하게되면,

<p>이미지 경로가 공용 디렉토리에 상대적인 위치로 설정된 것을 확인할 수 있습니다.</p>
<pre><code>&lt;img 
  src=&quot;dist/632b3c3b709912325de272d52ec0b0aa.png&quot; 
  alt=&quot;6시에 퇴근하려는데 에러를 발견한 개발자&quot; /&gt;</code></pre><br>
<br>

<h2 id="url-loader"><strong>url-loader</strong></h2>
<br>
다음은 url-loader 입니다.

<br>

<p>url-loader 가 탄생한 배경과 이유로는,</p>
<br>

<h3 id="첫번째로-성능-최적화">첫번째로 성능 최적화</h3>
<p>웹 애플리케이션에서 여러 작은 이미지나 폰트 파일을 로드할 때,</p>
<p>각각의 HTTP 요청이 성능에 부정적인 영향을 미칠 수 있는데요.</p>
<p>url-loader는 이러한 정적 리소스들을</p>
<p>CSS나 JavaScript 파일 내에 인라인으로 포함시켜,</p>
<p>요청의 수를 줄이고 로딩 시간을 단축시키는 방법을 제공해서 최적화에 기여합니다.
<br></p>
<h3 id="두번째로-데이터-uri-스키마-사용"><strong>두번째로 데이터 URI 스키마 사용</strong></h3>
<p>url-loader는 파일을 Base64 인코딩된 문자열로 변환하여,</p>
<p>데이터 URI 스키마를 사용해 번들 내부에 직접 포함시킵니다.</p>
<p>바이너리 파일을 처리하는 데 사용되며,</p>
<p>이 방식은 작은 크기의 이미지나 폰트 파일에 효과적이고,</p>
<p>외부 파일 요청을 줄여서 최적화에 기여합니다.
<br></p>
<h3 id="세번째로-조건부-처리"><strong>세번째로 조건부 처리</strong></h3>
<p>파일의 크기에 따라 url-loader는 데이터 URI와 별도의 파일 사이에서 선택적으로 처리할 수 있습니다.</p>
<p>이를 통해 개발자는 성능과 요구 사항에 맞춰 최적의 로딩 방식을 선택할 수 있는거죠.</p>
 <br>

<p>url-loader 는 Webpack에서 사용되는 또 다른 로더들 중 하나로,</p>
<p>주로 이미지 파일이나 폰트 파일과 같은</p>
<p>바이너리 파일을 처리하는 데 사용됩니다.</p>
 <br>

<p>파일의 크기가 설정된 제한값 미만일 경우에,</p>
<p>파일을 Base64 형식의 문자열로 변환하여 번들에 직접 포함시킵니다.</p>
 <br>

<p>제한값을 초과할 경우 file-loader처럼 작동하게 되는거구요.
<br></p>
<p>url-loader의 주된 목적은 파일을 데이터 URL로 변환하여</p>
<p>번들에 직접 포함시키는 것으로</p>
<p>HTTP 요청의 수를 줄여서 성능을 향상시키는 데에 있습니다.</p>
<br>
 <br>

<h3 id="동작-원리"><strong>동작 원리</strong></h3>
<p>url-loader 는 지정된 파일을 인코딩하여 Base64 문자열로 변환시켜 줍니다.</p>
<p>이 문자열은 최종적으로 웹 애플리케이션의 JavaScript 번들 안에 포함되는데요.</p>
<p>브라우저에서 이러한 데이터 URL을 만나면,</p>
<p>추가적인 HTTP 요청 없이 해당 리소스를 직접 로드할 수 있게 됩니다.</p>
<br> 

<p>데이터 URL을 통해 리소스가 직접 인코딩되어</p>
<p>JavaScript 파일 내에 포함되므로,</p>
<p>웹 페이지 로드 시에 추가적인 네트워크 요청이 필요 없어지는거죠.</p>
 <br>

<p>하지만,</p>
<p>이 방법은 파일 크기가 커질수록 번들의 크기가 커지는 단점이 있습니다.</p>
<p>따라서 작은 이미지나 글꼴 파일에 주로 사용되며,</p>
<p>큰 파일의 경우 다른 방법을 사용하는 것이 좋겠습니다.</p>
 <br>

<p>예를 들어, 위에서 봤던 file-loader 를 사용하여</p>
<p>리소스를 별도의 파일로 분리하고</p>
<p>URL을 통해 참조하는 방식이 그 예 입니다.
<br></p>
<h3 id="url-loader-기본-설정"><strong>url-loader 기본 설정</strong></h3>
<p>url-loader 를 사용하기 위해서는 
먼저 npm을 통해 패키지를 설치해야 합니다.</p>
<br>

<pre><code class="language-shell">npm install url-loader --save-dev</code></pre>
<br>

<p>그 후,
Webpack 구성 파일(webpack.config.js)에 
url-loader 를 설정 해줍니다.</p>
<p>가장 기본적인 설정은 다음과 같습니다</p>
<br>

<pre><code class="language-javascript">module.exports = {
  module: {
    rules: [
      {
        test: /\\.(png|jpe?g|gif|svg)$/,
        use: {
          loader: &#39;url-loader&#39;,
        },
      },
    ],
  },
};</code></pre>
<p>이 기본 설정은 
png, jpeg, jpg, gif, svg 형식의 이미지 파일을 
데이터 URL로 변환하여 처리하게 합니다.</p>
<br>

<p><strong>옵션설명</strong> 📝</p>
<p>url-loader 는 다양한 옵션을 제공하는데요.</p>
<p>가장 중요한 옵션 중 하나는 limit 입니다.</p>
<p>이 옵션은 파일 크기의 임계값 (바이트 단위) 을 지정하고,</p>
<p>파일 크기가 이 임계값 미만인 경우 데이터 URL로 변환되고,</p>
<p>그 이상인 경우 별도의 파일로 분리됩니다.</p>
<p>별도의 파일로 분리될 때는 file-loader가 사용되는거죠.</p>
<pre><code class="language-javascript">{
  test: /\\.(png|jpe?g|gif|svg)$/,
  use: {
    loader: &#39;url-loader&#39;,
    options: {
      limit: 8192, // 8KB
    },
  },
}</code></pre>
<p>여기서는 8KB 미만의 이미지 파일이 데이터 URL로 변환되어 번들에 포함됩니다.</p>
 <br>

<h4 id="8kb-이상인-경우"><strong>8KB 이상인 경우,</strong></h4>
<h4 id="file-loader-가-적용되어-별도의-파일로-추출되는거구요"><strong>file-loader 가 적용되어 별도의 파일로 추출되는거구요.</strong></h4>
 <br>

<p>url-loader 의 다른 옵션으로는</p>
<p>mimetype (변환할 파일의 MIME 타입을 명시적으로 지정),</p>
<p>name (추출된 파일의 이름 패턴을 지정),</p>
<p>fallback (임계값보다 큰 파일을 처리하기 위해 사용할 대체 로더를 지정) 등이 있습니다.</p>
 <br>

<p>url-loader 를 사용하면</p>
<p>웹 애플리케이션의 성능을 향상시키는 동시에,</p>
<p>번들 크기를 최적화하는 데 도움이 될 수 있습니다.
<br></p>
<p>하지만 데이터 URL로 변환된 큰 파일은 번들 크기를 증가시킬 수 있으므로</p>
<p>적절한 limit 값을 설정하는 것이 중요합니다.</p>
 <br>

<p>인라인으로 변환되는 파일의 크기는 신중하게 선택해야 합니다.
너무 많은 데이터가 인라인으로 포함되면 
번들의 크기가 커져서 오히려 성능 저하를 유발할 수 있으니까요.</p>
]]></description>
        </item>
    </channel>
</rss>