개발새발

다양한 모듈 형식으로 js 파일 생성하기 본문

Typescript

다양한 모듈 형식으로 js 파일 생성하기

비숑주인 2025. 5. 17. 17:07

TypeScript를 사용하면 .ts 파일로 작성한 코드를 다양한 모듈 형식의 JavaScript 파일로 컴파일할 수 있다. 기본적으로 tsconfig.json을 설정하지 않으면 CommonJS 형식으로 변환되며, 이 설정을 수정하면 ECMAScript, UMD 등의 다른 형식으로도 출력할 수 있다.

본 글에서는 동일한 test.ts 파일을 CommonJS, ECMAScript, UMD 형식으로 각각 변환하면서 어떤 차이가 발생하는지 자세히 살펴보려고 한다. 

 

기본 설정: CommonJS

1. test.ts 코드 예시

import axios from "axios";

(async () => {
  try {
    const res = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
    console.log(res.data.userid);

    const res2 = await axios.post('https://jsonplaceholder.typicode.com/posts', {
      title: 'foo',
      body: 'bar',
      userid: 1,
    });
    console.log(res2.data.id);
  } catch (error) {
    if (axios.isAxiosError(error)) {
      console.log(error.response?.data.message);
    }
  }
})();

 

2. tsconfig.json 설정 (기본)

{
  "compilerOptions": {
    "target": "ES2016",
    "module": "CommonJS",
    "outDir": "./dist",
    "esModuleInterop": true
  }
}

 

3. 변환 결과 (CommonJS)

"use strict";
var __awaiter = ... // async/await를 지원하지 않는 target을 위한 대체 함수
var __importDefault = ... // esModuleInterop을 위한 함수

Object.defineProperty(exports, "__esModule", { value: true });
const axios_1 = __importDefault(require("axios"));

(() => __awaiter(void 0, void 0, void 0, function* () {
  ...
}))();

 

  • __awaiter: target이 ES2016이라 async/await가 직접 지원되지 않아 제너레이터 함수로 변환된다.
  • __importDefault: esModuleInterop 옵션이 true일 경우 CommonJS 모듈에서 default를 안전하게 가져오기 위한 보조 함수이다.
  • Object.defineProperty(..., "__esModule", ...): 해당 모듈이 ES 모듈 스타일로 작성되었음을 표시한다.

target을 높인 경우 (ES2022)

1. 변경된 tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "CommonJS",
    "esModuleInterop": true
  }
}

 

2. 변환 결과

"use strict";
var __importDefault = ...

Object.defineProperty(exports, "__esModule", { value: true });
const axios_1 = __importDefault(require("axios"));

(async () => {
  try {
    const res = await axios_1.default.get(...);
    ...
  } catch (error) {
    ...
  }
})();

 

  • __awaiter가 사라진다. 최신 자바스크립트 엔진에서는 async/await를 natively 지원하므로 별도 함수가 필요 없다.

ECMAScript 모듈로 변환 (ESM)

1. tsconfig.json 설정

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2015",
    "moduleResolution": "node"
  }
}

 

2. 변환 결과

import axios from "axios";

(async () => {
  try {
    const res = await axios.get(...);
    ...
  } catch (error) {
    ...
  }
})();

 

  • CommonJS의 흔적이 사라지고 실제로 .ts와 거의 동일한 코드가 출력된다.
  • 명시적인 exports, require, __importDefault, __esModule 등의 코드가 없다.
  • Node.js에서는 .mjs 확장자를 사용하거나 type: "module" 설정이 필요하다.

UMD (Universal Module Definition)

1. tsconfig.json 설정

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "UMD",
    "esModuleInterop": true
  }
}

 

2. 변환 결과

(function (factory) {
  if (typeof module === "object" && typeof module.exports === "object") {
    var v = factory(require, exports);
    if (v !== undefined) module.exports = v;
  } else if (typeof define === "function" && define.amd) {
    define(["require", "exports", "axios"], factory);
  }
})(function (require, exports) {
  "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  const axios_1 = __importDefault(require("axios"));
  (async () => {
    ...
  })();
});

 

 

  • CommonJS (Node.js)와 AMD (RequireJS 등) 환경 모두 호환되도록 만들어진 통합 모듈 형식이다.
  • 브라우저, Node.js, CDN 환경에서도 유연하게 사용 가능하도록 설계된 구조이다.
  • 최근에는 사용 빈도가 낮으며, 대부분은 ESM 또는 CommonJS를 사용한다.

 

결론

모듈 형식 특징
CommonJS Node.js에서 기본 사용, require, module.exports 사용
ES2015 최신 표준 모듈 시스템, import / export 사용
UMD CommonJS + AMD 통합, 광범위 호환성
AMD, SystemJS 과거 사용되던 브라우저 기반 모듈 시스템 (현재는 비권장)
 

타입스크립트는 다양한 런타임 환경에서의 호환성을 고려하여 모듈 형식을 유연하게 선택할 수 있도록 지원한다. 어떤 환경에서 어떤 모듈 시스템을 사용할지는 프로젝트의 목적과 배포 환경에 따라 달라진다.

 

부록: 추천 설정 조합

목적 추천 설정
Node.js 백엔드 개발 module: "CommonJS" + target: "ES2022"
브라우저 기반 프론트엔드 module: "ES2015" + target: "ES2022"
라이브러리 배포 (넓은 호환성) module: "UMD"