트랜스파일레이션은 소스 코드를 한 프로그래밍 언어에서 다른 언어로 동일한 추상화 수준에서 변환하는 것입니다. 기계어로 컴파일하는 것과 달리, 트랜스파일레이션은 고수준 언어 간에 코드를 변환합니다: TypeScript에서 JavaScript로, Kotlin에서 Java로, Dart에서 JavaScript로. Babel Documentation에 따르면, Babel은 주간 3,500만 이상의 다운로드와 수백 개의 플러그인을 지원하는 가장 인기 있는 트랜스파일러입니다.
핵심 요점
트랜스파일레이션(소스-대-소스 컴파일)은 프로그램을 한 프로그래밍 언어에서 다른 언어로 변환하면서 동일한 추상화 수준을 유지하는 프로세스입니다. 트랜스파일러는 언어 A의 소스 코드를 받아 대상 환경에서 실행할 수 있는 언어 B의 동등한 코드를 생성합니다. 일반적인 예: TypeScript에서 JavaScript, SASS에서 CSS, Haxe에서 여러 대상 언어로.
트랜스파일레이션은 컴파일과 달리 출력 코드가 높은 수준으로 유지되어 사람이 읽을 수 있다는 점입니다(비록 그 목적은 아니지만). 컴파일러(GCC, LLVM, javac)는 코드를 기계어 또는 바이트코드로 변환합니다 — 읽을 수 없는 형식입니다. 트랜스파일러는 추가로 컴파일하거나 축소할 수 있는 코드를 생성합니다.
트랜스파일레이션이 필요한 이유. 주요 이유는 호환성입니다. 개발자는 최신 언어(타입이 있는 TypeScript, null safety가 있는 Kotlin)를 사용하려 하지만 대상 플랫폼이 JavaScript 또는 Java만 지원합니다. 트랜스파일레이션을 통해 최신 언어로 작성하면서 대상 환경에서 이해할 수 있는 코드를 배포할 수 있습니다.
| 트랜스파일러 | 소스 → 대상 | 용도 |
|---|---|---|
| Babel | ES6+/TypeScript → ES5 | 웹 개발, React, Vue |
| tsc(TypeScript 컴파일러) | TypeScript → JavaScript | 모든 TypeScript 애플리케이션 |
| kotlinc-js | Kotlin → JavaScript | Kotlin/JS, React Kotlin Wrappers |
| dart2js | Dart → JavaScript | Flutter Web, AngularDart |
| SWC | TypeScript/JS → ES5 | Next.js, Rust 기반 번들링 |
추상화 수준이 주요 차이점입니다. 트랜스파일러는 동일한 수준의 언어 간(고수준 → 고수준) 코드를 변환합니다. 컴파일러는 고수준에서 저수준(기계어, 바이트코드)으로 변환합니다. LLVM IR은 중간 표현이지만 여전히 원본 C++ 또는 Rust보다 낮은 수준입니다.
결과의 가독성이 두 번째 차이점입니다. 트랜스파일의 결과(TypeScript에서 JavaScript)는 읽을 수 있고 브라우저에서 디버그할 수 있습니다. 컴파일의 결과(C++에서 기계어)는 읽기 위한 것이 아니며 분석에는 디스어셈블러가 필요합니다. 소스 맵은 트랜스파일된 코드를 원본 소스와 연결하여 디버그를 돕습니다.
CI/CD 파이프라인에서 트랜스파일레이션은 빌드 단계에서 수행됩니다. TypeScript 프로젝트의 경우 tsc 또는 Babel이 Docker 컨테이너에서 실행되어 JavaScript와 소스 맵을 생성한 후 축소되어 서버 또는 앱 스토어에 배포됩니다. 트랜스파일 결과의 캐싱을 구성하는 것이 중요합니다 — tsc --incremental은 실행 간 종속성 그래프를 저장하여 빌드 시간을 30-50% 단축합니다.
모바일 프로젝트(React Native)의 경우 Metro Bundler를 통한 트랜스파일은 각 릴리스마다 CI 서버에서 실행됩니다. 캐시 디렉토리(tmp/metro-cache)와 --workers를 통한 병렬 빌드가 프로세스를 가속화합니다. GitHub Actions와 GitLab CI는 실행 간 node_modules 및 .cache 디렉토리 캐싱을 지원하며, 이는 파이프라인 시간 단축에 중요합니다.
실행 속도도 다릅니다. 기계어로 컴파일하면 최대 성능을 제공합니다. 트랜스파일은 추상화 수준의 오버헤드를 유지합니다: TypeScript에서 나온 JavaScript는 일반 JavaScript와 동일한 속도로 실행됩니다. 최적화(TypeScript —strict)는 분석 단계에서 작동하며 런타임에는 작동하지 않습니다.
시나리오 1: TypeScript → JavaScript — 가장 일반적인 시나리오입니다. 개발자가 타입이 있는 TypeScript로 작성하면 tsc 컴파일러 또는 Babel이 타입 주석을 제거하고 순수 JavaScript를 생성합니다. 모든 Angular 프로젝트와 대부분의 React 프로젝트(2026)는 TypeScript 트랜스파일을 사용합니다. State of JS 2025에 따르면, 설문조사에 참여한 개발자의 79%가 주요 프로젝트에서 TypeScript를 사용합니다.
시나리오 2: Kotlin → JavaScript — 풀스택 개발을 위해 Kotlin/JS에서 사용됩니다. Kotlin 코드는 IR(Intermediate Representation)을 사용하여 Kotlin 컴파일러를 통해 JavaScript로 컴파일됩니다. Kotlin/JS는 외부 JS 라이브러리와의 통합을 위해 TypeScript 타입 선언(.d.ts)을 지원합니다. JetBrains는 자사 제품의 웹 인터페이스에 Kotlin/JS를 사용합니다.
시나리오 3: SASS/SCSS → CSS — CSS 전처리기의 트랜스파일입니다. Dart Sass(권장 구현)는 .scss를 .css로 트랜스파일하여 믹스인, 변수, 중첩 규칙 및 함수를 확장합니다. 이것은 컴파일이 아니라(CSS는 그대로 CSS) 구문 확장을 동반한 트랜스파일입니다.
| 파라미터 | 트랜스파일레이션 | 컴파일 | 인터프리테이션 |
|---|---|---|---|
| 입력 → 출력 | 고수준 → 고수준 | 고수준 → 기계어 | 코드 → 즉시 실행 |
| 예시 | TypeScript → JavaScript | C++ → ARM/x86 | Python → CPython 런타임 |
| 출력 코드 가독성 | 예 | 아니요 | 해당 없음 |
| 성능 | 대상 언어와 동일 | 최대 | 컴파일보다 낮음 |
| 런타임 필요 | 아니요(순수 대상 코드) | 아니요 | 예 |
Babel은 가장 인기 있는 JavaScript 트랜스파일러로, ES6+/ESNext 코드를 ES5 호환 JavaScript로 변환합니다. Babel은 플러그인 및 프리셋 시스템을 통해 작동합니다: 각 플러그인이 하나의 변환(화살표 함수, async/await, 옵셔널 체이닝)을 담당합니다. @babel/preset-env는 대상 브라우저(browserslist)를 기반으로 필요한 플러그인을 자동으로 결정합니다.
Babel 아키텍처는 세 단계로 구성됩니다: 파싱 → 변환 → 생성. 파서(Babylon/@babel/parser)는 소스 코드를 AST(추상 구문 트리)로 변환합니다. 트랜스포머(플러그인)가 AST를 수정합니다. 생성기(@babel/generator)가 수정된 AST에서 출력 코드를 생성합니다.
// 원본 ES6+ 코드
const greet = (name = "World") => {
return `Hello, ${name}!`;
};
class User {
constructor(name) {
this.name = name;
}
}
const data = { user: { address: { city: "Moscow" } } };
const city = data?.user?.address?.city;// Babel 적용 후 (target: > 0.25%, not dead)
"use strict";
var greet = function (name) {
if (name === void 0) { name = "World"; }
return "Hello, " + name + "!";
};
var User = function (name) {
this.name = name;
};
var data = { user: { address: { city: "Moscow" } } };
var city = data != null
? data.user != null
? data.user.address != null
? data.user.address.city
: void 0
: void 0
: void 0;Babel이 변환했습니다: 화살표 함수를 함수 표현식으로, 기본 매개변수(name = “World”)를 void 0 검사로, 템플릿 문자열을 연결로, 클래스를 생성자 함수로, 옵셔널 체이닝(?.)을 삼항 연산자 체인으로. const는 ES5 호환성을 위해 var로 대체되었습니다.
TypeScript는 강력한 타입 언어로 JavaScript로 트랜스파일됩니다. tsc 컴파일러(TypeScript 컴파일러)는 두 가지 작업을 수행합니다: 타입 검사와 트랜스파일(출력). 중요한 점은 타입 검사와 트랜스파일이 독립적인 단계라는 것입니다. 타입 검사 없이 트랜스파일을 실행하거나(--noEmitOnError false) 코드 생성 없이 타입 검사를 실행할 수 있습니다(--noEmit true).
TypeScript 트랜스파일은 모든 타입 주석, 인터페이스, 타입 별칭 및 제네릭 매개변수를 제거합니다 — 이들은 JavaScript에 존재하지 않습니다. 열거형은 객체로, 데코레이터는 함수 호출로, async/await는 제너레이터로(target이 ES2017 미만인 경우) 변환됩니다. tsconfig.json은 target(JavaScript 버전), module(모듈 시스템), strict(타입 검사 엄격도) 및 outDir(출력 폴더)를 제어합니다.
{
"compilerOptions": {
"target": "es2015",
"module": "esnext",
"lib": ["es2015", "dom"],
"strict": true,
"outDir": "./dist",
"rootDir": "./src",
"esModuleInterop": true,
"sourceMap": true,
"declaration": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}target: “es2015”는 tsc에 ES6 구문(화살표 함수, 클래스, let/const)으로 JavaScript를 생성하도록 지시합니다. module: “esnext”는 Webpack에서 이후 Tree Shaking을 위해 ES 모듈(import/export)을 유지합니다. strict: true는 모든 타입 검사(strictNullChecks, noImplicitAny, strictFunctionTypes)를 활성화합니다. declaration: true는 라이브러리의 TypeScript 소비자를 위해 .d.ts 파일을 생성합니다.
React Native는 Babel과 Metro를 사용하여 JavaScript/TypeScript를 JavaScriptCore(iOS) 또는 Hermes(Android)에서 실행할 수 있는 코드로 트랜스파일합니다. Babel 플러그인은 JSX 변환, Flow/TypeScript 주석 및 React Native 특화 최적화를 추가합니다. Metro Bundler는 추가로 모듈을 번들링하고 개발을 위한 Hot Module Replacement를 수행합니다.
Flutter는 Dart 트랜스파일을 사용합니다. Flutter Web의 경우 dart2js가 Dart를 최적화된 JavaScript로 트랜스파일합니다. Flutter Mobile의 경우 dart2native가 Dart를 네이티브 ARM 코드로 컴파일합니다. Flutter는 개발을 위해 Dart DevCompiler(dartdevc)도 지원합니다 — 더 빠르게 Dart를 JavaScript로 트랜스파일하지만 최적화는 적습니다.
// babel.config.js — React Native 트랜스파일
module.exports = {
presets: [
["module:metro-react-native-babel-preset"],
],
plugins: [
["module-resolver", {
root: ["."],
alias: {
"@": "./src",
"@components": "./src/components",
},
}],
"react-native-reanimated/plugin",
],
env: {
production: {
plugins: ["transform-remove-console"],
},
},
};metro-react-native-babel-preset에는 React Native에 필요한 모든 플러그인이 포함되어 있습니다: JSX, Flow/TypeScript, Metro 모듈 시스템, async/await, 클래스 프로퍼티 및 데코레이터. module-resolver 플러그인은 짧은 임포트를 위한 별칭을 추가합니다(@/components/Button을 ../../components/Button 대신). 프로덕션 모드에서는 transform-remove-console이 코드에서 모든 console.log를 제거합니다.
자주 묻는 질문
트랜스파일은 동일한 수준의 다른 언어로 코드를 변환합니다(예: TypeScript → JavaScript). 컴파일은 고수준에서 저수준(C++ → 기계어)으로 변환합니다. 트랜스파일의 결과는 읽을 수 있지만 컴파일의 결과는 읽을 수 없습니다.
React Native는 기본적으로 트랜스파일이 필요합니다 — Metro Bundler가 Babel을 사용하여 JSX, TypeScript 및 최신 JavaScript를 JavaScriptCore 및 Hermes와 호환되는 코드로 변환합니다. Babel이 없으면 React Native는 컴포넌트의 JSX 구문을 실행할 수 없습니다.
가능합니다: Babel과 @babel/preset-typescript 및 SWC가 TypeScript 트랜스파일을 지원합니다. tsc보다 빠르지만 Babel은 타입 검사를 수행하지 않고 타입 주석만 제거합니다. 타입 검사를 위해서는 tsc --noEmit을 별도로 실행하거나 fork-ts-checker-webpack-plugin을 사용해야 합니다.
소스 맵은 트랜스파일된 코드를 원본 소스와 연결하는 파일입니다. 브라우저에서 TypeScript를 디버그할 수 있게 합니다: 중단점은 .ts 파일에 설정되고 스택 트레이스는 .js 대신 .ts 라인을 표시합니다. 소스 맵 없이는 트랜스파일된 코드를 디버그하는 것이 거의 불가능합니다.
트랜스파일 자체는 애플리케이션 성능에 영향을 미치지 않습니다 — 출력 코드는 대상 언어로 네이티브하게 작성된 코드와 동일한 속도로 실행됩니다. 오버헤드는 트랜스파일러가 최적이 아닌 코드를 생성할 때만 발생합니다(예: Babel이 배열 메서드에 대한 대규모 폴리필을 생성할 수 있음).
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.