Angular集成Firebase部署后报错:TypeError: "ot(...).auth is not a function"
ot(...).auth is not a function 错误的解决办法 我之前也碰到过一模一样的问题:开发模式下用ng serve跑完全正常,但是构建后用live-server托管就弹出这个ERROR TypeError: "ot(...).auth is not a function"的错误,折腾了好一会儿才搞定,分享下我的解决方案:
问题根源
这个错误本质上是生产构建时的**树摇优化(tree-shaking)**搞的鬼——Firebase的部分模块被Angular的构建工具误判为未使用,给优化掉了;另外直接访问afAuth.auth这个内部属性的写法,在生产环境的代码压缩重命名后也容易出问题。
具体解决步骤
1. 先确保AngularFire和Firebase依赖版本兼容且为最新
不同版本的Angular和AngularFire/Firebase有严格的对应关系,版本不匹配很容易出奇怪的bug。先执行更新命令:
npm install @angular/fire@latest firebase@latest --save
更新完可以检查下package.json里的版本,确保两者版本是配套的(比如Angular 16对应AngularFire 7.6+、Firebase 9.x以上)。
2. 修改AuthService的代码,用AngularFire封装好的API替代直接访问auth属性
你的代码里直接用了this.afAuth.auth.signInWithPopup和this.afAuth.auth.signOut,这种写法在生产压缩后容易出问题,换成AngularFireAuth提供的实例方法就稳了:
import { Router } from "@angular/router"; import { Injectable } from '@angular/core'; import { AngularFireAuth } from "@angular/fire/auth"; import { User } from 'firebase'; import { auth } from 'firebase/app'; @Injectable({ providedIn: 'root' }) export class AuthService { public user: User; constructor(public afAuth: AngularFireAuth, public router: Router ) { this.afAuth.authState.subscribe(user => { if (user) { this.user = user; localStorage.setItem('user', JSON.stringify(this.user)); } else { localStorage.setItem('user', 'null'); // 注意:不能直接存null,要存字符串'null',否则JSON.parse会报错 } }) } get isAuthenticated(): boolean { const user = JSON.parse(localStorage.getItem('user')); return user !== null && user !== 'null'; // 加上对'null'字符串的判断 } authState() { return this.afAuth.authState } login() { // 直接调用afAuth的signInWithPopup方法 this.afAuth.signInWithPopup(new auth.GoogleAuthProvider()); } logout() { // 调用afAuth的signOut方法,加上then确保登出完成后再跳转 this.afAuth.signOut().then(() => { this.router.navigate(['']); }); } }
另外我改了localStorage存值的地方——直接存null的话,JSON.parse会返回null,但有时候会出现字符串'null'的情况,所以获取的时候要做双重判断。
3. 检查AppModule的Firebase初始化方式(针对AngularFire 7+)
如果你的AngularFire是7.x以上版本,建议用新的provideFirebaseApp和provideAuth方式初始化,这种方式更适配生产构建的优化:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { provideFirebaseApp, initializeApp } from '@angular/fire/app'; import { provideAuth, getAuth } from '@angular/fire/auth'; import { AppComponent } from './app.component'; // 你的Firebase配置 const firebaseConfig = { apiKey: "YOUR_API_KEY", authDomain: "YOUR_AUTH_DOMAIN", projectId: "YOUR_PROJECT_ID", storageBucket: "YOUR_STORAGE_BUCKET", messagingSenderId: "YOUR_MESSAGING_SENDER_ID", appId: "YOUR_APP_ID" }; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, // 新的初始化方式 provideFirebaseApp(() => initializeApp(firebaseConfig)), provideAuth(() => getAuth()), ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
如果是旧版本的AngularFire,用AngularFireModule.initializeApp也可以,但尽量升级到新方式更稳妥。
4. 确认angular.json的构建配置没有问题
生产构建默认的优化是开启的,但如果你的angular.json里修改过build配置,确保optimization是true,同时没有把Firebase相关模块排除在优化之外:
"architect": { "build": { "configurations": { "production": { "optimization": true, "outputHashing": "all", "sourceMap": false, "namedChunks": false, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true } } } }
验证步骤
修改完以上内容后,执行ng build(现在默认是生产环境构建),然后用live-server启动dist文件夹,测试登录登出功能,应该就不会再出现那个错误了。
内容的提问来源于stack exchange,提问作者str028

