Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐛] 🔥 Unable to Create Document - this._firestore.native.documentSet is not a function (it is undefined) #8196

Closed
2 of 10 tasks
Full-lifey opened this issue Dec 18, 2024 · 9 comments
Labels

Comments

@Full-lifey
Copy link

Issue

I have a fresh Expo project and have gone through all development steps listed in the getting started guide.

I'm trying to create a user document as soon as a user account is created via the auth module. However, when I do so I'm getting an error stating:
undefined this._firestore.native.documentSet is not a function (it is undefined)

I'm simply calling the add method on the CollectionReference returned and submitting user data. I'm able to successfully create the user account, but the firestore method to create a doc is failing.

  const signUp = async () => {
    try {
      const userCredential = await auth().createUserWithEmailAndPassword(
        email,
        password,
      );
      await firestore()
        .collection('users')
        .add({
          userID: userCredential.user.uid,
          email: userCredential.user.email,
          name: {
            first: firstName,
            last: lastName,
          },
          createdAt: firestore.FieldValue.serverTimestamp(),
          updatedAt: firestore.FieldValue.serverTimestamp(),
          enabled: true,
        });
    } catch (error) {
      const e = error as FirebaseAuthTypes.NativeFirebaseAuthError;
      console.error(e.code, e.message);
    }
  };

app.json snippet

    "ios": {
      "supportsTablet": true,
      "bundleIdentifier": "dev.myapp",
      "googleServicesFile": "firebase/GoogleService-Info.plist"
    },
    "android": {
      "googleServicesFile": "./firebase/google-services.json",
      "package": "dev.myapp",
      "adaptiveIcon": {
        "foregroundImage": "./assets/images/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      }
    },
    "web": {
      "bundler": "metro",
      "output": "static",
      "favicon": "./assets/images/favicon.png"
    },
    "plugins": [
      "expo-router",
      "@react-native-firebase/app",
      "@react-native-firebase/auth",
      "@react-native-firebase/crashlytics",
      [
        "expo-splash-screen",
        {
          "image": "./assets/images/splash-icon.png",
          "imageWidth": 200,
          "resizeMode": "contain",
          "backgroundColor": "#ffffff"
        }
      ],
      [
        "expo-build-properties",
        {
          "ios": {
            "useFrameworks": "static"
          }
        }
      ]
    ],

Describe your issue here


Project Files

Javascript

Click To Expand

package.json:

{
  "name": "myapp",
  "main": "expo-router/entry",
  "version": "1.0.0",
  "scripts": {
    "start": "expo start",
    "reset-project": "node ./scripts/reset-project.js",
    "android": "DARK_MODE=media expo start --android",
    "ios": "DARK_MODE=media expo start --ios",
    "web": "DARK_MODE=media expo start --web",
    "test": "jest --watchAll",
    "lint": "expo lint",
    "postinstall": "patch-package"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/html-elements": "^0.4.2",
    "@expo/vector-icons": "^14.0.2",
    "@gluestack-ui/alert-dialog": "^0.1.32",
    "@gluestack-ui/button": "^1.0.8",
    "@gluestack-ui/form-control": "^0.1.19",
    "@gluestack-ui/icon": "^0.1.25",
    "@gluestack-ui/input": "^0.1.32",
    "@gluestack-ui/link": "^0.1.23",
    "@gluestack-ui/nativewind-utils": "^1.0.23",
    "@gluestack-ui/overlay": "^0.1.16",
    "@gluestack-ui/textarea": "^0.1.24",
    "@gluestack-ui/toast": "^1.0.8",
    "@legendapp/motion": "^2.4.0",
    "@react-native-firebase/app": "^21.6.1",
    "@react-native-firebase/auth": "^21.6.1",
    "@react-native-firebase/crashlytics": "^21.6.1",
    "@react-native-firebase/firestore": "^21.6.1",
    "@react-navigation/bottom-tabs": "^7.0.0",
    "@react-navigation/native": "^7.0.0",
    "babel-plugin-module-resolver": "^5.0.2",
    "expo": "~52.0.11",
    "expo-blur": "~14.0.1",
    "expo-build-properties": "~0.13.1",
    "expo-constants": "~17.0.3",
    "expo-dev-client": "~5.0.4",
    "expo-font": "~13.0.1",
    "expo-haptics": "~14.0.0",
    "expo-linking": "~7.0.3",
    "expo-router": "~4.0.9",
    "expo-splash-screen": "~0.29.13",
    "expo-status-bar": "~2.0.0",
    "expo-symbols": "~0.2.0",
    "expo-system-ui": "~4.0.4",
    "expo-web-browser": "~14.0.1",
    "nativewind": "^4.0.36",
    "react": "18.3.1",
    "react-dom": "18.3.1",
    "react-native": "0.76.3",
    "react-native-css-interop": "^0.0.36",
    "react-native-gesture-handler": "~2.20.2",
    "react-native-reanimated": "~3.16.1",
    "react-native-safe-area-context": "4.12.0",
    "react-native-screens": "~4.1.0",
    "react-native-svg": "^15.9.0",
    "react-native-web": "~0.19.13",
    "react-native-webview": "13.12.2",
    "tailwindcss": "^3.4.15"
  },
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@types/jest": "^29.5.12",
    "@types/react": "~18.3.12",
    "@types/react-test-renderer": "^18.3.0",
    "eslint": "^8.57.0",
    "eslint-config-expo": "~8.0.1",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.2.1",
    "eslint-plugin-react-native": "^4.1.0",
    "jest": "^29.2.1",
    "jest-expo": "~52.0.2",
    "jscodeshift": "^0.15.2",
    "prettier": "^3.4.1",
    "react-test-renderer": "18.3.1",
    "typescript": "^5.3.3"
  },
  "private": true
}

firebase.json for react-native-firebase v6:

# N/A

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
# N/A

AppDelegate.m:

// N/A


Android

Click To Expand

Have you converted to AndroidX?

  • my application is an AndroidX application?
  • I am using android/gradle.settings jetifier=true for Android compatibility?
  • I am using the NPM package jetifier for react-native compatibility?

android/build.gradle:

// N/A

android/app/build.gradle:

apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"

def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()

/**
 * This is the configuration block to customize your React Native Android app.
 * By default you don't need to apply any configuration, just uncomment the lines you need.
 */
react {
    entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
    reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
    hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
    codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()

    // Use Expo CLI to bundle the app, this ensures the Metro config
    // works correctly with Expo projects.
    cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
    bundleCommand = "export:embed"

    /* Folders */
     //   The root of your project, i.e. where "package.json" lives. Default is '../..'
    // root = file("../../")
    //   The folder where the react-native NPM package is. Default is ../../node_modules/react-native
    // reactNativeDir = file("../../node_modules/react-native")
    //   The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
    // codegenDir = file("../../node_modules/@react-native/codegen")

    /* Variants */
    //   The list of variants to that are debuggable. For those we're going to
    //   skip the bundling of the JS bundle and the assets. By default is just 'debug'.
    //   If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
    // debuggableVariants = ["liteDebug", "prodDebug"]

    /* Bundling */
    //   A list containing the node command and its flags. Default is just 'node'.
    // nodeExecutableAndArgs = ["node"]

    //
    //   The path to the CLI configuration file. Default is empty.
    // bundleConfig = file(../rn-cli.config.js)
    //
    //   The name of the generated asset file containing your JS bundle
    // bundleAssetName = "MyApplication.android.bundle"
    //
    //   The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
    // entryFile = file("../js/MyApplication.android.js")
    //
    //   A list of extra flags to pass to the 'bundle' commands.
    //   See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
    // extraPackagerArgs = []

    /* Hermes Commands */
    //   The hermes compiler command to run. By default it is 'hermesc'
    // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
    //
    //   The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
    // hermesFlags = ["-O", "-output-source-map"]

    /* Autolinking */
    autolinkLibrariesWithApp()
}

/**
 * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
 */
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()

/**
 * The preferred build flavor of JavaScriptCore (JSC)
 *
 * For example, to use the international variant, you can use:
 * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
 *
 * The international variant includes ICU i18n library and necessary data
 * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
 * give correct results when using with locales other than en-US. Note that
 * this variant is about 6MiB larger per architecture than default.
 */
def jscFlavor = 'org.webkit:android-jsc:+'

android {
    ndkVersion rootProject.ext.ndkVersion

    buildToolsVersion rootProject.ext.buildToolsVersion
    compileSdk rootProject.ext.compileSdkVersion

    namespace 'dev.mindfulsoftware.mydream'
    defaultConfig {
        applicationId 'dev.mindfulsoftware.mydream'
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0.0"
    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
        }
    }
    packagingOptions {
        jniLibs {
            useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
        }
    }
    androidResources {
        ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
    }
}

// Apply static values from `gradle.properties` to the `android.packagingOptions`
// Accepts values in comma delimited lists, example:
// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
    // Split option: 'foo,bar' -> ['foo', 'bar']
    def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
    // Trim all elements in place.
    for (i in 0..<options.size()) options[i] = options[i].trim();
    // `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
    options -= ""

    if (options.length > 0) {
        println "android.packagingOptions.$prop += $options ($options.length)"
        // Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
        options.each {
            android.packagingOptions[prop] += it
        }
    }
}

dependencies {
    // The version of react-native is set by the React Native Gradle Plugin
    implementation("com.facebook.react:react-android")

    def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
    def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
    def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";

    if (isGifEnabled) {
        // For animated gif support
        implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}")
    }

    if (isWebpEnabled) {
        // For webp support
        implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}")
        if (isWebpAnimatedEnabled) {
            // Animated webp support
            implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}")
        }
    }

    if (hermesEnabled.toBoolean()) {
        implementation("com.facebook.react:hermes-android")
    } else {
        implementation jscFlavor
    }
}

apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'

android/settings.gradle:

pluginManagement {
    includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile().toString())
}
plugins { id("com.facebook.react.settings") }

extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
  if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
    ex.autolinkLibrariesFromCommand()
  } else {
    def command = [
      'node',
      '--no-warnings',
      '--eval',
      'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
      'react-native-config',
      '--json',
      '--platform',
      'android'
    ].toList()
    ex.autolinkLibrariesFromCommand(command)
  }
}

rootProject.name = 'myDream'

dependencyResolutionManagement {
  versionCatalogs {
    reactAndroidLibs {
      from(files(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../gradle/libs.versions.toml")))
    }
  }
}

apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
useExpoModules()

include ':app'
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile())

MainApplication.java:

// N/A

AndroidManifest.xml:

<!-- N/A -->


Environment

Click To Expand

react-native info output:

 OUTPUT GOES HERE
  • Platform that you're experiencing the issue on:
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • react-native-firebase version you're using that has this issue:
    • 21.6.1
  • Firebase module(s) you're using that has the issue:
    • firestore
  • Are you using TypeScript?
    • Y 5.3.3


@Full-lifey
Copy link
Author

Full-lifey commented Dec 18, 2024

I have since created a simple button to test this issue within my protected routes. This is getting the same error message:

export default function HomeScreen() {
  const logout = async () => {
    try {
      await auth().signOut();
    } catch (e) {
      console.error(e);
    }
  };

  const testCreate = async () => {
    try {
      await firestore().collection('test').add({
        name: 'test',
      });
    } catch (e) {
      console.error(e);
    }
  };

  return (
    <View className="bg-black flex-1 justify-center items-center">
      <Text>Profile</Text>
      <Button onPress={testCreate}>
        <ButtonText>Test Firebase</ButtonText>
      </Button>

      <Button onPress={logout}>
        <ButtonText>Log Out</ButtonText>
      </Button>
    </View>
  );
}

@mikehardy
Copy link
Collaborator

looks like the sort of error I would expect if I added the firestore module in package.json but didn't properly build it in to the app that was actually running on the device under test

@Full-lifey
Copy link
Author

Full-lifey commented Dec 18, 2024

I won't argue with you.

However, how is that supposed to happen? There's no expo plugin included for firestore.... therefore no build process for an expo development build.

I have ran all typical expo build steps by running npx expo prebuild --clean post-installation of firestore and that has not worked.

@mikehardy
Copy link
Collaborator

mikehardy commented Dec 18, 2024

firestore doesn't need a plugin, if you've added it in package.json and done the prebuild magic that should work.

If you just make a vanilla react-native project with npx react-native init SimpleReproducer then add app and firestore module, drop your google-services.json into android/app (I think that's where it goes...) and try to make a similar button that accesses firestore then do a yarn android I bet it works

(not saying "hey avoid Expo", just saying "let's localize the problem to something about the Expo build by proving it can work somehow / some way)

@Full-lifey
Copy link
Author

@mikehardy I agree that it should work but you also stated there's a potential build step causing this issue. I've looked over the docs 5x and I don't see anything missed here.

Also, have you seen the RN-CLI react-native-firebase getting started steps? It's not a trivial task to setup just to make sure it's possible. I'm also not sure that would help in any way other than "proving that it can work."

Any other more targeted ideas? Especially considering even react-native no longer recommends using their CLI version??

@mikehardy
Copy link
Collaborator

No

@Full-lifey
Copy link
Author

Alright so there are some build steps that expo performs depending on how each platform is ran.

The needed build steps for this library to work will not work if running npx expo start and then hitting the a or i keys to build and run their respective emulators/simulators.

After a development build is specified/created in order for @react-native-firebase/firestore to run properly a manual build must be ran. This is either npx expo run:android or npx expo run:ios.

Apologies for the confusion, it seems expo does not fully run a development build when running npx expo start and running a simulator from there.

@mikehardy
Copy link
Collaborator

Interesting - if there is any spot in the docs where this info would be useful there is an edit link at the top right of every page on rnfirebase.io and the web UI on github for docs PRs only takes a couple minutes. I'd be happy to merge any guidance that gets people through the process in a painless way - acquiring this knowledge sounds like unneeded suffering to me, but it's pretty subtle

@Full-lifey
Copy link
Author

Thanks Mike! I will definitely submit something when I get back from vacation. I appreciate your help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants