본문 바로가기

Frontend/Typescript

Rollup 번들러로 enum과 const enum 트랜스파일링해보기

바로 이전에 enum은 어떻게 써야 하는지에 대한 글을 쓴 적이 있었다.

https://gugu76.tistory.com/130

 

enum과 const enum을 비교하는 내용이 있었는데, 해당 글을 작성하다 보니 직접 트랜스파일링해서 결과를 보고 싶다는 생각이 들었다.

그래서 Rollup 번들러를 사용해서 간단하게나마 enum을 트랜스파일링해보고 결과를 확인해 보았다.

 

Rollup

Rollup도 Webpack 같은 자바스크립트 번들러 중 한 종류이다.

Rollup은 빌드 결과물을 ES6 모듈 형태로 만들 수 있다.

이는, 사용자가 라이브러리의 코드 일부만 사용하게 되면 해당 부분만 번들 결과물에 포함시킬 수 있게 되는 것이다.

그래서, 사용하지 않는 코드를 빌드 단에서 제거하는 트리 쉐이킹 기법을 활용해 빌드 크기를 효율적으로 줄일 수 있다고 한다.

 

프로젝트 세팅

프로젝트 세팅은 다음과 같이 진행했다.

 

1. 프로젝트 초기화

yarn init -y



2. typescript 설치

yarn add --dev typescript



3. tsconfig.json 생성 및 변경

npx tsc --init
// tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "jsx": "react",
    "preserveConstEnums": false
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts"],
  "exclude": ["node_modules"]
}



4. Rollup, 관련 플러그인 설치

yarn add --dev rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs rollup-plugin-terser rollup-plugin-typescript2



5. rollup 설정 파일 생성 및 변경

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "rollup-plugin-typescript2";
import { terser } from "rollup-plugin-terser";

export default {
  input: "src/index.ts",  // 번들링의 시작점이 되는 파일
  output: {
    file: "dist/bundle.js",  // 번들된 결과물의 출력 파일
    format: "es",  // 출력 형식 (여기서는 ECMAScript 모듈 형식)
    sourcemap: true,  // 소스맵 생성 여부
  },
  plugins: [
    resolve(),       // 외부 모듈 해결
    commonjs(),      // CommonJS 모듈을 ES6 형태로 변환
    typescript(),    // TypeScript 파일을 트랜스파일
    terser(),        // JavaScript 코드 압축
  ],
};



6. 빌드 script 추가 및 type module로 설정

// package.json
{
  "scripts": {
    "build": "rollup -c"
  },
  "type": "module",
}

 

문자형 enum 트랜스파일 결과

import { DeliveryStatus1 } from "./enum";

console.log(DeliveryStatus1.DELIVERED);
var E;
!(function (E) {
  (E.READY = "READY"),
    (E.DELIVERING = "DELIVERING"),
    (E.DELIVERED = "DELIVERED");
})(E || (E = {})),
  console.log(E.DELIVERED);

 

예상했던 대로, enum을 트랜스파일해보니 즉시 실행 함수(IIFE) 형태로 나온 것을 알 수 있다.

이렇듯, Rollup과 같은 번들러에서는 이런 즉시 실행 함수 형태가 포함되면, 빌드 시 트리 쉐이킹이 안 되기 때문에 번들 크기가 조금 더 커질 수 있다고 한다.

 

추가로, enum런타임에 객체로 존재하고, 각 멤버는 변수에 할당되어 초기화된다.

코드에서 console.log(E.DELIVERED); 부분에서 enum의 멤버를 참조하고 있는 걸 볼 수 있다.

 

const enum 트랜스파일 결과

import { DeliveryStatus2 } from "./enum";

console.log(DeliveryStatus2.DELIVERED);
console.log("DELIVERED");

 

 

const enum런타임에 객체로 존재하지 않고 컴파일 타임에 인라인화되어 상수화된다.

코드에서 console.log("DELIVERED"); 부분에서는 상수 "DELIVERED"가 직접 사용되어 있는 것을 볼 수 있다.

 

숫자형 enum 트랜스파일 결과

import { DeliveryStatus3 } from "./enum";

console.log(DeliveryStatus3.DELIVERED);
console.log(DeliveryStatus3[2]);
var E;
!(function (E) {
  (E[(E.READY = 0)] = "READY"),
    (E[(E.DELIVERING = 1)] = "DELIVERING"),
    (E[(E.DELIVERED = 2)] = "DELIVERED");
})(E || (E = {})),
  console.log(E.DELIVERED),
  console.log(E[2]);

 

숫자형 enum도 문자형 enum과 마찬가지로 객체로 변환되는 것을 알 수 있다.

 

하지만 다른 점은 리버스 매핑 관련한 부분이다.

export enum DeliveryStatus3 {
  READY,
  DELIVERING,
  DELIVERED,
}
const DeliveryStatus1 = {
  READY: 0,
  DELIVERING: 1,
  DELIVERED: 2,
  "0": "READY",
  "1": "DELIVERING",
  "2": "DELIVERED",
};

 

이전 글에서도 언급했다시피, 숫자형 enum리버스 매핑이 가능한데, 해당 원리를 트랜스파일된 결과에서도 확인할 수 있었다.

!(function (E) {
  (E[(E.READY = 0)] = "READY"),
    (E[(E.DELIVERING = 1)] = "DELIVERING"),
    (E[(E.DELIVERED = 2)] = "DELIVERED");
})(E || (E = {})),

 

 

참고 자료

https://wormwlrm.github.io/2021/11/07/Rollup-React-TypeScript.html

https://velog.io/@wynter_j/Bundler-JavaScript-%EB%B2%88%EB%93%A4%EB%9F%AC-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Webpack-Parcel-Rollup-Vite...-2