How to use Firebase modular (v9) #7597
-
The contributors have recently done a great job by providing also modular syntax which 1-to-1 match official Firebase import auth from '@react-native-auth/auth'
auth.onAuthStateChanged(...) it is also possible to write a modular code like this import { onAuthStateChanged, getAuth } from '@react-native-auth/auth' // No TS support yet
onAuthStateChanged(getAuth()) This is great news as unifies code for web and native again. 🎉 Note that currently there are no Typescript definitions for exported functions. With this discussion I would like to brainstorm how to use modular syntax in hybrid Expo app. That compiles both to iOS and Android as well to Web. Possible solution is to use extension native.ts and web.ts to choose the correct module to import. // ./src/firebase/modular/app.ts
export { initializeApp } from '@react-native-firebase/app/lib/modular/app' // ./src/firebase/modular/app.native.ts
export { initializeApp } from 'firebase/app' // ./src/firebase/modular/auth.ts
export { getAuth, onAuthStateChanged, signInAnonymously } from 'firebase/auth' // ./src/firebase/modular/auth.native.ts
export { getAuth, onAuthStateChanged, signInAnonymously } from '@react-native-firebase/auth' And then use is as follows. import {
getAuth,
onAuthStateChanged,
signInAnonymously,
} from '../firebase/modular/auth'
onAuthStateChanged(getAuth(), (user) => {
if (!user) {
signInAnonymously(getAuth())
}
}) By using .native.ts instead of .web.ts one even get a correct Typescript definitions in the rest of the project. IssuesNeed to re-export (small)All the needed functions has to be re-exported. Boiler plate needed. 3rd party modules (big)Any 3rd party modules does not know about our rewrites and will import either Native or Web firebase. Either breaking web or native. Eample of such module is react-firebase-hooks which internally imports from 'firebase/auth|firestore' and therefore not working on native. SolutionsDo a module replacement with metro. Any ideas how? Use browser field of package.json to replace native module while running on web. This only works when replacing native module to web. Not the opposite way as we need for react-firebase-hooks. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 9 replies
-
I've been able to get this working by editing metro.config.js by adding the following custom resolver in an NX monorepo project that has both web and expo apps that are sharing firebase code. Below is a slightly adapted version of what I'm using (removed the NX specific parts):
This has worked well so far, the JS SDK modules are swapped out for their native counterparts at build time, whilst during development I get full TypeScript support as it is using the JS SDK types. I can also use third-party libraries that reference the JS SDK, as their imports are also swapped at build time. The only slight issue I've encountered so far is with using the emulators, where I have had to create a file with a .native extension in order to bootstrap them properly. Also, there is a difference with initializeApp, the native implementation returns a promise, which the JS SDK does not, but again, I can handle this in the .native version of the initialisation. Hopefully the native api gets to parity soon. @mikehardy - sorry for the tag, I saw you have used shims for a shared web/native project in the past, so this approach may interest you. |
Beta Was this translation helpful? Give feedback.
-
Thank you @alexstanbury for a great reply. nodeModulesPaths is empty array if one does not work in nx. I replaced it with path to node_modules. Below is the full metro.config.js file. I think we can close this discussion as resolved. // Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('expo/metro-config')
const path = require('path')
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname)
const node_modules = path.resolve(__dirname, 'node_modules')
config.resolver.resolveRequest = (context, moduleName, platform) => {
if (moduleName.startsWith('firebase/')) {
const filePath = `${node_modules}/@react-native-${moduleName}/lib/index.js`
console.log(
'***** metro.config.js custom resolving',
moduleName,
'to',
filePath,
'*****',
)
return {
filePath,
type: 'sourceFile',
}
}
// Ensure you call the default resolver.
return context.resolveRequest(context, moduleName, platform)
}
module.exports = config |
Beta Was this translation helpful? Give feedback.
Sorry, I omitted that part because it is nx specific. You would use it like so: