signalforge
Version:
Fine-grained reactive state management with automatic dependency tracking - Ultra-optimized, zero dependencies
318 lines (278 loc) • 8.62 kB
text/typescript
/**
* React Native Setup and Installation Script
*
* This file provides setup instructions and installation helper for
* integrating SignalForge's native JSI module into a React Native project.
*/
/**
* Installation Instructions
* =========================
*
* For React Native 0.68+ with New Architecture:
*
* 1. Install SignalForge:
* ```bash
* npm install signalforge
* # or
* yarn add signalforge
* ```
*
* 2. Enable New Architecture (if not already enabled):
*
* Android (android/gradle.properties):
* ```properties
* newArchEnabled=true
* ```
*
* iOS (ios/Podfile):
* ```ruby
* ENV['RCT_NEW_ARCH_ENABLED'] = '1'
* ```
*
* 3. Link native module:
*
* Android: Already auto-linked via Gradle
* iOS: Run pod install
* ```bash
* cd ios && pod install && cd ..
* ```
*
* 4. Rebuild the app:
* ```bash
* # Android
* cd android && ./gradlew clean && cd ..
* npx react-native run-android
*
* # iOS
* cd ios && xcodebuild clean && cd ..
* npx react-native run-ios
* ```
*
* For React Native < 0.68 (Old Architecture):
*
* The JSI bindings will still work, but you'll need to manually install
* the native module using the JSI installer function.
*
* See: examples/react-native-legacy-setup.ts
*/
/**
* Runtime Installation (Old Architecture)
*
* For React Native projects not using the new architecture,
* you can manually install the JSI bindings at runtime.
*/
// Type declaration for JSI installer (provided by native module)
declare global {
var installSignalForgeJSI: (() => boolean) | undefined;
}
type NativeInstaller = (() => boolean) | undefined;
/**
* Resolve the best available native installer.
*
* Priority order:
* 1) A global injected installer (old architecture/manual install)
* 2) The native module exported via React Native (new architecture default)
*/
function getNativeInstaller(): NativeInstaller {
if (typeof global.installSignalForgeJSI === 'function') {
return global.installSignalForgeJSI;
}
try {
// Lazy-require so web/Node builds do not attempt to load react-native
const { NativeModules } = require('react-native');
const installer = NativeModules?.SignalForge?.install;
if (typeof installer === 'function') {
return installer;
}
} catch (error) {
// Non-react-native environments will land here (expected)
}
return undefined;
}
/**
* Install JSI bindings at runtime
*
* Call this once during app initialization, before using any
* signal operations. This installs the native JSI functions
* into the global scope.
*
* Returns true if installation succeeded, false otherwise.
*
* Example:
* ```typescript
* import { installJSIBindings } from 'signalforge/native/setup';
*
* // In your App.tsx or index.js:
* if (installJSIBindings()) {
* console.log('SignalForge native JSI installed!');
* } else {
* console.warn('SignalForge running in JS fallback mode');
* }
* ```
*/
export function installJSIBindings(): boolean {
// Check if already installed
if (typeof global.__signalForgeCreateSignal === 'function') {
return true;
}
// Check if installer function is available
const installer = getNativeInstaller();
if (typeof installer === 'function') {
try {
const result = installer();
if (result) {
console.log('[SignalForge] JSI bindings installed successfully');
return true;
}
} catch (error) {
console.error('[SignalForge] Failed to install JSI bindings:', error);
}
}
// Check if JSI module was loaded but not installed
if (typeof global.__signalForgeCreateSignal === 'function') {
console.log('[SignalForge] JSI bindings already available');
return true;
}
console.warn('[SignalForge] Native module not available, using JavaScript fallback');
return false;
}
/**
* Check if native JSI bindings are available
*
* Useful for conditional logic or diagnostics.
*/
export function isNativeAvailable(): boolean {
return typeof global.__signalForgeCreateSignal === 'function';
}
/**
* Get information about the current runtime
*/
export function getRuntimeInfo() {
return {
nativeAvailable: isNativeAvailable(),
engine: getJavaScriptEngine(),
platform: getPlatform(),
architecture: getArchitecture(),
};
}
/**
* Detect which JavaScript engine is running
*/
function getJavaScriptEngine(): 'Hermes' | 'JSC' | 'V8' | 'Unknown' {
// Check for Hermes
if (typeof (global as any).HermesInternal !== 'undefined') {
return 'Hermes';
}
// Check for V8 (Chrome DevTools, Android)
if (typeof (global as any).__v8 !== 'undefined') {
return 'V8';
}
// Check for JSC (iOS default)
if (typeof (global as any).nativePerformanceNow !== 'undefined') {
return 'JSC';
}
return 'Unknown';
}
/**
* Detect the platform
*/
function getPlatform(): 'iOS' | 'Android' | 'Web' | 'Unknown' {
if (typeof navigator !== 'undefined') {
const userAgent = navigator.userAgent || '';
if (/android/i.test(userAgent)) return 'Android';
if (/iPad|iPhone|iPod/.test(userAgent)) return 'iOS';
if (typeof window !== 'undefined') return 'Web';
}
// In React Native, Platform module would be better
// but we avoid the import to keep this file standalone
return 'Unknown';
}
/**
* Detect architecture (for debugging)
*/
function getArchitecture(): string {
// This is approximate - actual arch detection needs native module
if (typeof (global as any).__ARCH__ === 'string') {
return (global as any).__ARCH__;
}
return 'Unknown';
}
/**
* Performance testing utility
*
* Run a benchmark comparing native vs JS performance.
* Only available in development builds.
*/
export function runPerformanceBenchmark(): {
nativeAvailable: boolean;
operations: number;
timeMs: number;
opsPerSecond: number;
} | null {
if (!isNativeAvailable()) {
console.warn('[SignalForge] Native module not available, cannot run benchmark');
return null;
}
const operations = 100000;
const signalIds: string[] = [];
console.log(`[SignalForge] Running benchmark (${operations} operations)...`);
const startTime = Date.now();
// Create signals
for (let i = 0; i < 100; i++) {
const id = global.__signalForgeCreateSignal!(i);
signalIds.push(id);
}
// Read/write operations
for (let i = 0; i < operations; i++) {
const idx = i % signalIds.length;
const signalId = signalIds[idx];
// Read
global.__signalForgeGetSignal!(signalId);
// Write
global.__signalForgeSetSignal!(signalId, i);
// Check version
global.__signalForgeGetVersion!(signalId);
}
// Cleanup
for (const id of signalIds) {
global.__signalForgeDeleteSignal!(id);
}
const endTime = Date.now();
const timeMs = endTime - startTime;
const opsPerSecond = Math.round((operations / timeMs) * 1000);
const result = {
nativeAvailable: true,
operations,
timeMs,
opsPerSecond,
};
console.log(`[SignalForge] Benchmark complete:`, result);
return result;
}
/**
* Diagnostic utility - print all available information
*/
export function printDiagnostics(): void {
console.log('=== SignalForge Native Diagnostics ===');
const runtimeInfo = getRuntimeInfo();
console.log('Runtime Info:', JSON.stringify(runtimeInfo, null, 2));
console.log('\nGlobal JSI Functions:');
console.log(' __signalForgeCreateSignal:', typeof global.__signalForgeCreateSignal);
console.log(' __signalForgeGetSignal:', typeof global.__signalForgeGetSignal);
console.log(' __signalForgeSetSignal:', typeof global.__signalForgeSetSignal);
console.log(' __signalForgeHasSignal:', typeof global.__signalForgeHasSignal);
console.log(' __signalForgeDeleteSignal:', typeof global.__signalForgeDeleteSignal);
console.log(' __signalForgeGetVersion:', typeof global.__signalForgeGetVersion);
console.log(' __signalForgeBatchUpdate:', typeof global.__signalForgeBatchUpdate);
console.log('\n=====================================');
}
/**
* Default export for convenience
*/
export default {
installJSIBindings,
isNativeAvailable,
getRuntimeInfo,
runPerformanceBenchmark,
printDiagnostics,
};