Skip to content

Using the spread operator on Native modules breaks compatibility layer for bridgeless mode #43221

Closed
@gabrieldonadel

Description

@gabrieldonadel

Description

While investigating why the compatibility layer was not working for react-native-netinfo when bridgeless mode was tuned on, I noticed that they were using the spread operator (...) directly on the object returned from React Native's NativeModules e.g.

import {NativeModules} from 'react-native';

const RNCNetInfo: NetInfoNativeModule = NativeModules.RNCNetInfo;

export default {
  ...RNCNetInfo,
  get eventEmitter(): NativeEventEmitter {
     ...
  }
}

This is not a problem when bridgeless mode is tuned off, but as soon as bridgeless mode is tuned on, trying to access any of the module functions will result in an unhandled promise rejection

image

Upon some investigation, I noticed that this same error also happens if we try to use the spread operator over a turbo module (with bridgeless mode on and off). I believe that's the case because the module object is a host object and doesn't quite support the ... syntax yet.

To fix this specific case I just used Object.assign instead (check react-native-netinfo/react-native-netinfo#717 for more details), but thinking from a compatibility perspective we should try to address this so that old/unmaintained libraries that use this pattern can benefit from the compatibility layer

Steps to reproduce

With bridgeless mode ON:

  1. Create a NativeModule
  2. Access the module on the JS side
  3. Export the module using the spread operator

Or just clone https://github.com/gabrieldonadel/rn-spread-operator-bug and run the app, it already includes all the use cases

React Native Version

0.74.0-rc.1

Affected Platforms

Runtime - Android, Runtime - iOS

Output of npx react-native info

System:
  OS: macOS 14.0
  CPU: (12) arm64 Apple M2 Max
  Memory: 91.98 MB / 32.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.18.2
    path: ~/.volta/tools/image/node/18.18.2/bin/node
  Yarn:
    version: 3.6.4
    path: ~/.volta/tools/image/yarn/1.22.21/bin/yarn
  npm:
    version: 9.8.1
    path: ~/.volta/tools/image/node/18.18.2/bin/npm
  Watchman: Not Found
Managers:
  CocoaPods:
    version: 1.14.3
    path: /Users/gabriel/.rbenv/shims/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.2
      - iOS 17.2
      - macOS 14.2
      - tvOS 17.2
      - visionOS 1.0
      - watchOS 10.2
  Android SDK:
    API Levels:
      - "22"
      - "26"
      - "30"
      - "31"
      - "33"
      - "34"
    Build Tools:
      - 26.0.3
      - 30.0.3
      - 31.0.0
      - 33.0.0
      - 33.0.1
      - 33.0.2
      - 34.0.0
    System Images:
      - android-22 | ARM 64 v8a
      - android-26 | Google APIs Intel x86_64 Atom
      - android-30 | ARM 64 v8a
      - android-33 | Google APIs ARM 64 v8a
      - android-33 | Google Play ARM 64 v8a
      - android-34 | Google Play ARM 64 v8a
    Android NDK: Not Found
IDEs:
  Android Studio: 2023.1 AI-231.9392.1.2311.11076708
  Xcode:
    version: 15.2/15C500b
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.8
    path: /usr/bin/javac
  Ruby:
    version: 2.7.8
    path: /Users/gabriel/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.74.0-rc.1
    wanted: 0.74.0-rc.1
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: true
  newArchEnabled: true

Stacktrace or Logs

TypeError: _index.default.helloWorld is not a function (it is undefined), js engine: hermes

Reproducer

https://github.com/gabrieldonadel/rn-spread-operator-bug

Screenshots and Videos

bridgeless on bridgeless off
Screen.Recording.2024-02-27.at.21.45.57.mov
Screen.Recording.2024-02-27.at.21.44.31.mov
Screen.Recording.2024-02-27.at.21.43.08.mov
Screen.Recording.2024-02-27.at.21.41.17.mov

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions