Remix集成Firebase认证报错:Cannot read properties of undefined (reading '_getRecaptchaConfig')
解决Remix集成Firebase注册时的"_getRecaptchaConfig"未定义错误
错误原因
你遇到的Cannot read properties of undefined (reading '_getRecaptchaConfig')错误,是因为在Remix的服务端action函数中使用了Firebase客户端SDK的认证方法。Firebase客户端SDK的createUserWithEmailAndPassword依赖浏览器环境的reCAPTCHA配置,而服务端运行时没有这个环境,导致相关属性未定义。
解决方案
方案一:使用Firebase Admin SDK在服务端处理注册
Firebase Admin SDK专门用于服务端操作,不依赖浏览器环境,适合在Remix的action中使用:
- 安装Firebase Admin SDK
npm install firebase-admin
- 配置Admin SDK(新建
app/utils/firebase-admin.ts)
import admin from 'firebase-admin'; if (!admin.apps.length) { admin.initializeApp({ credential: admin.credential.cert({ projectId: process.env.FIREBASE_PROJECT_ID, clientEmail: process.env.FIREBASE_CLIENT_EMAIL, privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'), }), }); } export const adminAuth = admin.auth();
- 修改Remix的action函数
import { adminAuth } from '~/utils/firebase-admin'; export async function action({ request }: ActionArgs) { const formData = await request.formData(); const formValues = Object.fromEntries(formData); invariant( formValues?.email && typeof formValues?.email === 'string', "email为空或不是字符串类型", ); invariant( formValues?.password && typeof formValues?.password === 'string', "密码为空或不是字符串类型", ); try { // 使用Admin SDK创建用户 const userRecord = await adminAuth.createUser({ email: formValues.email, password: formValues.password, }); console.log('创建用户成功:', userRecord.uid); } catch (error) { console.log('注册错误:', error); logger.error(getErrorMessage(error)); } return null; }
方案二:将注册逻辑移到客户端执行
把注册操作放在浏览器端执行,避免服务端环境不兼容的问题:
修改表单组件,在客户端处理提交逻辑:
import { useState } from 'react'; import { Form, Link, useNavigation } from '@remix-run/react'; import { auth } from '~/utils/firebase'; import { createUserWithEmailAndPassword } from 'firebase/auth'; export default function SignupForm() { const navigation = useNavigation(); const [error, setError] = useState<string | null>(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const email = formData.get('email') as string; const password = formData.get('password') as string; try { await createUserWithEmailAndPassword(auth, email, password); // 注册成功后的跳转或其他逻辑 } catch (err) { setError((err as Error).message); console.log('注册错误:', err); } }; return ( <Form onSubmit={handleSubmit} className="space-y-3" noValidate replace > {error && <p className="text-red-500">{error}</p>} <fieldset> <label htmlFor="email">邮箱</label> <Input name="email" placeholder="邮箱" /> </fieldset> <fieldset> <label htmlFor="password">密码</label> <Input name="password" type="password" placeholder="密码" /> </fieldset> <LoadingButton type="submit" size="lg" name="intent" value="__with_email" isLoading={navigation.state === 'loading'} className="mt-[18px] min-h-[56px] w-full text-base" > 创建账号 </LoadingButton> <p className="mt-[18px] text-center text-base"> 已有账号?{' '} <Link to="/login" className="font-bold hover:underline"> 登录 </Link> </p> </Form> ); }
注意事项
- 使用Admin SDK时,需要在环境变量中配置Firebase服务账号的相关信息(projectId、clientEmail、privateKey),这些信息可以从Firebase控制台的"服务账号"页面下载JSON文件获取。
- 客户端处理注册时,确保Firebase客户端SDK已正确初始化,且仅在浏览器环境中执行相关逻辑(Remix中可以通过
typeof window !== 'undefined'判断环境)。
内容的提问来源于stack exchange,提问作者Elysee Bleu
相关产品推荐
相关产品推荐

