Skip to content

Commit 1cc3e42

Browse files
authored
fix(Worklets): remote function re-serialization (#9115)
## Summary In Bundle Mode we always use `createSerializable` function which had no path for re-serializing remote functions. This PR adds such paths so remote function can be now passed freely between runtimes more than once. ## Test plan Runtime tests pass in Bundle mode and outside of Bundle Mode.
1 parent 9e1560c commit 1cc3e42

File tree

5 files changed

+38
-56
lines changed

5 files changed

+38
-56
lines changed

apps/common-app/src/apps/reanimated/examples/RuntimeTests/tests/runtimes/runOnRuntimeSyncWithId.test.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,11 @@ describe('runOnRuntimeSyncWithId', () => {
7070
value = 0;
7171
scheduleOnUI(() => {
7272
'worklet';
73-
// @ts-expect-error TODO: fix RemoteFunction re-serialization.
74-
const remoteFunction = callbackPass.__remoteFunction as typeof callbackPass;
7573
const result = runOnRuntimeSyncWithId(UIRuntimeId, () => {
7674
'worklet';
7775
return 42;
7876
});
79-
scheduleOnRN(remoteFunction, result);
77+
scheduleOnRN(callbackPass, result);
8078
});
8179
await waitForNotification(PASS_NOTIFICATION);
8280
expect(value).toBe(42);
@@ -85,14 +83,11 @@ describe('runOnRuntimeSyncWithId', () => {
8583
test('from UI Runtime to Worker Runtime', async () => {
8684
scheduleOnUI(() => {
8785
'worklet';
88-
// @ts-expect-error TODO: fix RemoteFunction re-serialization.
89-
const remoteFunction = callbackPass.__remoteFunction as typeof callbackPass;
90-
9186
const result = runOnRuntimeSyncWithId(workletRuntime1.runtimeId, () => {
9287
'worklet';
9388
return 42;
9489
});
95-
scheduleOnRN(remoteFunction, result);
90+
scheduleOnRN(callbackPass, result);
9691
});
9792
await waitForNotification(PASS_NOTIFICATION);
9893
expect(value).toBe(42);
@@ -101,14 +96,12 @@ describe('runOnRuntimeSyncWithId', () => {
10196
test('from UI Runtime to non-existing Runtime', async () => {
10297
scheduleOnUI(() => {
10398
'worklet';
104-
// @ts-expect-error TODO: fix RemoteFunction re-serialization.
105-
const remoteFunction = callbackPass.__remoteFunction as typeof callbackPass;
10699
try {
107100
const result = runOnRuntimeSyncWithId(9999, () => {
108101
'worklet';
109102
return 42;
110103
});
111-
scheduleOnRN(remoteFunction, result);
104+
scheduleOnRN(callbackPass, result);
112105
} catch (error) {
113106
scheduleOnRN(callbackFail, error instanceof Error ? error.message : String(error));
114107
}

apps/common-app/src/apps/reanimated/examples/RuntimeTests/tests/runtimes/scheduleOnRuntime.test.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
import { beforeEach, describe, expect, notify, test, waitForNotification } from '../../ReJest/RuntimeTestsApi';
99

1010
type localGlobal = typeof globalThis & {
11-
__notifyPass(num: number): void;
11+
scheduleOnRN: typeof scheduleOnRN;
1212
};
1313

1414
describe('scheduleOnRuntime', () => {
@@ -30,13 +30,10 @@ describe('scheduleOnRuntime', () => {
3030
value = 0;
3131

3232
[workletRuntime1, workletRuntime2].forEach(runtime => {
33-
// TODO: fix RemoteFunction re-serialization.
3433
runOnRuntimeSync(runtime, () => {
3534
'worklet';
36-
(globalThis as localGlobal).__notifyPass = (num: number) => {
37-
'worklet';
38-
scheduleOnRN(callbackPass, num);
39-
};
35+
// TODO: fix worklet re-serialization outside of Bundle Mode
36+
(globalThis as localGlobal).scheduleOnRN = scheduleOnRN;
4037
});
4138
});
4239
});
@@ -58,7 +55,7 @@ describe('scheduleOnRuntime', () => {
5855

5956
scheduleOnRuntime(workletRuntime1, () => {
6057
'worklet';
61-
(globalThis as localGlobal).__notifyPass(42);
58+
(globalThis as localGlobal).scheduleOnRN(callbackPass, 42);
6259
});
6360
});
6461

@@ -72,7 +69,7 @@ describe('scheduleOnRuntime', () => {
7269

7370
scheduleOnRuntime(workletRuntime2, () => {
7471
'worklet';
75-
(globalThis as localGlobal).__notifyPass(42);
72+
(globalThis as localGlobal).scheduleOnRN(callbackPass, 42);
7673
});
7774
});
7875

apps/common-app/src/apps/reanimated/examples/RuntimeTests/tests/runtimes/scheduleOnRuntimeWithId.test.tsx

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ const PASS_NOTIFICATION = 'PASS';
1313
const FAIL_NOTIFICATION = 'FAIL';
1414

1515
type localGlobal = typeof globalThis & {
16-
__notifyPass(num: number): void;
17-
__notifyFail(rea: string): void;
16+
scheduleOnRN: typeof scheduleOnRN;
1817
};
1918

2019
describe('scheduleOnRuntimeWithId', () => {
@@ -42,17 +41,10 @@ describe('scheduleOnRuntimeWithId', () => {
4241
reason = '';
4342

4443
[UIRuntimeId, workletRuntime1.runtimeId, workletRuntime2.runtimeId].forEach(runtimeId => {
45-
// TODO: fix RemoteFunction re-serialization.
4644
runOnRuntimeSyncWithId(runtimeId, () => {
4745
'worklet';
48-
(globalThis as localGlobal).__notifyPass = (num: number) => {
49-
'worklet';
50-
scheduleOnRN(callbackPass, num);
51-
};
52-
(globalThis as localGlobal).__notifyFail = (rea: string) => {
53-
'worklet';
54-
scheduleOnRN(callbackFail, rea);
55-
};
46+
// TODO: fix worklet re-serialization outside of Bundle Mode
47+
(globalThis as localGlobal).scheduleOnRN = scheduleOnRN;
5648
});
5749
});
5850
});
@@ -95,7 +87,7 @@ describe('scheduleOnRuntimeWithId', () => {
9587
'worklet';
9688
scheduleOnRuntimeWithId(UIRuntimeId, () => {
9789
'worklet';
98-
(globalThis as localGlobal).__notifyPass(42);
90+
(globalThis as localGlobal).scheduleOnRN(callbackPass, 42);
9991
});
10092
});
10193
await waitForNotification(PASS_NOTIFICATION);
@@ -107,7 +99,7 @@ describe('scheduleOnRuntimeWithId', () => {
10799
'worklet';
108100
scheduleOnRuntimeWithId(workletRuntime1.runtimeId, () => {
109101
'worklet';
110-
(globalThis as localGlobal).__notifyPass(42);
102+
(globalThis as localGlobal).scheduleOnRN(callbackPass, 42);
111103
});
112104
});
113105
await waitForNotification(PASS_NOTIFICATION);
@@ -120,10 +112,10 @@ describe('scheduleOnRuntimeWithId', () => {
120112
try {
121113
scheduleOnRuntimeWithId(9999, () => {
122114
'worklet';
123-
(globalThis as localGlobal).__notifyPass(42);
115+
scheduleOnRN(callbackPass, 42);
124116
});
125117
} catch (error) {
126-
(globalThis as localGlobal).__notifyFail(error instanceof Error ? error.message : String(error));
118+
scheduleOnRN(callbackFail, error instanceof Error ? error.message : String(error));
127119
}
128120
});
129121

@@ -136,7 +128,7 @@ describe('scheduleOnRuntimeWithId', () => {
136128
'worklet';
137129
scheduleOnRuntimeWithId(UIRuntimeId, () => {
138130
'worklet';
139-
(globalThis as localGlobal).__notifyPass(42);
131+
(globalThis as localGlobal).scheduleOnRN(callbackPass, 42);
140132
});
141133
});
142134
await waitForNotification(PASS_NOTIFICATION);
@@ -147,7 +139,7 @@ describe('scheduleOnRuntimeWithId', () => {
147139
'worklet';
148140
scheduleOnRuntimeWithId(workletRuntime1.runtimeId, () => {
149141
'worklet';
150-
(globalThis as localGlobal).__notifyPass(42);
142+
(globalThis as localGlobal).scheduleOnRN(callbackPass, 42);
151143
});
152144
});
153145
await waitForNotification(PASS_NOTIFICATION);
@@ -158,7 +150,7 @@ describe('scheduleOnRuntimeWithId', () => {
158150
'worklet';
159151
scheduleOnRuntimeWithId(workletRuntime2.runtimeId, () => {
160152
'worklet';
161-
(globalThis as localGlobal).__notifyPass(42);
153+
(globalThis as localGlobal).scheduleOnRN(callbackPass, 42);
162154
});
163155
});
164156
await waitForNotification(PASS_NOTIFICATION);
@@ -170,10 +162,10 @@ describe('scheduleOnRuntimeWithId', () => {
170162
try {
171163
scheduleOnRuntimeWithId(9999, () => {
172164
'worklet';
173-
(globalThis as localGlobal).__notifyPass(42);
165+
(globalThis as localGlobal).scheduleOnRN(callbackPass, 42);
174166
});
175167
} catch (error) {
176-
(globalThis as localGlobal).__notifyFail(error instanceof Error ? error.message : String(error));
168+
scheduleOnRN(callbackFail, error instanceof Error ? error.message : String(error));
177169
}
178170
});
179171

apps/common-app/src/apps/reanimated/examples/RuntimeTests/tests/runtimes/scheduleOnUI.test.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,9 @@ describe('scheduleOnUI', () => {
4242
test('schedules on UI Runtime to UI Runtime', async () => {
4343
scheduleOnUI(() => {
4444
'worklet';
45-
// @ts-expect-error TODO: fix RemoteFunction re-serialization.
46-
const remoteFunction = callbackPass.__remoteFunction as typeof callbackPass;
47-
4845
scheduleOnUI(() => {
4946
'worklet';
50-
scheduleOnRN(remoteFunction, 42);
47+
scheduleOnRN(callbackPass, 42);
5148
});
5249
});
5350

@@ -58,12 +55,9 @@ describe('scheduleOnUI', () => {
5855
test('schedules on Worker Runtime to UI Runtime', async () => {
5956
scheduleOnRuntime(workletRuntime, () => {
6057
'worklet';
61-
// @ts-expect-error TODO: fix RemoteFunction re-serialization.
62-
const remoteFunction = callbackPass.__remoteFunction as typeof callbackPass;
63-
6458
scheduleOnUI(() => {
6559
'worklet';
66-
scheduleOnRN(remoteFunction, 42);
60+
scheduleOnRN(callbackPass, 42);
6761
});
6862
});
6963

packages/react-native-worklets/src/memory/serializable.native.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -173,15 +173,21 @@ export function createSerializable<TValue>(
173173
if (Array.isArray(value)) {
174174
return cloneArray(value, shouldPersistRemote, depth);
175175
}
176-
if (
177-
globalThis._WORKLETS_BUNDLE_MODE_ENABLED &&
178-
isFunction &&
179-
(value as WorkletImport).__bundleData
180-
) {
181-
return cloneImport(value as WorkletImport) as SerializableRef<TValue>;
182-
}
183-
if (isFunction && !isWorkletFunction(value)) {
184-
return cloneRemoteFunction(value);
176+
if (isFunction) {
177+
if (globalThis._WORKLETS_BUNDLE_MODE_ENABLED) {
178+
if ((value as RemoteFunction).__remoteFunction) {
179+
// Remote functions are already serialized.
180+
return (value as RemoteFunction)
181+
.__remoteFunction as SerializableRef<TValue>;
182+
}
183+
if ((value as WorkletImport).__bundleData) {
184+
return cloneImport(value as WorkletImport) as SerializableRef<TValue>;
185+
}
186+
} else {
187+
if (!isWorkletFunction(value)) {
188+
return cloneRemoteFunction(value);
189+
}
190+
}
185191
}
186192
// RN has introduced a new representation of TurboModules as a JS object whose prototype is the host object
187193
// More details: https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp#L182
@@ -732,7 +738,7 @@ function getWorkletCode(value: WorkletFunction) {
732738
return code;
733739
}
734740

735-
type RemoteFunction<TValue> = {
741+
type RemoteFunction<TValue = unknown> = {
736742
__remoteFunction: FlatSerializableRef<TValue>;
737743
};
738744

0 commit comments

Comments
 (0)