Skip to content

Don't throw when the module is imported outside the native runtime - #478

Draft
niamh-coleman wants to merge 1 commit into
mainfrom
niamh/expo-server-export-safe-import
Draft

niamh-coleman wants to merge 1 commit into
mainfrom
niamh/expo-server-export-safe-import

Conversation

@niamh-coleman

Copy link
Copy Markdown
Contributor

Why?

Importing @intercom/intercom-react-native in an Expo Router route or layout file breaks the iOS Release build of a default Expo SDK 58 app. The default template sets web.output: "server", so the "Bundle React Native code and images" build step also exports server code, and that export evaluates every route file in Node. There the import throws:

TypeError: Cannot read properties of undefined (reading 'UNREAD_COUNT_CHANGE_NOTIFICATION')

The module read native module properties at load time, and outside the native runtime those modules are undefined.

How?

Two reads happened at import, and both now happen safely:

  • IntercomEvents read its event names from IntercomEventEmitter. They now use optional chaining, so in the app they are the same native constants, and outside it they are undefined.
  • setNeedsStatusBarAppearanceUpdate read IntercomModule.setNeedsStatusBarAppearanceUpdate while building the Platform.select object, which evaluates every branch. It now calls the method when invoked, like the other methods do.

A new test imports the module without IntercomEventEmitter or IntercomModule in NativeModules. It also checks that the event names and the status bar method still come from the native modules when they exist.

Notes for reviewers
  • Android uses the same JS. Its IntercomEventEmitter only exports the unread count and JWT constants, so IntercomWindowDidHide and IntercomWindowDidShow were already undefined there, and still are.
  • The new test fails on main with the TypeError above and passes with this change. Locally it ran against newer jest, React Native and TypeScript than the pinned ones, and ESLint didn't run, so CI is the check against the pinned versions.
  • Not yet built end to end in an Expo app from this branch.

🤖 Generated with Claude Code

Importing the package read native module properties at load time:
IntercomEvents read its event names from IntercomEventEmitter, and
setNeedsStatusBarAppearanceUpdate read its method from IntercomModule
while building the Platform.select object. Outside the native runtime
those modules are undefined, so the import threw. Expo Router's server
export evaluates every route file in Node, which broke the iOS Release
build of a default Expo app that imports the package in a route or
layout. Both reads now happen safely, and the values in the app are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant