프론트엔드 개발 도구에 대한 이해 - 빌드 도구와 모듈 번들러 (feat. 모듈의 탄생)

이보경·2024년 1월 18일

개발 환경

목록 보기
3/3
post-thumbnail

지난번 빌드 도구(CRA와 Vite)에 대한 질문을 GPT에게 물어보고 막연한 궁금증을 풀어보았다.
이번에는 모듈부터 빌드 도구 내에서 번들할 때 사용되는 다양한 번들러에 대해 알아보고자 한다.


📌 웹팩이전의 세계와 모듈의 개념

생활코딩

웹팩은 흔히 알고 있는 모듈 번들러이다. 모듈 번들러란 무엇이고 어떤 문제를 해결하기위해 탄생하게 되었을까?

우선 모듈 번들러가 등장하기 전에는 다음과 같은 문제가 있었다.

// World 출력
스크립트가 순차적으로 실행될 때, 별개의 자바스크립트 파일에서 불러왔지만 변수이름이 충돌해 아래 파일(word.js)의 값으로 덮어 씌어진다. 스크립트를 분리해도, 파일을 분리해도 var로 선언된 word 변수는 전역 변수가 되기 때문이다.

각각의 변수를 독립적으로 사용할 수 없을까? 그래서 탄생한 것이 '모듈'이다.
모듈은 관련된 기능이나 변수, 클래스, 함수 등을 포함하고 있는 코드의 집합을 독립적인 단위로 사용하는 것을 말한다.

JavaScript ES6부터는 import와 export 키워드를 사용하여 모듈을 정의하고 가져올 수 있게 되었다. (ESM, ES6 Module)

// Hello World 출력
이처럼 각 파일 단위로 스코프를 제한하여 모듈 간의 이름 충돌을 방지할 수 있다.

이런 모듈의 기능은 최신 브라우저에만 탑재되어 있으며, 각각의 파일(모듈)별로 모두 불러와야 한다는 문제가 있다. (아래 이미지처럼 모듈 파일이 100개라면 100+번의 네트워크 통신을 해야한다.) 초기 로딩 속도가 저하되고 네트워크의 부하로 서비스 제공이 느려진다.

개발자들은 이러한 모듈을 하나로 합쳐서 제공하는 방법을 고민했고, 그렇게 탄생한 것이 바로 모듈 번들러이다.

뿐만 아니라
더 작은 용량의, 더 최적화된 리소스를 제공해주기,
흩어져 있는 여러 파일을 하나로 통합하고 문자를 압축시키기,
다양한 사용자 환경에서도 돌아가도록 코드를 변환하기,
안 쓰이는 소스코드 부분을 분석해서 제거하기,
...

웹사이트 전처리 요구사항이 점점 많아지면서 이를 자동화시켜줄 도구가 필요했다.
여기서 grunt glub 같은 도구가 하나 둘 등장하기 시작했고 마침내 webpack의 시대가 도래하게 되었다.

// 웹팩을 이용해 번들링한 파일을 네트워크 탭에서 확인하는 화면
이렇게 변환하는 과정은 생활코딩 - 4. 웹팩의 도입을 참고하면 된다.


📌 모듈 시스템

CommonJS

브라우저 외의 환경(Node.js)에서 작동하도록 만들어진 모듈 시스템
비동기 모듈 로드에 대한 부분은 고려되지 않음

AMD(Asynchronous Module Definition)

비동기 모듈 로드 지원

-> 시간이 지나면서 CommonJS와 AMD 사이에서 호환성 문제가 발생

ES6 모듈 (ESM)

<script type=’module” src=”app**.mjs**”></script>
기본적으로 strict mode 적용
모듈 스코프, export, import

  • 모듈 내에서 var 키워드로 선언한 변수는 → 전역 변수 x, window객체의 프로퍼티 x
  • import시 파일 확장자를 생략할 수 없음
  • as 키워드
  • default 키워드
    • 이름없이 하나의 값을 export함, var/let/const 키워드 사용 불가, {} 없이 임의의 이름으로 import함

📌 모듈 번들러

그래서 모듈 번들러란,

  • 의존성이 있는 여러개의 JS파일을 하나의 JS파일로 합쳐주는 도구
  • 번들러 설정에 따라서 CSS나 이미지 파일 같은 것도 같이 취급할 수 있음
  • Webpack, Parcel, Rollup, Browserify 등

역할

  • 모듈 번들링
    : 웹 애플리케이션에서 사용되는 JavaScript, CSS, 이미지 등의 모든 자원을 모듈로 관리하고, 이를 하나의 번들 파일로 묶어줍니다.
  • 의존성 해결
    : 애플리케이션의 모듈 간의 의존성을 분석하여 필요한 모듈을 동적으로 로드하고 순서대로 실행할 수 있게 해줍니다.
  • 번들 최적화
    : 중복되는 코드나 사용되지 않는 코드 등을 제거하여 번들 크기를 최소화하고 로딩 속도를 향상시킵니다.
  • 코드 스플리팅
    : 애플리케이션을 여러 개의 작은 청크(chunk)로 분할하여 필요한 부분만 로드하여 초기 로딩 시간을 단축합니다.
  • 리소스 관리
    : 번들에 포함된 이미지, 폰트 등의 리소스를 관리하고 필요한 경우 최적화하여 제공합니다.

종류

차세대 번들러 비교 및 분석 (feat. webpack, rollup, esbuild, vite)

2022 stateofjs 자료를 참고해보면 번들러의 생태계는 다음과 같다.

vite > esbuild > rollup > parcel > webpack

webpack부터 차례대로 살펴보자.

Webpack

대표적인 자바스크립트 번들러로,
많은 기능과 확장성으로 좀 더 복잡한 프로젝트에서도 효율적으로 모듈을 관리할 수 있도록 도와줌

  • 모듈 번들링(Module Bundling): 진입점에 연결된 파일을 단일 파일로 묶어준다.
  • 번들 최적화(Automatic Bundle Optimization): 번들 최적화를 통해, 보다 더 작은 번들을 생성하고 그만큼 빠르게 로딩할 수 있다.
  • 코드 스플리팅(Code Splitting): 모듈을 청크(chunk)로 분리하여, 동적으로 필요한 모듈만 로딩할 수 있다.
  • 트리 쉐이킹(Tree Shaking): 사용되지 않는 코드를 제거해 번들의 크기를 줄이고 성능을 향상시킬 수 있다.
  • 개발 서버 실행(Development Server): 코드가 변경될 때마다 브라우저에 반영(HMR)되는 개발용 서버를 실행할 수 있다.
  • 정체성은 번들러의 목적인 "통합"
  • 설정이 간편하고 직관적
    하나의 설정 파일에서 원하는 번들이 생성 될 수 있도록 컨트롤할 수 있다.
    entry와 output을 명시하고 어떤 plugin과 loader로 파일들을 다룰 건지 명시하면 된다.
    Webpack 공식문서 - 웹팩의 핵심개념(Entry, Output, Loaders, Plugins, Mode)
  • 풍부한 plugins과 loaders
    쉽게 plugin과 loader를 부착할 수 있어 강력한 개발 커뮤니티가 뒷바침해주고 있다.
  • 강력한 개발서버
    webpack은 Hot Module Replacement(HMR)를 처음으로 제안했고 2012년부터 사용되어왔다.
    HMR는 소스코드의 변화를 감지하여 브라우저를 직접 새로고침할 필요가 없이 변화를 바로 반영해준다
  • Code Splitting.
    번들 로드 최적화하는 작업이다.
    파일들을 여러 번들 파일으로 분리하여 병렬로 스크립트를 로드하여 페이지 로딩속도를 개선할 수 있다.

Rollup

  • 정체성은 "확장"
  • 작은 코드조각들을 거대하고 복잡한 어플리케이션 혹은 라이브러리로 만들어 준다고 스스로 소개

    "어플리케이션 만들 땐 webpack으로, 라이브러리 만들 땐 rollup으로!"

  • rollup vs. webpack
    • rollup이 좀 더 빠르다. webpack은 모듈들을 함수로 감싸서 평가하는 방식을 사용하지만, rollup은 모듈들을 호이스팅하여 한번에 평가하기 때문에 성능상 이점이 있다.
    • rollup은 더 가벼운 번들을 생성한다. tree shaking은 기본적으로 ES6 코드에서 제대로 동작한다.
    • rollup은 CommonJS 코드를 ES6코드에서 사용할 수 있다.

esbuild

  • ESBuild는 내부적으로 Go로 작성되어 JS 기반의 번들러보다 10배에서 100배까지 빠른 엄청난 퍼포먼스를 보인다.
    • 빠른 이유: 네이티브 코드 방식 사용, 병렬처리 최적화, 메모리 사용 최적화, 자체 JavaScript 파서 사용
  • 번들러로서 필수적인 기능들이 갖춰져 있지만 아직까지도 메이저 버전이 릴리즈 되지 못했다. (현재 기준 v0.20.1)
  • 하지만 설정이 webpack, rollup처럼 유연하지 못하고 아직 안전성 관련 이슈가 있다.
    • code splitting 및 CSS와 관련된 처리가 아직 미비함
    • esbuild는 es5 이하의 문법을 아직 100% 지원하지 않음

Vite

ESBuild의 단점을 보완시킨 라이브러리,
Vue.js의 창시자인 Evan You가 만든 frontend build tool

  • native ES modules 기반의 강력한 개발서버
  • esbuild로 파일들을 통합하고 rollup을 통해 번들링

전반적으로 esbuild로 성능을 극적을 끌어오고 rollup을 통해서 번들링의 유연성을 챙겼다고 볼 수 있음

⭐️ 공식문서 - Vite를 사용해야 하는 이유

  • 개발 서버 구동 시간이 거의 0에 가까움
  • 모든 CommonJS 및 UMD 파일을 ESM으로 불러올 수 있도록 변환함
  • 별도의 설정이 없이 다양한 리소스 import 가능
  • CSS 빌드 최적화
  • Direct Import 구문에 대해 Preload 하도록 함으로써, 네트워크 비용 줄임

Parcel

Webpack과 달리 별도의 구성 파일 없이 간단하게 사용할 수 있는 번들러로,
최소한의 구성(Zero config)을 지향
Parcel 공식문서



📌 빌드 도구(Build Tool)

빌드 도구와 번들러

대표적인 빌드 도구 중 하나인 웹팩(Webpack)은 동시에 강력한 번들러로도 알려져 있다.
이렇게 빌드 도구와 번들러는 혼합하여 사용되어 혼란스러울 수 있다.

요약하자면, 빌드 도구는 웹 애플리케이션의 개발 및 빌드 과정에서 다양한 작업을 처리하는 도구들을 가리키는 상위 개념이고, 번들러는 빌드 도구의 일부로, 모듈 시스템을 관리하고 번들 형태로 애플리케이션을 묶어주는 일을 한다.

빌드 도구에 대해 자세히 알아보자.

역할

: 웹 애플리케이션을 개발하기 위해 필요한 소스 코드와 자원들을 처리하고 변환

  • 파일 복사
    : 웹 애플리케이션에 필요한 정적 파일(HTML, 이미지, 폰트 등)을 복사하여 적절한 위치에 배치
  • 전처리기 변환
    : CSS 전처리기(Sass, Less 등)나 CSS 프레임워크(Tailwind CSS, Bootstrap 등)를 사용한 스타일 시트를 브라우저가 이해할 수 있는 CSS로 변환
  • 트랜스파일링
    : 최신 자바스크립트 문법(ES6+)을 구형 브라우저에서도 동작할 수 있는 호환성 있는 코드로 변환. 주로 바벨(Babel)이 사용됨
  • 코드 압축
    : JavaScript, CSS, HTML 등의 코드를 압축하여 파일 크기를 최소화.
  • 환경 변수 설정
    : 개발 환경과 프로덕션 환경에서 다른 설정을 적용할 수 있도록 환경 변수를 관리.

구성요소

주요 구성요소에는 작업 실행기(태스크 러너), 번들러, 패키지 관리자, 개발 서버, 코드 린터 및 포맷터, 트랜스파일러 및 폴리핑이 있다.

프런트엔드 빌드 도구

작업 실행기(태스크 러너)

: 여러 작업을 동시에 또는 순차적으로 조정하고 실행하여 반복적인 작업을 자동화 한다. 인기 있는 작업 실행기에는 GulpGrunt가 있다. 이를 통해 개발자는 JavaScript로 사용자 정의 작업을 작성할 수 있으므로 더 나은 제어와 유연성이 가능하다. 작업에는 일반적으로 연결, 축소, 변환 및 린트가 포함된다.

grunt
minifying, 파일 통합, lint 적용 등 등록된 task를 순서대로 실행시켜 줌
설정이 파편화되고 개발자가 직접 컨트롤해야하는 영역이 많음

Gulp
grunt와 흡사한 task runner
다만 stream-based로 파일을 접근하기에 grunt에 비해 성능이 더 우수하다고 평가를 받고 있음

번들러

: 번들러는 종속성과 함께 애플리케이션 코드를 번들이라고 하는 단일 또는 여러 개의 최적화된 출력 파일로 패키징함. WebpackRollup과 같은 번들러는 종속성 그래프를 지능적으로 분석하여 최적화된 번들을 생성하여 HTTP 요청 수를 줄이고 성능을 향상시킴. 또한 코드 분할(지연 로딩), 트리 쉐이킹, 개발 중 애플리케이션 자동 다시 로드와 같은 기능도 제공

패키지 관리자

: npmYarn과 같은 패키지 관리자는 소프트웨어 패키지를 관리하고 배포하는 일을 담당. 패키지 종속성을 유지하고 버전 호환성을 보장하면서 패키지 설치, 업데이트 및 구성 프로세스를 단순화.

개발 서버

: 개발 중에 애플리케이션을 제공하기 위해 개발자의 컴퓨터에서 로컬로 실행되는 웹 서버. Browsersync, webpack-dev-serverLive Server자동 재로딩, 핫 모듈 교체(HMR), 심지어 여러 브라우저와 장치에 걸친 동기화 테스트와 같은 기능을 제공하여 전체 개발 프로세스를 더욱 효율적으로 만드는 인기 있는 개발 서버.

코드 린터 및 포맷터

: ESLintStylelint와 같은 코드 린터는 일관된 코딩 스타일을 적용하고 잠재적인 오류가 프로덕션 환경에 적용되기 전에 이를 포착하는 데 도움이 됨. Prettier와 같은 포맷터는 소스 코드의 형식을 자동으로 지정하여 일관성을 더욱 보장하고 가독성을 향상시킴.

트랜스파일러 및 폴리필

: Babel, swc과 같은 트랜스파일러는 최신 JavaScript 구문을 대부분의 브라우저에서 널리 지원되는 동등한 이전 구문으로 변환함. 이를 통해 개발자는 브라우저 호환성을 손상시키지 않고 최신 기능과 개선 사항을 사용하여 코드를 작성할 수 있음. Polyfill은 이전 브라우저에서 기본적으로 지원되지 않는 기능의 대체 구현을 제공하여 다양한 브라우저와 장치에서 일관된 사용자 경험을 보장.



📌 마무리

CRA와 Vite 차이에 대해 공부하면서 Webpack, Rollup에 대해 알아야 했고, 핫 모듈 교체(Hot Module Replacement, HMR)라는 용어를 접하게 되었다. 번들과 빌드 도구는 다른 개념으로 알고 있었는데 자꾸 혼용되는 부분에서 헷갈려서 처음부터 끝까지 파헤쳐 정리하게 되었다. 이참에 모듈에 대한 내용도 복습하면서 ESM을 이용한 번들링으로 빠른 성능을 지원하는 Vite를 사용해야 하는 이유를 짚어볼 수 있었다. 전반전인 생태계를 훑어봤으니 이제 Vite에 대해 톺아볼까?

0개의 댓글