3039 words
15 minutes
트리쉐이킹과 번들링 1
2025-07-08

트리쉐이킹은 최종 번들 크기를 줄이기 위해 사용되지 않는 코드를 제거하는 방법이다.
번들부터 알아보자.

번들링 알아보기#

개요#

🍊
번들이란 무엇이냐. 최적화할 때 나오는 말인데 번들이란 말만 보면 여러 개의 파일을 합쳐서 묶어놓은 것을 말한다. 그래서 번들링이란 말이 나오는데 묶어둔다는 것이다.

왜 묶어놓느냐? 왜 번들링이 필요한가? 묶어놓으면서 압축해두면서 전체 크기를 줄이고, 성능이 더 나오나?

🍊
주요 번들러에는 웹팩, vite, Rollup 등이 있다.

🍊
변들링의 과정
엔트리 포인트 = index.js를 설정하고 의존성 그래프를 생성한다
모듈을 변환한다. 타입스크립트는 자바스크립트로, SCSS는 CSS로.

코드 분할, 스플리팅을 한다.
최적화, 압축이나 트리쉐이킹을 한다.
이렇게 최종 번들 파일이 생성된다.

최적화 기법으로 코드 스플리팅이 있다.
모든 코드를 한번에 불러오면 초기 로딩 시간이 걸리니까, 코드를 부분부분 분할해서 동적으로 필요할 때 해당 부분을 가져오도록 한다. 이게 번들링과 연관이 있었군. lazy loading

모든 코드 → 하나의 큰 bundle.js (예: 2MB)

// 코드 스플리팅
├── main.bundle.js (500KB)     ← 초기 필수 코드
├── admin.bundle.js (300KB)    ← 관리자 페이지용
├── chart.bundle.js (400KB)    ← 차트 라이브러리
└── profile.bundle.js (200KB)  ← 프로필 페이지용

// 실제 코드, 코드 스플리팅
const AdminPage = React.lazy(() => import('./AdminPage'));

트리쉐이킹은 사용하지 않는 코드는 자동으로 제거해준다.

🍊
Bundle Analyzer를 사용하면 html 파일로도 해당 프로젝트의 번들 크기들을 보여준다.
이를 기반으로 최적화할 수 있다.


웹팩과 번들링#

[Web] 🗂프론트엔드에서 번들링이란? / 🛠Webpack

Ij8ODRb.png

웹개발에서의 번들링은 무슨 의미인가. 웹개발에서 번들링은 빌드라고 할 수 있다.
빌드를 하면 최종적으로 js, css, html 그 밖의 정적파일들이 나오게 된다.

이런 식으로 코드를 열심히 짜고 이것저것하고
마지막에는 번들링 과정을 통해 이것들을 요리조리 잘 모아 묶어서 정적 파일로 만들어야 한다.
이것이 번들링이다. 묶기.
브라우저는 이 번들링된 정적 파일로 우리가 보는 웹페이지를 보여준다.

왜 번들링을 하는가?#

번들링은 단순히 묶어주는게 아니라 일종의 압축 역할도 한다.
파일 크기가 더 작아지고, 속도도 빨라진다. 번들링은 선택이 아니라 필수다.

또 번들링해 둠으로써 사용자가 임의로 조작하는 것을 방지할 수도 있다고 한다.
이건 처음 알았네. 종종 강의 빨리 감기하려고 자바스크립트로 임의로 조작하는 경우가 있는데
번들링이 잘되면 이게 안되나? 더 알아보자.

  • 아래에서 다시 왔는데 그 변수이름 난독화하는 과정 의미하는 듯. 완전한 조작 방지는 어렵지 않을까?

웹팩 지표#

웹팩. 대표적인 번들링 도구다. 자바스크립트 생태계에서는 제일 많이 쓴다고 한다.
진짜인지 궁금해서 npm trends를 살펴봤다.

최근 1년 기준으로는 롤업이 상당히 올라온 것을 볼 수 있다. 쳐보니까 비트도 내부적으로 롤업 쓴다나 그렇다네…

웹팩 공식문서 보기#

웹팩 공식 문서
웹팩은 공식적으로 “자바스크립트 애플리케이션을 위한 정적 모듈 번들러”라고 하는데 번들러면 그냥 번들러지 갑자기 무슨 모듈 번들러인가.

모듈 번들러는 무엇이냐면, html, css, javascript 등의 자원을 각각의 모듈로 보고 이를 조합해 하나의 묶음올 번들링하는 도구라고 한다.
잘 모르겠다. 더 자세히 보자.

번들러와 모듈 번들러#

번들러는 단순히 하나로 묶는다는 말이고 모듈 번들러는 모듈 시스템을 이해하고 처리하는 번들러이다. 번들러의 하나라고 봐야겠다. 모듈 시스템을 이해한다는 것은 의존성 관계를 파악하고 해결도 가능하다.

음…더 알아보자.


버전5를 기준으로 보겠다.

웹팩이 애플리케이션을 처리할 때, 내부적으로는 프로젝트에 필요한 모든 모듈을 매핑하고 하나 이상의 번들을 생성하는 의존성 그래프를 만든다.

번들러는 의존성 그래프를 만든다고 한다. 일단 웹팩은 모듈 번들러이므로 모듈 시스템 import, export나 commonJS에 대해 이해하고 의존 관계를 파악하는 능력이 있나보다. 이를 기반으로 의존성 그래프를 만드는 듯.

저 의존성 그래프를 만들기 위해 엔트리 포인트, 웹팩에서는 webpack.config.js 에서 뭘 설정해서 원하는 대로 할…수있나? 일단 해당 파일에서 엔트리 포인트 설정은 가능함.

웹팩 버전 4 이후로는 프로젝틀르 번들링하기 위해 설정 파일을 필요로 하지 않는다. …사용자 요구에 따라 유연하게 설정이 가능합니다.

  • 설정 파일을 만들지 않고 디폴트 엔트리, 출력, 모드를 사용한다고 한다. 설정 파일 없어서 Zero Config라고 함.

웹팩 핵심개념 이해하기#

핵심개념만 알면 시작할 수 있다고 한다. 굿…알아..보자..
엔트리, 출력, 로더, 플러그인, 모드, 브라우저 호환성…이정도의 개념이 있다.

웹팩 : 엔트리#

엔트리는 뭐냐. 웹팩이 내부의 의존성 그래프를 생성하기 위해 사용해야 하는 모듈이다. 웹팩은 엔트리 포인트가 직간접적으로 의존하는 다른 모듈과 라이브러리를 찾아낸다.

오..대단해 똑똑한 친구다
기본값은 ./src/index.js이지만 웹팩 설정에서 수정할 수 있다.

// webpack.config.js
module.exports = {
  entry: './path/to/my/entry/file.js',
};

웹팩 : output#

output 속성은 생성된 번들을 내보낼 위치와 이 파일의 이름을 지정하는 방법을 웹팩에게 알려준다. 기본 출력 파일은 ./dist/main.js로 생성된 파일들을 ./dist 폴더로 설정된다.
이래서 빌드하면 저 경로로 파일들이 생겼군.

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js',
  },
};

아웃풋 지정한 예제
근데? 보니까 require, exports 쓰는 거 보니까 그..import export 쓰는 ES6 문법이 아니라 노드에서 쓰는 commonJS 문법을 쓰네. 왜 그러냐면 웹팩은 노드에서 실행되기 때문이다. 웹팩 자체가 노드 기반 도구다.

번들릥 이름을 지정해주고, 저장할 경로도 지정해주었다. 노드에서 쓰는 파일 경로 모듈 path를 가져와서 쓴다.

웹팩 : 로더#

로더는 뭔가
웹팩은 기본적으로 자바스크립트와 json 파일만 이해한다. 로더를 사용하면 웹팩이 다른 유형의 파일을 처리하거나, 유효한 모듈로 변환해서 의존성 그래프에 추가한다.

  • 운영체제인가 어디에서 로더가 약간 변환기 같은 역할했었던 것 같은데 여기서도 같은 의미로 사용되는 듯

로더는 웹팩 설정에 2가지 속성을 가진다. test와 use 속성 2가지이다.
변환이 필요한 파일을 식별하는 것이 test 속성
변환을 수행하는데 사용되는 로더를 가리키는 use 속성

const path = require('path');

module.exports = {
  output: {
    filename: 'my-first-webpack.bundle.js',
  },
  module: {
    rules: [{ test: /\.txt$/, use: 'raw-loader' }],
  },
};

rules 속성을 정의해서 test와 use 속성을 가진 하나의 규칙을 선언했다.
이것은 무슨 말이냐면

  • require나 import 문에서 txt 파일로 확인되는 경로를 발견하면 번들에 추가하기 전에 raw-loader를 사용해 변환 작업을 수행하라는 것이다.
rules : [ ...
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }
]

이런 식으로 체인을 처리할 수도 있다. 이 경우 오른쪽부터 실행된다. 즉 scss가 scss 로더로 css 변환되고, css 로더로 js 모듈로 변환되고, 스타일 로더가 이를 DOM에 스타일로 삽입한다.

웹팩은 기본적으로 js와 json만 이해하기 때문에 그 이외의 파일은 로더로 인식시켜주어야 한다.

웹팩 : 플러그인#

위에서 로더는 특정 유형의 모듈을 변환하는데 사용했다. 플로그인을 사용하면 번들을 최적화하거나 에셋 관리, 환경 변수 주입 등의 여러가지 일을 수행할 수 있다.

플러그인은 어떻게 사용?
require를 통해 플러그인을 요청하고 plugins 배열에 추가해야 한다. 플러그인은 new 연산자를 사용해야 한다. 왜냐면 플러그인은 기본적으로 클래스라서 인스터스를 만들어야 사용할 수 있다.

const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 내장 plugin에 접근하는 데 사용

module.exports = {
  module: {
    rules: [{ test: /\.txt$/, use: 'raw-loader' }],
  },
  plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};

기본 웹팩 동작에서 결과물은 자바스크립트만 나온다. 그러니까 dist/main.js 파일 한 개만 결과적으로 나온다. 이를 html로 만들어주기 위해 예시에서 플러그인을 설정해준 것이다.

플러그인이 빌드된=번들링된 js 파일을 템플릿 위치의 html에 추가 (<script src="main.js"/)해서 html을 완성한다.

웹팩 : 모드#

그 밖에도 모드, 브라우저 호환성이 있다.
모드는 development, production, none 등이 있어서 환경에 따라 설정을 다르게 해줄 수 있다.

var config = {
  entry: './app.js',
  //...
};

module.exports = (env, argv) => {
  if (argv.mode === 'development') {
    config.devtool = 'source-map';
  }

  if (argv.mode === 'production') {
    //...
  }

  return config;
};
// 실행
// webpack --mode=development 
// webpack --mode=production

실제로 이를 활용해 배포에서는 파일 크기를 최소화하거나, console.log같은 디버그 코드를 자동으로 제거하도록 할 수 있다. 또 변수명을 알아볼 수 없게 바꿔 코드를 보호할 수 있다. 서버 포트번호도 설정할 수 있다. 이를 통해 프록시 설정도 할 수 있다. 트리쉐이킹을 통해 쓰지 않는 코드를 제거하도록도 할 수 있다. 할 수 있는게 많군. API 주소도 설정해줄 수 있음

예시에서의 소스맵을 만들어두면 번들링 되기 전의 원본 코드로 추적할 수 있다. 이를 통해 정확히 어느 코드의 몇번째 줄에서 에러가 발생했는지 디버깅할 수 있다.


브라우저 호환성
웹팩 자체는 ES5 브라우저에서 동작하지만 코드 분할 기능과 같은 동적 import를 쓰려면 Promise가 필요하다. 이를 구형 브라우저에서 쓰려면 폴리필(없는 기능 자스로 만들어서 주기)을 로드해야 한다.


어쩌다보니 번들링만 했다..트리쉐이킹 추가 개념은 다시 정리하자 ㅠ
트리 쉐이킹으로 자바스크립트 페이로드 줄이기

트리쉐이킹과 번들링 1
softourr.github.io/트리쉐이킹과-번들링---1.md
Author
softourr
Published at
2025-07-08