Skip to content

fix: use TurboModuleRegistry as primary lookup to support RN 0.79+ bridgeless mode#657

Merged
gre merged 1 commit into
masterfrom
fix/bridgeless-turbomodule-detection
May 27, 2026
Merged

fix: use TurboModuleRegistry as primary lookup to support RN 0.79+ bridgeless mode#657
gre merged 1 commit into
masterfrom
fix/bridgeless-turbomodule-detection

Conversation

@gre
Copy link
Copy Markdown
Owner

@gre gre commented May 27, 2026

Summary

  • Removes the global.__turboModuleProxy heuristic
  • Uses TurboModuleRegistry.get() as the primary resolver (the correct stable API for both old and new arch)
  • Keeps NativeModules.RNViewShot as the legacy fallback

Background

The previous code used global.__turboModuleProxy != null as a gate to decide between TurboModuleRegistry.getEnforcing() and NativeModules.RNViewShot. In RN 0.79+ bridgeless mode, __turboModuleProxy is null, so it fell through to NativeModules.RNViewShot — which is also absent in bridgeless (0 keys). This caused:

react-native-view-shot: NativeModules.RNViewShot is undefined. Make sure the library is linked on the native side.

TurboModuleRegistry.get() is the correct API for module resolution in both old and new arch, including most bridgeless setups.

Scope / Known Limitations

This PR fixes the JS-side module lookup heuristic. However, in fully bridgeless runtimes (RN 0.81 + Expo SDK 54, where global.RN$UnifiedNativeModuleProxy === true), runtime evidence shows TurboModuleRegistry.get('RNViewShot') itself returns null. This appears to be because the iOS native implementation depends on self.bridge.uiManager addUIBlock: — a bridge-only API — which prevents the TurboModule from initializing without a bridge. Full bridgeless support would require migrating the iOS view-lookup path away from RCTUIManager, which is tracked in #653 as a separate larger effort.

Related: #653

Test plan

  • Code Quality (ESLint + TypeScript strict) passes
  • Web Playwright E2E passes
  • Old arch (bridge mode) iOS: captureRef still works
  • New arch (non-bridgeless) iOS: captureRef still works

🤖 Generated with Claude Code

…idgeless mode

In bridgeless mode (RN 0.79+, Expo SDK 54+), `__turboModuleProxy` is not
installed as a global, so the previous heuristic fell through to
`NativeModules.RNViewShot` which is also unavailable (zero-key object in
bridgeless mode). Replace both paths with `TurboModuleRegistry.get()` as
the primary resolver and `NativeModules.RNViewShot` as a fallback for old
architecture compatibility. Fixes #653.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 27, 2026 14:46
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes the native module resolution path for RNViewShot so JS attempts React Native’s TurboModuleRegistry lookup before falling back to legacy NativeModules.

Changes:

  • Removes the global.__turboModuleProxy heuristic.
  • Uses TurboModuleRegistry.get("RNViewShot") as the primary resolver.
  • Keeps NativeModules.RNViewShot as the legacy fallback.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/specs/NativeRNViewShot.ts
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@gre gre merged commit e7a0bd6 into master May 27, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants