expo / expo-three

Utilities for using THREE.js on Expo
MIT License
738 stars 89 forks source link

Can't find variable: HTMLElement #288

Closed obasille closed 1 year ago

obasille commented 1 year ago

I've stumbled into a strange issue, using Three in a Expo project causes HTMLElement to become undefined.

I don't use of HTMLElement since I'm targeting mobile only, but some packages that I'm using do and as soon I'm starting to use Three I'm getting this error:

ReferenceError: Can't find variable: HTMLElement

For example some packages might run this code ref instanceof HTMLElement which normally works fine in a Expo project, until you start using Three.

For example this simple app will immediately crash:

import { StatusBar } from 'expo-status-bar';
import { useEffect } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { THREE } from 'expo-three';

export default function App() {
  useEffect(() => {
    new THREE.Scene(); // Comment this line, remove the import and it works!
    console.log(HTMLElement); // Throws "ReferenceError: Can't find variable: HTMLElement"
  });
  return (
    <View style={styles.container}>
      <Text>Open up App.tsx to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  );
}

package.json

  "dependencies": {
    "expo": "~47.0.13",
    "expo-gl": "^12.0.1",
    "expo-status-bar": "~1.4.2",
    "expo-three": "^7.0.0",
    "react": "18.1.0",
    "react-dom": "18.1.0",
    "react-native": "0.70.5",
    "react-native-web": "~0.18.9",
    "three": "^0.145.0"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@types/react": "~18.0.14",
    "@types/react-native": "~0.70.6",
    "typescript": "^4.6.3"
  },

Any help would be greatly appreciated!

obasille commented 1 year ago

For anyone who stumble on this problem, I found the root cause:

expo-three is importing @expo/browser-polyfill which changes the user agent to "chrome" => navigator.userAgent = 'chrome'.

Some libraries that target both the web and React Native check the user agent before using HTMLElement. In a normal React Native context the user agent is undefined and those libraries don't use any web specific classes. But once the user agent is changed to "chrome", the library will think it's running in a web environment (and in my case it will use HTMLElement).

Note : I was wrong to think that HTMLElement should exist in React Native.