Add TurboModule and CodegenNativeComponent bindings for React Native New Architecture#840
Add TurboModule and CodegenNativeComponent bindings for React Native New Architecture#840ricku44 wants to merge 1 commit intorescript-react-native:mainfrom
Conversation
There was a problem hiding this comment.
IMHO, this should be enough:
module CodegenNativeComponent = {
type options = {
interfaceOnly?: bool,
paperComponentName?: string,
paperComponentNameDeprecated?: string,
excludedPlatforms?: array<[#iOS | #android]>,
}
type nativeComponentType<'props> = React.component<'props>
@module("react-native")
external codegenNativeComponent: (
string,
~options: options=?,
) => nativeComponentType<'props> = "codegenNativeComponent"
}module TurboModuleRegistry = {
@module("react-native") @scope("TurboModuleRegistry")
external get: string => nullable<'t> = "get"
@module("react-native") @scope("TurboModuleRegistry")
external getEnforcing: string => 't = "getEnforcing"
}|
hi @Freddy03h, Thanks for reviewing the PR. Let me give you more insights. This PR introduces ReScript support for React Native's codegen system. Currently, React Native codegen works by parsing TypeScript or Flow files using respective AST parsers (like I've implemented a Flow-like AST parser for ReScript that translates ReScript syntax into the same Flow AST format that the existing codegen pipeline expects. This allows developers to write native module and component specifications in ReScript while maintaining full compatibility with the existing codegen infrastructure. Could you please review the implementation and suggest any improvements? I'm particularly interested in feedback on the best Rescript syntax for this for AST transformation logic and whether the ReScript-to-Flow AST mapping aligns well with the existing codegen expectations. NativeTurboModule.resopen ReactNative
open TurboModule
type spec = {
...turboModule,
initialise: ((option<string>, option<string>) => unit) => unit,
getSession: (
Js.Dict.t<string>,
Js.Dict.t<string>,
array<Js.Json.t>,
(option<string>, option<string>) => unit,
) => unit,
exit: string => unit,
}
let hyperHeadlessModule: get<spec> = get("HyperHeadlessModule")NativeButtonComponent.resopen ReactNative
open CodegenNativeComponent
module NativeButton = {
type props = {
...View.viewProps,
title: string,
color?: string,
}
let make: nativeComponentType<props> = codegenNativeComponent("NativeButton", ~options=makeOptions(~interfaceOnly=true, ()))
} |
|
hi @ricku44 |
|
Shared code works well, I'm wondering how should we add ReScript-specific validations that React Native enforces. Codegen supports TypeScript and Flow primarily and not JS maybe for type enforcement at the JavaScript-native boundary, preventing runtime crashes and ensuring performance. NativeModule and NativeComponent registration patterns involves getConstants and ViewProps enforcement. Works ✅import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {}
export default TurboModuleRegistry.getEnforcing<Spec>('NativeLocalStorage');Fails ❌import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';
export interface Spec {}
export default TurboModuleRegistry.getEnforcing<Spec>('NativeLocalStorage');Fails ❌import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';
export interface Spec extends TurboModule {}
export default TurboModuleRegistry.getEnforcing('NativeLocalStorage');Fails ❌import {TurboModuleRegistry} from 'react-native';
export interface Spec {
getConstants(): {};
}
export default TurboModuleRegistry.getEnforcing('NativeLocalStorage');Works ✅import type {ViewProps} from 'react-native';
import {codegenNativeComponent} from 'react-native';
export interface NativeProps extends ViewProps {
sourceURL?: string;
}
export default codegenNativeComponent<NativeProps>('CustomWebView');Fails ❌import {codegenNativeComponent} from 'react-native';
export interface NativeProps {
sourceURL?: string;
}
export default codegenNativeComponent<NativeProps>('CustomWebView');Fails ❌import type {ViewProps} from 'react-native';
import {codegenNativeComponent} from 'react-native';
export interface NativeProps extends ViewProps {
sourceURL?: string;
}
export default codegenNativeComponent('CustomWebView'); |
|
I think this is more than just bindings. I can't help you with the AST Parser or even if you want to use genType (I never used it). The only things I can't tell about your bindings is that you should prefer |
|
Should we make the flow consistent in NativeModule.res as well? |
|
@Freddy03h PR is ready for review. |
Changes Made
src/apis/TurboModule.res: Core TurboModule type definitions with proper inheritance enforcementsrc/apis/CodegenNativeComponent.res: Bindings for native component code generationTesting