Turbo Module은 JavaScript Interface(JSI)를 기반으로 구축된 React Native 네이티브 모듈의 진화입니다. Bridge와 달리 Turbo Module은 동기식으로 작동하며 JSON 직렬화가 필요 없어 상당한 성능 향상을 제공합니다. Meta Engineering Blog, 2024에 따르면, Turbo Module은 새 아키텍처의 핵심 구성 요소이며 React Native 0.76+에서 사용할 수 있습니다.
핵심 사항
Turbo Module은 JavaScript와 네이티브 코드 간의 통신을 위해 기존 Bridge를 대체하는 새로운 React Native 아키텍처의 구성 요소입니다. 모든 메시지가 JSON으로 직렬화되어 비동기식으로 전송되는 Bridge와 달리, Turbo Module은 JSI(JavaScript가 C++로 작성된 함수를 직접 호출할 수 있게 하는 레이어)를 사용합니다.
Turbo Module 아키텍처는 Meta 팀이 React Conf 2021에서 “The New Architecture”라는 코드명 아래 더 큰 React Native 재구성의 일부로 발표했습니다. Turbo Module 외에도 새 아키텍처에는 Fabric(새 렌더러), Codegen(코드 생성기) 및 JSI(상호 작용 인터페이스)가 포함됩니다. 이러한 구성 요소는 함께 2015년부터 React Native에 축적된 성능 문제를 해결합니다.
Turbo Module은 기존 네이티브 모듈의 세 가지 주요 문제를 해결합니다: 비동기성(모든 호출이 큐를 통과), 직렬화(각 호출에 JSON 변환 필요), 로딩(모든 모듈이 앱 시작 시 초기화). Turbo Module을 사용하면 네이티브 메서드가 동기식으로 호출되고, 데이터는 복사 없이 전송되며, 모듈은 필요에 따라 로드됩니다.
JSI(JavaScript Interface)는 JavaScript 엔진(Hermes 또는 JSC)과 네이티브 코드 사이에 레이어를 생성하는 C++ API입니다. JSI는 호스트 객체를 제공합니다. 이는 일반 JavaScript 객체 및 메서드처럼 보이는 C++ 객체입니다. JavaScript가 이러한 객체의 메서드를 호출하면 JSI는 직렬화나 스레드 전환 없이 해당 C++ 코드를 직접 실행합니다.
JSI와 Bridge의 주요 차이점은 데이터 복사가 없다는 것입니다. Bridge에서는 각 값이 JSON 문자열로 직렬화되고, 큐를 통과하며, 역직렬화됩니다. JSI는 메모리의 데이터에 대한 포인터를 전달하므로 성능 저하 없이 대용량 데이터를 처리할 수 있습니다. Meta의 테스트에 따르면 JSI 호출은 Bridge를 통한 동등한 호출보다 5~10배 빠르게 실행됩니다.
JSI는 HostObject 인터페이스를 정의합니다. 이는 React Native가 JS 환경에 일반 객체로 등록하는 C++ 클래스입니다. JS 코드가 속성에 액세스하거나 HostObject의 메서드를 호출하면 JSI가 호출을 가로채서 C++ 코드를 실행합니다. 이를 통해 Bridge 큐를 기다리지 않고 동기식으로 작업을 수행할 수 있습니다.
// JSI HostObject 예제 — 동기 네이티브 호출
class ImageCompressorHostObject : public jsi::HostObject {
jsi::Value get(
jsi::Runtime& rt,
const jsi::PropNameID& propName
) override {
auto name = propName.utf8(rt);
if (name == "compressImage") {
return jsi::Function::createFromHostFunction(
rt,
jsi::PropNameID::forUtf8(rt, name),
2,
[](jsi::Runtime& rt,
const jsi::Value& thisValue,
const jsi::Value* args,
size_t count) -> jsi::Value {
return jsi::Value(rt, compressNative(
args[0].asString(rt).utf8(rt),
args[1].asNumber()
));
}
);
}
return jsi::Value::undefined();
}
};
위 코드는 JSI HostObject가 JavaScript의 compressImage 호출을 처리하는 방법을 보여줍니다. 함수는 두 개의 인수(경로 문자열과 품질 숫자)를 받고, 네이티브 함수 compressNative를 호출한 후 결과를 반환합니다. 모두 동기식이며, Bridge도 JSON도 필요하지 않습니다. 이것이 기존 아키텍처에 비해 JSI의 주요 이점입니다.
JSI는 React Native 메인 런타임의 일부이며 특정 JavaScript 엔진에 의존하지 않습니다. Hermes와 JavaScriptCore(JSC) 모두에서 작동하며 네이티브 환경과의 상호 작용을 위한 통합 인터페이스를 제공합니다.
Turbo Module과 Bridge의 비교는 React Native 아키텍처의 진화를 보여줍니다. Bridge는 2015년 React Native의 빠른 출시를 위해 설계되었지만, 애플리케이션 복잡성이 증가함에 따라 그 한계가 심각해졌습니다. Turbo Module은 이러한 문제를 아키텍처 수준에서 해결합니다.
| 특성 | Bridge | Turbo Module |
|---|---|---|
| 호출 속도 | 5~15ms 오버헤드 | 0.1~0.5ms 오버헤드 |
| 동기식 | 비동기만 가능 | 동기 및 비동기 |
| 직렬화 | 모든 호출에 JSON | 복사 없는 JSI 객체 |
| 타입 안전성 | 없음 | Codegen + TypeScript |
| 초기화 | 시작 시 모든 모듈 | 지연, 필요 시 |
실제로 차이는 빈번한 네이티브 메서드 호출(예: 미디어 처리 또는 GPU 작업)에서 가장 두드러집니다. 드문 호출(세션당 한 번)의 경우 성능 차이는 무시할 수 있습니다. Turbo Module은 또한 대용량 바이너리 데이터(이미지, 비디오, 바이너리 프로토콜) 처리를 단순화합니다. Bridge에서는 파일 시스템을 사용한 해결 방법이 필요했습니다.
Turbo Module을 생성하려면 TypeScript로 사양을 정의하는 것부터 시작합니다. Codegen은 이 사양을 기반으로 C++ 인터페이스와 Objective-C/Java 스텁을 자동으로 생성합니다. 이는 개발 방식을 완전히 바꿉니다. 개발자가 API를 한 번 설명하면 Codegen이 나머지를 모두 생성합니다.
// ImageCompressor.ts — Turbo Module 사양
import type { TurboModule } from 'react-native';
import type { Double } from 'react-native/Libraries/Types/CodegenTypes';
export interface Spec extends TurboModule {
compressImage(
imagePath: string,
quality: Double
): Promise<string>;
}
Codegen은 TypeScript 사양을 분석하고 C++ HostObject, Objective-C 프로토콜 및 Java 인터페이스를 생성합니다. 개발자는 네이티브 로직만 구현하면 됩니다. 이 접근 방식은 JavaScript와 네이티브 측의 타입이 항상 일치하도록 보장하여 수동 매핑 오류를 제거합니다.
// iOS용 TurboModule 구현 (생성된 스텁)
@interface ImageCompressorModule ()
RCT_EXPORT_MODULE(ImageCompressor)
@end
@implementation ImageCompressorModule
RCT_EXPORT_METHOD(compressImage:(NSString *)imagePath
quality:(NSNumber *)quality
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSData *compressed = [ImageProcessor compressAtPath:imagePath
quality:quality.doubleValue];
resolve([NSString stringWithUTF8String:compressed.UTF8String]);
}
@end
중요한 이점은 지연 로딩입니다. Turbo Module은 앱 시작 시 초기화되지 않고 JavaScript에서 처음 액세스할 때만 생성됩니다. 이는 모든 네이티브 모듈이 즉시 로드되는 기존 방식에 비해 앱 시작 시간을 30~50% 단축합니다.
Bridge에서 Turbo Module로의 전환은 애플리케이션을 완전히 다시 작성할 필요가 없습니다. React Native 0.73+는 두 아키텍처를 병렬로 지원합니다. Bridge 모듈은 계속 작동하고 새 모듈은 Turbo Module로 생성할 수 있습니다. 이를 통해 모듈별로 점진적으로 마이그레이션할 수 있습니다.
React Native 0.76+ 프로젝트에서 새 아키텍처를 활성화하려면 react-native.config.js 파일에서 newArchEnabled 플래그를 true로 설정합니다. 그 후에도 기존의 모든 네이티브 모듈은 Bridge를 통해 계속 작동하며 새 모듈은 Turbo Module로 생성할 수 있습니다. Codegen은 두 옵션을 모두 자동으로 처리합니다.
// react-native.config.js — 새 아키텍처 활성화
module.exports = {
project: {
ios: {},
android: {},
},
assets: [],
newArchEnabled: true,
};
JavaScript에서 가장 자주 호출되는 모듈부터 마이그레이션을 시작하는 것이 좋습니다. 이 모듈이 가장 큰 성능 향상을 얻을 수 있습니다. 드물게 호출되는 모듈(세션당 한 번)은 큰 성능 저하 없이 Bridge에 남겨둘 수 있습니다.
자주 묻는 질문
아니요, Turbo Module은 새 아키텍처가 활성화된 React Native 0.73+가 필요합니다. 버전 0.76부터 새 아키텍처는 안정화되어 프로덕션 프로젝트에 권장됩니다.
예, Turbo Module은 두 플랫폼을 모두 지원합니다. JSI는 크로스 플랫폼 C++ 레이어이며 Codegen은 iOS와 Android용으로 각각 Objective-C와 Java 스텁을 생성합니다.
아니요, Turbo Module은 JSI를 통해 모든 JS 엔진에서 작동합니다. 그러나 Hermes는 JSI 및 새 React Native 아키텍처와 함께 작동하도록 최적화되어 있어 권장됩니다.
Turbo Module 디버깅은 일반 네이티브 코드처럼 Xcode 또는 Android Studio를 통해 수행됩니다. 또한 JSI 호출 및 모듈 성능 추적을 위해 Flipper를 사용할 수 있습니다.
Turbo Module은 앱 크기에 거의 영향을 미치지 않습니다. JSI의 C++ 코드는 이미 React Native의 일부이며 생성되는 코드는 최소화되어 로직 중복 없이 인터페이스만 포함됩니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.