Skip to main content

Codegen 사용하기

이 가이드에서는 다음과 같은 내용을 다룬다:

  • Codegen을 설정하는 방법
  • 각 플랫폼별로 수동으로 Codegen을 호출하는 방법

또한 생성된 코드에 대해서도 설명한다.

사전 준비

React Native 앱이 있어야만 Codegen을 수동으로 실행하더라도 코드를 올바르게 생성할 수 있다. Codegen 과정은 앱 빌드와 밀접하게 연결되어 있으며, 관련 스크립트는 react-native NPM 패키지에 위치한다.

이 가이드를 따라 하려면 React Native CLI를 사용해 다음과 같이 프로젝트를 생성한다:

bash
npx @react-native-community/cli@latest init SampleApp --version 0.76.0

Codegen은 커스텀 모듈이나 컴포넌트를 위한 글루 코드를 생성하는 데 사용된다. Turbo Native Modules와 Fabric Native Components를 만드는 방법에 대한 자세한 내용은 해당 가이드를 참고한다.

Codegen 설정하기

Codegen은 앱의 package.json 파일을 수정하여 설정할 수 있다. CodegencodegenConfig라는 커스텀 필드로 제어된다.

package.json
  "codegenConfig": {
"name": "<SpecName>",
"type": "<types>",
"jsSrcsDir": "<source_dir>",
"android": {
"javaPackageName": "<java.package.name>"
},
"ios": {
"modulesConformingToProtocol": {
"RCTImageURLLoader": [
"<iOS-class-conforming-to-RCTImageURLLoader>",
// react-native-camera-roll 예시: https://github.com/react-native-cameraroll/react-native-cameraroll/blob/8a6d1b4279c76e5682a4b443e7a4e111e774ec0a/package.json#L118-L127
// "RNCPHAssetLoader",
],
"RCTURLRequestHandler": [
"<iOS-class-conforming-to-RCTURLRequestHandler>",
// react-native-camera-roll 예시: https://github.com/react-native-cameraroll/react-native-cameraroll/blob/8a6d1b4279c76e5682a4b443e7a4e111e774ec0a/package.json#L118-L127
// "RNCPHAssetUploader",
],
"RCTImageDataDecoder": [
"<iOS-class-conforming-to-RCTImageDataDecoder>",
// 이에 대한 좋은 예시는 없지만, 동일한 방식으로 동작한다. RCTImageDataDecoder를 구현하는 클래스 이름을 전달한다. 네이티브 모듈이어야 한다.
]
},
"componentProvider": {
"<componentName>": "<iOS-class-implementing-the-component>"
},
}
},

이 코드 조각을 앱에 추가하고 각 필드를 커스텀할 수 있다:

  • name: 스펙을 포함하는 파일을 생성할 때 사용할 이름이다. 관례적으로 Spec 접미사를 붙이지만, 필수는 아니다.
  • type: 생성할 코드의 타입이다. 허용되는 값은 modules, components, all이다.
    • modules: Turbo Native Modules에 대한 코드만 생성할 때 사용한다.
    • components: Native Fabric Components에 대한 코드만 생성할 때 사용한다.
    • all: 컴포넌트와 모듈이 혼합된 경우 사용한다.
  • jsSrcsDir: 모든 스펙이 위치한 루트 폴더를 지정한다.
  • android.javaPackageName: Codegen이 파일을 커스텀 패키지에 생성하도록 하는 Android 전용 설정이다.
  • ios: ios 필드는 앱 개발자와 라이브러리 관리자가 고급 기능을 제공하기 위해 사용할 수 있는 객체이다. 다음 필드는 모두 선택 사항이다.
    • ios.modulesConformingToProtocol: React Native는 네이티브 모듈이 특정 동작을 커스텀하기 위해 구현할 수 있는 프로토콜을 제공한다. 이 필드를 통해 해당 프로토콜을 준수하는 모듈 목록을 정의할 수 있다. 이 모듈들은 앱이 시작될 때 React Native 런타임에 주입된다.
      • ios.modulesConformingToProtocol.RCTImageURLLoader: RCTImageURLLoader 프로토콜을 구현하는 iOS 네이티브 모듈 목록이다. RCTImageURLLoader를 구현하는 iOS 클래스 이름을 전달해야 한다. 네이티브 모듈이어야 한다.
      • ios.modulesConformingToProtocol.RCTURLRequestHandler: RCTURLRequestHandler 프로토콜을 구현하는 iOS 네이티브 모듈 목록이다. RCTURLRequestHandler를 구현하는 iOS 클래스 이름을 전달해야 한다. 네이티브 모듈이어야 한다.
      • ios.modulesConformingToProtocol.RCTImageDataDecoder: RCTImageDataDecoder 프로토콜을 구현하는 iOS 네이티브 모듈 목록이다. RCTImageDataDecoder를 구현하는 iOS 클래스 이름을 전달해야 한다. 네이티브 모듈이어야 한다.
    • ios.componentProvider: 이 필드는 커스텀 JS React 컴포넌트와 이를 구현하는 네이티브 클래스 간의 연결을 생성하기 위해 사용되는 맵이다. 맵의 키는 컴포넌트의 JS 이름(예: TextInput)이고, 값은 컴포넌트를 구현하는 iOS 클래스(예: RCTTextInput)이다.

Codegen이 실행되면 앱의 모든 의존성을 검색하여 특정 규칙을 따르는 JS 파일을 찾고, 필요한 코드를 생성한다:

  • Turbo Native Modules는 스펙 파일이 Native로 시작해야 한다. 예를 들어, NativeLocalStorage.ts는 유효한 스펙 파일 이름이다.
  • Native Fabric Components는 스펙 파일이 NativeComponent로 끝나야 한다. 예를 들어, WebViewNativeComponent.ts는 유효한 스펙 파일 이름이다.

Codegen 실행하기

이 가이드의 나머지 부분은 여러분의 프로젝트에 Native Turbo Module, Native Fabric 컴포넌트 또는 둘 다 이미 설정되어 있다고 가정한다. 또한 package.json에 지정된 jsSrcsDir에 유효한 스펙 파일이 있다고 가정한다.

Android

안드로이드에서의 Codegen은 React Native Gradle Plugin(RNGP)과 통합되어 있다. RNGP는 package.json 파일에 정의된 설정을 읽고 Codegen을 실행할 수 있는 태스크를 포함한다. 이 Gradle 태스크를 실행하려면 먼저 프로젝트의 android 폴더로 이동한 후 다음 명령어를 실행한다:

bash
./gradlew generateCodegenArtifactsFromSchema

이 태스크는 앱에 연결된 모든 프로젝트(앱과 연결된 모든 node 모듈)에서 generateCodegenArtifactsFromSchema 명령어를 실행한다. 이는 해당 node_modules/<dependency> 폴더에 코드를 생성한다. 예를 들어, my-fabric-component라는 Fabric Native Component가 있다면, 생성된 코드는 SampleApp/node_modules/my-fabric-component/android/build/generated/source/codegen 경로에 위치한다. 앱의 경우, 생성된 코드는 android/app/build/generated/source/codegen 폴더에 저장된다.

위의 gradle 명령어를 실행한 후, SampleApp/android/app/build 폴더에서 코드 생성된 코드를 찾을 수 있다. 구조는 다음과 같다:

build
└── generated
└── source
└── codegen
├── java
│ └── com
│ ├── facebook
│ │ └── react
│ │ └── viewmanagers
│ │ ├── <nativeComponent>ManagerDelegate.java
│ │ └── <nativeComponent>ManagerInterface.java
│ └── sampleapp
│ └── NativeLocalStorageSpec.java
├── jni
│ ├── <codegenConfig.name>-generated.cpp
│ ├── <codegenConfig.name>.h
│ ├── CMakeLists.txt
│ └── react
│ └── renderer
│ └── components
│ └── <codegenConfig.name>
│ ├── <codegenConfig.name>JSI-generated.cpp
│ ├── <codegenConfig.name>.h
│ ├── ComponentDescriptors.cpp
│ ├── ComponentDescriptors.h
│ ├── EventEmitters.cpp
│ ├── EventEmitters.h
│ ├── Props.cpp
│ ├── Props.h
│ ├── ShadowNodes.cpp
│ ├── ShadowNodes.h
│ ├── States.cpp
│ └── States.h
└── schema.json

생성된 코드는 두 개의 폴더로 나뉜다:

  • java 폴더에는 플랫폼별 코드가 포함된다.
  • jni 폴더에는 JS와 Java가 올바르게 상호작용할 수 있도록 필요한 C++ 코드가 포함된다.

java 폴더 내에서 com/facebook/viewmanagers 하위 폴더에 Fabric 네이티브 컴포넌트의 생성된 코드를 찾을 수 있다.

  • <nativeComponent>ManagerDelegate.java 파일은 ViewManager가 커스텀 네이티브 컴포넌트에서 호출할 수 있는 메서드를 포함한다.
  • <nativeComponent>ManagerInterface.java 파일은 ViewManager의 인터페이스를 포함한다.

codegenConfig.android.javaPackageName에 설정된 이름의 폴더에서는 Turbo 네이티브 모듈이 작업을 수행하기 위해 구현해야 하는 추상 클래스를 찾을 수 있다.

jni 폴더에는 JS와 Android를 연결하기 위한 모든 보일러플레이트 코드가 포함된다.

  • <codegenConfig.name>.h 파일은 커스텀 C++ Turbo 네이티브 모듈의 인터페이스를 포함한다.
  • <codegenConfig.name>-generated.cpp 파일은 커스텀 C++ Turbo 네이티브 모듈의 연결 코드를 포함한다.
  • react/renderer/components/<codegenConfig.name> 폴더에는 커스텀 컴포넌트에 필요한 모든 연결 코드가 포함된다.

이 구조는 codegenConfig.type 필드에 all 값을 사용하여 생성되었다. modules 값을 사용하면 react/renderer/components/ 폴더가 생성되지 않는다. components 값을 사용하면 다른 파일들이 생성되지 않는다.

iOS

iOS에서 Codegen은 빌드 프로세스 중에 실행되는 Node 스크립트에 의존한다. 이 스크립트들은 SampleApp/node_modules/react-native/scripts/ 폴더에 위치한다.

주요 스크립트는 generate-codegen-artifacts.js이다. 이 스크립트를 실행하려면 앱의 루트 폴더에서 다음 커맨드를 실행한다:

bash
node node_modules/react-native/scripts/generate-codegen-artifacts.js

Usage: generate-codegen-artifacts.js -p [path to app] -t [target platform] -o [output path]

Options:
--help 도움말 보기 [boolean]
--version 버전 번호 보기 [boolean]
-p, --path React Native 프로젝트 루트 경로 [required]
-t, --targetPlatform 타겟 플랫폼. 지원 값: "android", "ios", "all".
[required]
-o, --outputPath 생성된 파일이 저장될 경로

여기서:

  • --path는 앱의 루트 폴더 경로를 나타낸다.
  • --outputPathCodegen이 생성한 파일을 저장할 경로이다.
  • --targetPlatform은 코드를 생성할 플랫폼을 지정한다.

생성된 코드

다음 인자와 함께 스크립트를 실행한다:

shell
node node_modules/react-native/scripts/generate-codegen-artifacts.js \
--path . \
--outputPath ios/ \
--targetPlatform ios

이 명령어를 실행하면 ios/build 폴더에 다음과 같은 파일들이 생성된다:

build
└── generated
└── ios
├── <codegenConfig.name>
│ ├── <codegenConfig.name>-generated.mm
│ └── <codegenConfig.name>.h
├── <codegenConfig.name>JSI-generated.cpp
├── <codegenConfig.name>JSI.h
├── FBReactNativeSpec
│ ├── FBReactNativeSpec-generated.mm
│ └── FBReactNativeSpec.h
├── FBReactNativeSpecJSI-generated.cpp
├── FBReactNativeSpecJSI.h
├── RCTModulesConformingToProtocolsProvider.h
├── RCTModulesConformingToProtocolsProvider.mm
└── react
└── renderer
└── components
└── <codegenConfig.name>
├── ComponentDescriptors.cpp
├── ComponentDescriptors.h
├── EventEmitters.cpp
├── EventEmitters.h
├── Props.cpp
├── Props.h
├── RCTComponentViewHelpers.h
├── ShadowNodes.cpp
├── ShadowNodes.h
├── States.cpp
└── States.h

이 중 일부 생성된 파일은 React Native 코어에서 사용된다. 그리고 package.jsoncodegenConfig.name 필드에 지정한 이름과 동일한 이름을 가진 파일들도 포함된다.

  • <codegenConfig.name>/<codegenConfig.name>.h: 커스텀 iOS Turbo Native Modules의 인터페이스를 포함한다.
  • <codegenConfig.name>/<codegenConfig.name>-generated.mm: 커스텀 iOS Turbo Native Modules의 연결 코드를 포함한다.
  • <codegenConfig.name>JSI.h: 커스텀 C++ Turbo Native Modules의 인터페이스를 포함한다.
  • <codegenConfig.name>JSI-generated.h: 커스텀 C++ Turbo Native Modules의 연결 코드를 포함한다.
  • react/renderer/components/<codegenConfig.name>: 커스텀 컴포넌트에 필요한 모든 연결 코드를 포함하는 폴더다.

이 구조는 codegenConfig.type 필드에 all 값을 사용해 생성된다. 만약 modules 값을 사용하면 react/renderer/components/ 폴더가 생성되지 않는다. components 값을 사용하면 다른 파일들이 생성되지 않는다.