카테고리 없음

웹팩(Webpack), 롤업(Rollup)과 같은 자바스크립트 번들러의 필요성

Chrysans 2025. 4. 22. 11:35
728x90
반응형

웹팩(Webpack), 롤업(Rollup)과 같은 자바스크립트 번들러의 필요성

webpack box

들어가며: 모던 웹 개발의 복잡성

오래전 웹 개발에서는 HTML 파일에 몇 개의 JS 파일만 추가하고 끝났던 시절이 있었다고 합니다. 하지만 오늘날의 웹 개발은 어떤가요? React, Vue, Angular와 같은 프레임워크, TypeScript, CSS 전처리기, 수백 개의 npm 패키지... 현대 웹 애플리케이션은 이전보다 훨씬 복잡해졌습니다.

이 복잡성을 다루기 위해 등장한 도구가 바로 자바스크립트 번들러입니다. 웹팩(Webpack), 롤업(Rollup),Vite, Parcel과 같은 도구들이 현대 웹 개발의 복잡성을 관리하는 핵심 역할을 합니다. 오늘은 이 번들러들이 왜 필요한지, 어떤 문제를 해결하는지 깊이 있게 살펴보겠습니다.


목차

  1. 번들러란 무엇인가?
  2. 번들러가 해결하는 핵심 문제
  3. 웹팩(Webpack)의 주요 기능
  4. 롤업(Rollup)의 주요 기능
  5. 번들러의 진화: ESBuild와 SWC
  6. 어떤 번들러를 선택해야 할까?
  7. 번들러 없이 개발할 수는 없을까?
  8. 자주 접하는 문제와 해결 방법
  9. 번들러 사용의 베스트 프랙티스

번들러란 무엇인가?

자바스크립트 번들러는 간단히 말해 여러 개의 파일을 하나(또는 여러 개의 최적화된 파일)로 묶어주는 도구입니다. 하지만 이 단순한 설명 뒤에는 현대 웹 개발에서 직면하는 수많은 복잡한 문제를 해결하는 강력한 기능들이 숨어 있습니다.

📁 project
  ├── 📁 node_modules/
  │   ├── 📁 react/
  │   ├── 📁 lodash/
  │   └── 📁 기타 100+ 패키지/
  ├── 📁 src/
  │   ├── app.js
  │   ├── components/
  │   ├── utils/
  │   └── styles/
  └── index.html

위와 같은 구조의 프로젝트가 있을 때, 번들러는 이 모든 파일을 분석하고 최종적으로는 브라우저가 이해할 수 있는 형태(ES5 , 폴리필 등)로 변환하여 배포합니다.


번들러가 해결하는 핵심 문제

1. 모듈 시스템의 다양성 문제

자바스크립트는 오랫동안 공식적인 모듈 시스템이 없었습니다. 이로 인해 다양한 모듈 형식이 등장했죠:

  • CommonJS (Node.js 환경): require()module.exports
  • AMD (RequireJS): 비동기 모듈 정의
  • UMD: CommonJS와 AMD를 모두 지원하는 방식
  • ES Modules: 현대 자바스크립트의 공식 모듈 시스템 (import/export)

아래는 각 모듈 시스템의 간단한 예시입니다:

// CommonJS (Node.js)
const lodash = require('lodash');
module.exports = function doSomething() {...};

// ES Modules
import lodash from 'lodash';
export function doSomething() {...};

브라우저는 기본적으로 이러한 모듈 문법을 모두 이해하지 못합니다(최신 브라우저는 ES Modules를 지원하지만, 구형 브라우저는 지원하지 않음). 번들러는 이러한 다양한 모듈 형식을 브라우저가 이해할 수 있는 형태로 변환합니다.

2. HTTP 요청 최소화

웹 성능에 영향을 미치는 주요 요소 중 하나는 HTTP 요청의 수입니다. 수많은 작은 JS 파일을 로드하는 것보다, 하나의 큰 파일(또는 최적화된 여러 개의 파일)을 로드하는 것이 일반적으로 더 효율적입니다.

<!-- 번들러 사용 전 -->
<script src="app.js"></script>
<script src="utils.js"></script>
<script src="components/button.js"></script>
<script src="components/form.js"></script>
<script src="node_modules/lodash/index.js"></script>
<!-- 등등 수십 개의 스크립트 -->

<!-- 번들러 사용 후 -->
<script src="bundle.js"></script>
<!-- 또는 최적화된 여러 개의 번들 -->
<script src="vendor.js"></script>
<script src="app.js"></script>

3. 최신 자바스크립트 문법 지원

ES6+ 문법은 개발자 경험을 크게 향상시키지만, 모든 브라우저가 이러한 최신 문법을 지원하는 것은 아닙니다. 번들러는 Babel과 같은 도구와 연동하여 최신 자바스크립트 코드를 구형 브라우저에서도 작동하는 코드로 변환(트랜스파일)합니다.

// 자바스크립트 코드 (ES2023)
export function sortProducts(products) {
  // 원본 배열을 변경하지 않고 정렬된 새 배열 반환
  const sortedByPrice = products.toSorted((a, b) => a.price - b.price);
  return sortedByPrice;
}

// 사용 예시
const products = [
  { id: 1, name: "Phone", price: 699 },
  { id: 2, name: "Laptop", price: 999 },
  { id: 3, name: "Earbuds", price: 129 },
  { id: 4, name: "Monitor", price: 249 }
];

console.log(sortProducts(products));

// 바벨이 ES2023의 toSorted() 메서드를 트랜스파일하면, 폴리필 형태의 코드는 대략 다음과 같을 것입니다
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.sortProducts = sortProducts;

require("core-js/modules/es.array.to-sorted.js");

function sortProducts(products) {
  // 바벨은 toSorted를 직접 사용하지 않고 폴리필로 완전히 대체함
  var sortedByPrice = products.slice().sort(function (a, b) {
    return a.price - b.price;
  });

  return sortedByPrice;
}

4. 코드 최적화 및 분석

번들러는 단순히 파일을 연결하는 것 이상의 작업을 수행합니다. 트리 쉐이킹(사용하지 않는 코드 제거), 코드 분할(code splitting), 미니피케이션(공백 및 주석 제거), 번들 크기 분석 등 다양한 최적화 작업을 수행합니다.

// 원본 코드
import { sum, multiply, divide } from './math.js';

// 아래 함수 중 sum만 사용됨
console.log(sum(1, 2));

// 트리 쉐이킹 후 번들에 포함되는 코드
// multiply와 divide 함수는 번들에서 제외됨

웹팩의 주요 기능

웹팩(Webpack)은 가장 인기 있는 번들러 중 하나로, 풍부한 기능과 생태계를 갖추고 있습니다.

1. 로더(Loader) 시스템

웹팩의 가장 강력한 기능 중 하나는 다양한 파일 형식을 처리할 수 있는 로더 시스템입니다.

// webpack.config.js 간단 예시
module.exports = {
  entry: './src/index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader' // JS 파일은 Babel로 처리
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'] // CSS 파일 처리
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: 'file-loader' // 이미지 파일 처리
      }
    ]
  }
};

이 설정을 통해 자바스크립트 파일뿐만 아니라 CSS, 이미지 등 모든 종류의 애셋을 모듈로 다룰 수 있습니다.

2. 플러그인(Plugin) 시스템

웹팩의 플러그인 시스템은 번들링 과정의 거의 모든 측면을 커스터마이징할 수 있게 해줍니다.

// webpack.config.js에 플러그인 추가
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  // 기본 설정...
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html' // HTML 파일 자동 생성
    }),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css' // CSS 파일 분리 추출
    })
  ]
};

3. 코드 분할(Code Splitting)

웹팩은 애플리케이션을 여러 청크(chunk)로 분할하여 필요할 때만 로드할 수 있게 해줍니다.

// 동적 임포트를 통한 코드 분할
import React from 'react';

const App = () => {
  const [ShowComponent, setShowComponent] = React.useState(null);

  const loadComponent = async () => {
    // 이 부분은 별도의 청크로 분할됩니다
    const { default: LazyComponent } = await import('./LazyComponent');
    setShowComponent(() => LazyComponent);
  };

  return (
    <div>
      <button onClick={loadComponent}>컴포넌트 로드</button>
      {ShowComponent && <ShowComponent />}
    </div>
  );
};

롤업의 주요 기능

롤업(Rollup)은 특히 라이브러리 개발자들 사이에서 인기 있는 번들러입니다.

1. 트리 쉐이킹(Tree Shaking) 최적화

롤업은 ES 모듈의 정적 구조를 활용하여 효율적인 트리 쉐이킹을 수행합니다. 이는 라이브러리 크기를 최소화하는 데 특히 유용합니다.

// rollup.config.js 간단 예시
export default {
  input: 'src/main.js',
  output: {
    file: 'bundle.js',
    format: 'esm' // ES 모듈 형식으로 출력
  }
};

2. 다양한 출력 형식 지원

롤업은 다양한 모듈 형식으로 출력을 생성할 수 있어 라이브러리 개발에 유리합니다.

// rollup.config.js에서 여러 형식 출력
export default {
  input: 'src/main.js',
  output: [
    {
      file: 'dist/bundle.cjs.js',
      format: 'cjs' // CommonJS
    },
    {
      file: 'dist/bundle.esm.js',
      format: 'esm' // ES Modules
    },
    {
      name: 'myLibrary',
      file: 'dist/bundle.umd.js',
      format: 'umd' // UMD (브라우저와 Node.js 모두에서 사용 가능)
    }
  ]
};

번들러의 진화: ESBuild와 SWC

최근에는 성능에 중점을 둔 새로운 번들러들이 등장하고 있습니다.

ESBuild

Go 언어로 작성된 ESBuild는 웹팩보다 10-100배 빠른 속도를 자랑합니다.

// esbuild 간단 사용 예시
const esbuild = require('esbuild');

esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  minify: true,
  outfile: 'dist/bundle.js',
}).catch(() => process.exit(1));

SWC (Speedy Web Compiler)

Rust로 작성된 SWC는 Babel의 대안으로, 훨씬 빠른 속도로 코드를 트랜스파일합니다.

// Next.js 12에서 SWC 사용 예시 (next.config.js)
module.exports = {
  swcMinify: true, // SWC를 사용하여 JavaScript 코드 압축
};

어떤 번들러를 선택해야 할까?

번들러 선택은 프로젝트의 특성과 요구사항에 따라 달라집니다.

웹팩을 선택해야 하는 경우

  • 복잡한 애플리케이션을 개발할 때
  • 다양한 자산 유형(CSS, 이미지 등)을 처리해야 할 때
  • 풍부한 생태계와 커뮤니티 지원이 필요할 때

롤업을 선택해야 하는 경우

  • 라이브러리 개발 시
  • 트리 쉐이킹이 중요할 때
  • 다양한 모듈 형식으로 출력해야 할 때

ESBuild/SWC를 선택해야 하는 경우

  • 빌드 속도가 가장 중요한 요소일 때
  • 큰 프로젝트에서 개발 경험을 향상시키고 싶을 때

번들러 없이 개발할 수는 없을까?

ES 모듈은 현대 브라우저에서 기본적으로 지원되므로, 이론적으로는 번들러 없이 개발이 가능합니다.

<!-- 번들러 없이 ES 모듈 사용 -->
<script type="module">
  import { Component } from './components.js';
  import { helper } from './utils.js';

  // 코드 작성...
</script>

하지만 이 방식에는 여러 한계가 있습니다:

  1. HTTP 요청 수가 증가하여 성능이 저하될 수 있음
  2. 구형 브라우저 지원 문제
  3. 트리 쉐이킹과 같은 최적화 부재
  4. npm 패키지 직접 사용의 어려움

따라서 현대 웹 애플리케이션에서는 여전히 번들러가 필요한 경우가 대부분입니다.


자주 접하는 문제와 해결 방법

문제 1: 번들 크기가 너무 큰 경우

원인: 너무 많은 의존성, 큰 라이브러리, 최적화 부족

해결 방법:

  • 코드 분할(Code Splitting) 적용
  • 트리 쉐이킹 활성화
  • 불필요한 의존성 제거
  • 번들 분석 도구 사용 (예: webpack-bundle-analyzer)
// webpack-bundle-analyzer 사용 예시
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  // 기존 설정...
  plugins: [
    new BundleAnalyzerPlugin()
  ]
};

문제 2: 빌드 속도가 느린 경우

원인: 많은 모듈, 복잡한 로더 체인, 무거운 플러그인

해결 방법:

  • 캐싱 활성화
  • 병렬 처리 설정
  • 필요한 로더와 플러그인만 사용
  • ESBuild나 SWC와 같은 빠른 번들러로 전환 고려
// 웹팩 캐싱 및 병렬 처리 설정
module.exports = {
  // 기존 설정...
  cache: true,
  parallelism: 4,
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        options: {
          cacheDirectory: true // Babel 캐싱 활성화
        }
      }
    ]
  }
};

번들러 사용의 베스트 프랙티스

권장 사항

  1. 환경별 최적화: 개발 환경과 프로덕션 환경을 분리하여 설정
  2. 코드 분할 적극 활용: 초기 로드 시간 개선을 위해 필요한 코드만 로드
  3. 캐싱 전략 수립: 효율적인 캐싱을 위한 콘텐츠 해시 활용
  4. 정기적인 의존성 업데이트: 보안 및 성능 개선을 위해 정기적으로 패키지 업데이트
// 환경별 웹팩 설정 예시
const commonConfig = {
  // 공통 설정
};

const devConfig = {
  mode: 'development',
  devtool: 'inline-source-map',
  // 개발 환경 특화 설정
};

const prodConfig = {
  mode: 'production',
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  // 프로덕션 환경 특화 설정
};

module.exports = (env) => {
  return env.production ? { ...commonConfig, ...prodConfig } : { ...commonConfig, ...devConfig };
};

용어 설명

  • 번들링(Bundling): 여러 개의 파일을 하나 또는 여러 개의 최적화된 파일로 묶는 과정
  • 트리 쉐이킹(Tree Shaking): 사용하지 않는 코드를 제거하는 최적화 기법
  • 코드 분할(Code Splitting): 코드를 여러 개의 청크로 나누어 필요할 때만 로드하는 기법
  • 로더(Loader): 다양한 유형의 파일을 모듈로 변환하는 웹팩의 기능
  • 플러그인(Plugin): 번들링 과정의 다양한 측면을 확장하는 기능
  • 청크(Chunk): 번들러가 생성하는 코드의 단위
  • 진입점(Entry Point): 번들러가 의존성 트리를 구축하기 시작하는 파일
  • ESM(ECMAScript Modules): 자바스크립트 공식 모듈 시스템
  • CJS(CommonJS): Node.js 환경에서 주로 사용되는 모듈 시스템
  • 트랜스파일링(Transpiling): 한 형태의 소스 코드를 다른 형태로 변환하는 과정

 

https://webpack.kr/concepts/

 

Concepts | 웹팩

웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.

webpack.kr

 

https://2022.stateofjs.com/en-US/libraries/build-tools/

 

State of JavaScript 2022: Build Tools

This chart splits positive (“want to learn”, “would use again”) vs negative (“not interested”, “would not use again”) experiences on both sides of a central axis. Bar thickness represents the number of respondents aware of a technology.

2022.stateofjs.com

 

728x90
반응형