모듈/번들러/트랜스파일러

dr7204·2025년 4월 22일

모듈

개발하는 애플리케이션의 크기가 커지고 프로그램의 내부를 기능별로 분할한 부분을 “모듈”이라 부른다

모듈화의 장점

  • 유지보수
    • 기능들이 모듈화가 잘 되어있다면 의존성을 줄일 수 있어 유지보수가 편리하다.
  • 네임스페이스화
    • 모듈화를 하면 모듈만의 네임스페이스를 가지기 떄문에 중복 변수명으로부터 자유로워진다.
  • 재사용성
    • 재사용 가능한 로직을 모듈로 분리시켜 필요할 때마다 사용할 수 있다.

모듈 시스템

JavaScript 프로그램을 모듈로 개발하고 배포할 수 있게 하기 위해 만들어짐

CJS (CommonJS)

모듈 시스템이 없던 초기의 자바스크립트는 브라우저에서는 큰 문제가 없었지만 서버 사이드에서 사용하기에는 여러 기능들을 모듈화 없이 유지보수하는 것은 거의 불가능에 가까웠다. 파일을 나누는 것은 가능하지만 스코프가 전역(Global)이라서 충돌 위험이 너무 컸다.

하지만 클라이언트와 서버 측에서 같은 언어를 쓸 때의 많은 이점으로 인해 수요는 늘어갔고, 이로 인해 탄생한 것이 ServerJS(CommonJS) 이다.

// 내보내기
module.exports = function add(a, b) { return a + b }

// 가져오기
const add = require("./add");
  • 구) ServerJS
  • Node.js에서 기본적으로 사용하는 모듈 시스템이다.
  • 서버 사이드에서 사용하며, 동기적으로 작동한다. (위에서 아래로 순차적으로 실행)
    • 서버 애플리케이션은 파일 시스템에 직접적으로 접근할 수 있고, 필요한 모듈이나 데이터를 로컬에서 빠르게 로드할 수 있다.
    • 이러한 방식은 네트워크 지연 시간이 거의 없기 때문에 동기적으로 작동해도 문제가 없다.

브라우저의 경우, 네트워크를 통해 모듈이나 라이브러리를 로드하기 떄문에 동기적 로딩은 웹페이지의 로딩 시간을 크게 증가시킬 수 있다.
규모가 클수록 더 많은 영향을 받았고, 브라우저 환경을 고려한 비동기로 동작하는 모듈 시스템 AMD가 탄생하게 되었다.

AMD (Asynchronous Module Definition)

AMD 그룹은 브라우저 환경을 위한 브라우저 모듈의 표준을 만들고자 했으며, 자바스크립트 모듈과 의존성을 비동기적으로 로드하는 방법을 정의하는 개방형 표준을 공개했다. 이 표준을 기반으로 모듈 시스템을 위한 다양한 라이브러리가 탄생했다.

amdjs-api/AMD.md at master · amdjs/amdjs-api

  • RequireJS
  • 클라이언트에서 주로 사용하며(서버 사이드에서 사용 가능), 비동기적으로 작동한다.
  • define을 통해 모듈을 정의하고, require을 통해 모듈을 비동기적으로 불러와 사용한다.

UMD (Universal Module Definition)

자바스크립트 생태계가 점점 넓어지며, CommonJS와 AMD 모듈 시스템을 모두 지원해야 하는 상황이 생기게 되었고 두 모듈 방식을 좀 더 효율적으로 구성하기 위해 모듈 관리 패턴 UMD가 탄생하게 되었다.

(function (root, factory) {
  if (typeof module === 'object' && module.exports) {
    // CommonJS
    module.exports = factory();
  } else if (typeof define === 'function' && define.amd) {
    // AMD
    define([], factory);
  } else {
    // 브라우저 글로벌
    root.myLibrary = factory();
  }
}(this, function () {
  return {
    hello: function() { console.log("Hello!"); }
  };
}));
  • 모듈 선언을 위해 즉시실행함수(IIFE)를 사용한다.
  • 보통 라이브러리를 배포할 떄 많이 사용한다.
  • 다양한 환경에서 실행할 수 있는 유연한 구조이다.
    • CommonJS 모듈을 사용할 수 있는지 확인
    • 그렇지않다면 AMD에서 사용하는 define 함수를 사용할 수 있는지 확인
    • 둘 다 아니라면 브라우저라 판단

ESM (ES Module)

모듈화를 위한 다양한 움직임 끝에 ECMAScripts2015 표준 명세에 ECMA Modules가 등장하며, 자바스크립트 자체 모듈 시스템을 사용할 수 있게 되었다.

// 내보내기
export function add (a, b) { return a + b }

// 가져오기
import { add } from "/add.js"
  • 현재는 브라우저와 Node.js 모두에서 기본적으로 지원한다.
  • 비동기 로딩과 명확한 의존성 파악이 가능하다.
  • 트리 쉐이킹(tree-shaking)을 통해 사용하지 않는 코드를 제거할 수 있다.
  • 브라우저에서는 <script type=”module”>을 통해 직접 사용할 수 있다.
  • Node.js에서는 package.json 에 “type”: “module”을 추가하면 된다.

브라우저는 기본적으로 ESM만 인식한다.
따라서 다른 모듈 시스템을 제공하는 라이브러리를 사용하기 위해서는 ESM 형식으로 변환(트랜스파일) 해주는 과정이 필요하다.
이러한 작업은 보통 Webpack, Rollup 같은 번들러 도구들이 처리해준다.

번들러(Bundler)

웹 애플리케이션 개발에 필요한 HTML, CSS, JS 등의 모듈화된 자원들을 모아서, 하나 혹은 최적의 소수 파일로 결합(번들링)하는 도구이다.

결합 전 수행 작업

개발자의 작업 효율성을 높이고, 브라우저 호환성이나 성능을 개선하는데 크게 도움을 준다.

  • 불필요한 주석이나 공백 제거
  • 난독화
  • 파일 압축
  • 최신 문법이나 기타 개발에 필요한 특수 기능 등을 브라우저가 지원하는 형태로 변환(트랜스파일링)

요즘의 번들러는 단순히 파일을 묶는 기능 뿐만 아니라, 트랜스파일링 작업도 포함한 종합적인 빌드 도구로 발전했다. 이에 해당하는 예시로는 Webpack, Rollup 등이 있다.

Webpack

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

  • 모듈 번들링 (Module Bundling)
    • 진입점에 연결된 파일을 단일 파일로 묶어줌
  • 번들 최적화 (Automatic Bundle Optimization)
    • 번들 최적화를 통해. 보다 더 작은 번들을 생성하고 그만큼 빠르게 로딩할 수 있다.
  • 코드 스플리팅 (Code Splitting)
    • 모듈을 청크(chunk)로 분리하여, 동적으로 필요한 모듈만 로딩할 수 있다.
  • 트리 쉐이킹 (Tree Shaking)
    • 사용하지 않는 코드를 제거해서 번들의 크기를 줄이고 성능을 향상시킨다.
  • 개발 서버 시행 (Development Server)
    • 코드가 변경될 때마다 브라우저에 반영(HMR)되는 개발용 서버를 실행할 수 있다.

Rollup

경량화와 번들 최적화를 중점에 둔 ES Module 번들러이다.

  • ESM 중심
    • ES 모듈을 기본으로 지원한다.
    • 최신 JS 문법에 최적화되어 있어서 Tree Shaking 효과가 좋다
  • Tree Shaking 최적화
    • Webpack보다 더 깔끔하게 제거하는 경우가 많다.
  • 라이브러리 번들링에 최적화
    • 앱보다는 라이브러리(npm 패키지 등)을 번들링할 때 더 많이 사용된다.
    • 작은, 최적화된 번들을 만드는 데 강점이 있다

ESBuild

노드기반 번들러보다 10~100배 빠른 빌드를 제공하는 번들러이다.

  • Go 언어 기반
    • Go로 구현되어 병렬 처리가 최적화되어 있어서 수백 개 파일도 몇 초안에 번들링이 가능하다.

트랜스파일러(Tranpsiler)

소스 코드를 한 프로그래밍 언어에서 다른 프로그래밍 언어로 변환해주는 도구이다. 주로 최신 버전의 언어를 구형 버전의 언어로 변경하거나, 다른 언어로 변경하는데 사용된다.

자바스크립트를 대상으로 하는 트랜스파일러는 Babel, TSC, ESBuild 등이 있다.

  • ES6 → ES5 (Babel)
  • typescript → javascript (TypeScript Compiler)
  • sass / scss → css

Babel

대표적인 자바스크립트 트랜스파일러로, 최신 버전의 자바스크립트 코드를 오래된 버전의 자바스크립트 코드로 변환해주는 역할을 한다.

  • 구) 6to5
  • ES5 문법으로의 변환을 통해, 모든 브라우저에서 일관적 동작을 보장해준다. (크로스 브라우징)
  • 플러그인과 프리셋 시스템을 제공하여 개발자가 원하는 변환 규칙을 추가하고 설정할 수 있다.
  • 소스 변환 과정이 추가되기 때문에 빌드 시간을 증가시킬 수 있다.
  • 파싱(parsing) → 변환(transformation) → 출력(print)의 세 단계를 걸쳐서 코드를 변환한다.
    • 파싱 : 코드를 읽어서 AST(추상 구문 트리)로 변환
    • 변환 : AST를 정해진 규칙에 따라 다시 변환(ES6 → ES5)
    • 출력 : 변환된 AST를 다시 소스 코드로 출력

SWC

Speedy Web Compiler의 약자로, JS와 TS를 빠르게 트랜스파일링하는 도구이다.

  • 초고속 트랜스파일링
    • Rust로 작성되어서, JavaScript/TypeScript 트랜스파일링 속도가 매우 빠르다.
  • TypeScript 지원
    • 별도로 추가 설정 없이 TypeScript 파일을 바로 컴파일할 수 있다.
  • React + TS 환경에서 유용
    • React 프로젝트에 맞는 설정과 트랜스파일링이 간단하다.
  • Babel보다 생태계가 작다.

지금은 대부분의 빌드 도구가 두 역할을 동시에 처리하기 때문에 옛날에 비해 트랜스파일러와 모듈러의 경계가 흐려졌다. 이제는 도구의 “정체성”보다는 “무엇을 해결해주는가(문법 변환? 모듈 결합? 최적화?)”를 중심으로 이해하는게 더 실용적이다.

0개의 댓글