Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions apps/bare-expo/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3098,6 +3098,29 @@ PODS:
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17)
- UMAppLoader (6.0.7)
- WorkletsTester (0.0.1):
- ExpoModulesCore
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- Yoga (0.0.0)
- ZXingObjC/Core (3.6.9)
- ZXingObjC/OneD (3.6.9):
Expand Down Expand Up @@ -3295,6 +3318,7 @@ DEPENDENCIES:
- RNSVG (from `../../../node_modules/react-native-svg`)
- RNWorklets (from `../../../node_modules/react-native-worklets`)
- UMAppLoader (from `../../../packages/unimodules-app-loader/ios`)
- WorkletsTester (from `../modules/worklets-tester/ios`)
- Yoga (from `../../../node_modules/react-native/ReactCommon/yoga`)

SPEC REPOS:
Expand Down Expand Up @@ -3741,6 +3765,9 @@ EXTERNAL SOURCES:
UMAppLoader:
inhibit_warnings: false
:path: "../../../packages/unimodules-app-loader/ios"
WorkletsTester:
inhibit_warnings: false
:path: "../modules/worklets-tester/ios"
Yoga:
:path: "../../../node_modules/react-native/ReactCommon/yoga"

Expand Down Expand Up @@ -3930,6 +3957,7 @@ SPEC CHECKSUMS:
SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
UMAppLoader: b649e542381c8abe788ffb13893e632d598910a5
WorkletsTester: f76956000cdf163c71f8eb20fe09f1bfa21acbaf
Yoga: 35d573dff66536d48493acb65a519482f8219fe8
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"platforms": ["android"],
"platforms": ["apple", "android"],
"apple": {
"modules": ["WorkletsTesterModule"]
},
"android": {
"modules": ["expo.modules.worklets.tester.WorkletsTesterModule"]
}
Expand Down
25 changes: 25 additions & 0 deletions apps/bare-expo/modules/worklets-tester/ios/WorkletsTester.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'json'

package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))

Pod::Spec.new do |s|
s.name = 'WorkletsTester'
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.license = package['license']
s.author = package['author']
s.homepage = package['homepage']
s.platforms = {
:ios => '15.1',
}
s.swift_version = '5.9'
s.source = { git: 'https://github.com/expo/expo.git' }
s.static_framework = true

s.source_files = '**/*.{h,cpp,m,mm,swift}'

s.dependency 'ExpoModulesCore'

install_modules_dependencies(s)
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import ExpoModulesCore

public final class WorkletsTesterModule: Module {
public func definition() -> ModuleDefinition {
Name("WorkletsTesterModule")

Function("executeWorklet") { (worklet: Worklet) in
guard let uiRuntime = try appContext?.uiRuntime else {
throw Exceptions.RuntimeLost()
}
worklet.execute(on: uiRuntime)
}

Function("scheduleWorklet") { (worklet: Worklet) in
guard let uiRuntime = try appContext?.uiRuntime else {
throw Exceptions.RuntimeLost()
}
worklet.schedule(on: uiRuntime)
}
}
}
18 changes: 18 additions & 0 deletions apps/bare-expo/modules/worklets-tester/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "worklets-tester",
"version": "0.0.1",
"private": true,
"description": "A local module for testing worklets integration",
"main": "src/index.ts",
"types": "src/index.ts",
"homepage": "https://expo.dev",
"author": "650 Industries, Inc.",
"license": "MIT",
"dependencies": {},
"devDependencies": {},
"peerDependencies": {
"expo": "*",
"react": "*",
"react-native": "*"
}
}
4 changes: 4 additions & 0 deletions apps/bare-expo/modules/worklets-tester/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ export const WorkletsTester = {
executeWorklet: (worklet: () => void) => {
WorkletsTesterModule?.executeWorklet?.(createSerializable(worklet));
},

isAvailable() {
return WorkletsTesterModule != null;
},
};
7 changes: 2 additions & 5 deletions apps/bare-expo/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
"extends": "expo/tsconfig.base",
"compilerOptions": {
"baseUrl": ".",
"lib": [
"dom",
"esnext"
],
"lib": ["dom", "esnext"],
"paths": {
"ThemeProvider": ["../common/ThemeProvider"],
"benchmarking": ["./modules/benchmarking"],
"worklets-tester": ["./modules/worklets-tester/src/index"]
"worklets-tester": ["./modules/worklets-tester"]
}
}
}
12 changes: 12 additions & 0 deletions apps/native-component-list/src/screens/Worklets/WorkletsScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { WorkletsTester } from 'worklets-tester';

import { optionalRequire } from '../../navigation/routeBuilder';
import ComponentListScreen, { apiScreensToListElements } from '../ComponentListScreen';

Expand All @@ -11,6 +13,16 @@ export const WorkletsScreens = [
},
];

if (WorkletsTester.isAvailable()) {
WorkletsScreens.push({
name: 'Worklets Tester Screen',
route: 'worklets/tester-screen',
getComponent() {
return optionalRequire(() => require('./WorkletsTesterScreen'));
},
});
}

export default function WorkletsScreen() {
const apis = apiScreensToListElements(WorkletsScreens);
return <ComponentListScreen apis={apis} sort={false} />;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import { installOnUIRuntime } from 'expo';
import React, { useState } from 'react';
import { View, StyleSheet, Text, TouchableOpacity, ScrollView } from 'react-native';
import { runOnJS } from 'react-native-worklets';
import 'react-native-reanimated';
import { WorkletsTester } from 'worklets-tester';

installOnUIRuntime();

type TestResult = {
name: string;
success: boolean;
message: string;
};

export default function WorkletsTesterScreen() {
const [results, setResults] = useState<TestResult[]>([]);

const addResult = (result: TestResult) => {
setResults((prev) => [result, ...prev]);
};

const clearResults = () => {
setResults([]);
};

const testExecuteWorklet = () => {
try {
WorkletsTester.executeWorklet(() => {
'worklet';
runOnJS(addResult)({
name: 'executeWorklet',
success: true,
message: 'Worklet executed synchronously on UI runtime',
});
});
} catch (error) {
addResult({
name: 'executeWorklet',
success: false,
message: `Error: ${error instanceof Error ? error.message : String(error)}`,
});
}
};

const testScheduleWorklet = () => {
try {
WorkletsTester.scheduleWorklet(() => {
'worklet';
runOnJS(addResult)({
name: 'scheduleWorklet',
success: true,
message: 'Worklet scheduled and executed on UI runtime',
});
});
} catch (error) {
addResult({
name: 'scheduleWorklet',
success: false,
message: `Error: ${error instanceof Error ? error.message : String(error)}`,
});
}
};

return (
<ScrollView style={styles.container}>
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.button} onPress={testExecuteWorklet}>
<Text style={styles.buttonText}>Test executeWorklet</Text>
</TouchableOpacity>

<TouchableOpacity style={styles.button} onPress={testScheduleWorklet}>
<Text style={styles.buttonText}>Test scheduleWorklet</Text>
</TouchableOpacity>

<TouchableOpacity style={[styles.button, styles.clearButton]} onPress={clearResults}>
<Text style={styles.buttonText}>Clear Results</Text>
</TouchableOpacity>
</View>

<View style={styles.resultsSection}>
<Text style={styles.resultsTitle}>Results:</Text>
{results.length === 0 ? (
<Text style={styles.noResults}>No tests run yet</Text>
) : (
results.map((result, index) => (
<View
key={index}
style={[styles.resultRow, result.success ? styles.successRow : styles.errorRow]}>
<Text style={styles.resultName}>{result.name}</Text>
<Text style={styles.resultMessage}>{result.message}</Text>
</View>
))
)}
</View>
</ScrollView>
);
}

const styles = StyleSheet.create({
container: {
padding: 16,
backgroundColor: '#f5f5f5',
},
title: {
fontSize: 20,
fontWeight: '600',
color: '#333',
},
subtitle: {
fontSize: 14,
color: '#666',
marginTop: 4,
},
buttonContainer: {
marginBottom: 20,
},
button: {
backgroundColor: '#007AFF',
paddingVertical: 12,
paddingHorizontal: 16,
borderRadius: 8,
marginBottom: 8,
alignItems: 'center',
},
clearButton: {
backgroundColor: '#666',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: '500',
},
resultsSection: {
flex: 1,
},
resultsTitle: {
fontSize: 18,
fontWeight: '600',
color: '#333',
marginBottom: 12,
},
noResults: {
fontSize: 14,
color: '#999',
fontStyle: 'italic',
},
resultRow: {
padding: 12,
borderRadius: 8,
marginBottom: 8,
},
successRow: {
backgroundColor: '#d4edda',
},
errorRow: {
backgroundColor: '#f8d7da',
},
resultName: {
fontSize: 14,
fontWeight: '600',
color: '#333',
marginBottom: 4,
},
resultMessage: {
fontSize: 12,
color: '#666',
},
});
3 changes: 2 additions & 1 deletion apps/native-component-list/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"paths": {
"@expo/vector-icons": ["react-native-vector-icons"],
"ThemeProvider": ["../common/ThemeProvider"],
"benchmarking": ["../bare-expo/modules/benchmarking"]
"benchmarking": ["../bare-expo/modules/benchmarking"],
"worklets-tester": ["../bare-expo/modules/worklets-tester"]
},
"types": ["jest"],
"typeRoots": ["./ts-declarations", "./node_modules/@types", "../../node_modules/@types"],
Expand Down
1 change: 1 addition & 0 deletions docs/constants/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ export const general = [
makePage('router/web/middleware.mdx'),
makePage('router/web/server-headers.mdx'),
makePage('router/web/static-rendering.mdx'),
makePage('router/web/server-rendering.mdx'),
makePage('router/web/async-routes.mdx'),
]),
makeGroup('Reference', [
Expand Down
Loading
Loading