I have an angular project set up to use firebase and I have installed and set up the emulators. The auth emulator works perfectly, I can login, create user, etc.. But the firestore and storage emulators set up in the same project are getting ignored and the calls are going to the live app in the cloud.
I am using the most recent v9 of the firebase apis
here is my angular module that declares provides the emulators:
@NgModule({
imports: [
CommonModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => {
const auth = getAuth();
if (environment.useEmulators) {
connectAuthEmulator(auth, 'http://localhost:9099', {
disableWarnings: true,
});
}
return auth;
}),
provideFirestore(() => {
let firestore: Firestore;
if (environment.useEmulators) {
firestore = initializeFirestore(getApp(), {
experimentalForceLongPolling: true,
});
connectFirestoreEmulator(firestore, 'localhost', 8080);
} else {
firestore = getFirestore();
}
return firestore;
}),
provideStorage(() => {
const storage = getStorage();
connectStorageEmulator(storage, 'localhost', 9199);
return storage;
}),
],
and here are the settings from the fierbase.json file:
"emulators": {
"auth": {
"port": 9099
},
"firestore": {
"port": 8080
},
"ui": {
"enabled": true
},
"storage": {
"port": 9199
}
},
I have made sure the port numbers match and when the emulator UI runs I can see the storage and firestore emulators are on and I can add records/files to each one.
here is a test function where I call the firestore get doc and storage getDownloadUrl
constructor(
private afs: AngularFirestore,
private storage: AngularFireStorage
) {}
public test(UID: string) {
if (UID !== null && UID !== undefined) {
const ref = this.storage.ref('userProfilePics/pic.png');
ref.getMetadata().subscribe((data) => console.log(data));
this.userSettingsDoc = this.afs.doc<UserSettings>('userSettings/' UID);
return this.userSettingsDoc.get();
} else {
return null;
}
}
these functions execute normally and return meta data for files in the live storage account. When I inspect the network traffic I can see that the results are coming from https://firestore.googleapis.com and ** https://firebasestorage.googleapis.com** and not http://localhost:8080 and http://localhost:9199 respectively.
I saw that this document recommends prefixing your project name with demo because it means the project will only connect to emulators and not production. However this seems to be ignored in my case.
so here is my environment file for dev builds:
export const environment = {
firebase: {
apiKey: "AIzaSyDtCn3C3rnDIoeEvGzj4HgmEZ0cGY",
authDomain: "app.firebaseapp.com",
projectId: "demo-app",
storageBucket: "app.appspot.com",
messagingSenderId: "89700977",
appId: "1:89707802:web:7af3c375c54dea04d0",
measurementId: "G-6K0SDV"
},
useEmulators: true,
production: false
};
When I start the emulators I get the message:
emulators: Detected demo project ID "demo-app", emulated services will use a demo configuration and attempts to access non-emulated services for this project will fail.
but when I call into the storage or firestore apis they still are going to the live google cloud endpoints.
Can someone help me figure out why these local emulators are not getting used in my dev environment?
CodePudding user response:
Often resetting the whole app solves this problem. I have recreated the setup from the code you have provided my app.module.ts is same as yours but I have passed getApp()
to following initializers getAuth(getApp())
, getFirestore(getApp())
and getStorage(getApp())
with my .firebaserc file as:
{
"projects": { "default": "<PROJECT_ID>" }
}
and It's working as intended with firebase emulator.
Also your firebase config variable does not have locationId
and databaseURL
Make sure to have these like as follows:
firebase: {
projectId: '<project-id>',
appId: '<app-id>',
databaseURL: 'https://<project-id>-default-rtdb.firebaseio.com',
storageBucket: '<project-id>.appspot.com',
locationId: 'us-central',
apiKey: '<api-key>',
authDomain: '<project-id>.firebaseapp.com',
messagingSenderId: '<messaging-sender-id>',
measurementId: '<measurement-id>',
},
useEmulators: true, production: false,
and firebase.json as follows :
{
"emulators": {
"auth": { "port": 9099 }, "firestore": { "port": 8080 }, "storage": { "port": 9199 },
"ui": { "enabled": true, "port": 3000 },
"singleProjectMode": true
},
"firestore": { "rules": "firestore.rules" }, "storage": { "rules": "storage.rules" }
}
With using default firestore and storage rules from the firebase console in the firestore.rules and storage.rules` files respectively.
If the above suggested won’t work then I will recommend you to uninstall @angular/fire
, firebase
from the project and install again with ng add @angular/fire
as Often this resolves my issues.
For information about how to configure with a bare minimum follow this article
CodePudding user response:
my project is inside an NX monorepo and I could not determine if other nx workspace settings were causing problems.
So I created a brand new POC angular app to test setting up the emulators from scratch. I was able to produce a minimum requirement App and the instructions can be found at this github issue I created
in the end I needed this for my ng module
@NgModule({
declarations: [AppComponent,],
imports: [
BrowserModule,
AppRoutingModule,
AngularFireStorageModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => {
const auth = getAuth();
if (environment.useEmulators) {
connectAuthEmulator(auth, 'http://localhost:9099', {
disableWarnings: true,
});
}
return auth;
}),
],
providers: [
{ provide: FIREBASE_OPTIONS, useValue: environment.firebase },
{
provide: AUTH_SETTINGS,
useValue: { appVerificationDisabledForTesting: true },
},
{ provide: USE_AUTH_EMULATOR, useValue: environment.useEmulators ? ['http://localhost', 9099] : undefined },
],
bootstrap: [AppComponent],
})
export class AppModule {}
there was a cors error:
Access to fetch at 'http://localhost/identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=AIzaSyCnBIYMzB4KsUOzP7C7AbGvJoHsj3lmMtE' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
that has to be fixed by reaplacing
provideAuth(() => getAuth()),
with
provideAuth(() => {
const auth = getAuth();
if (environment.useEmulators) {
connectAuthEmulator(auth, 'http://localhost:9099', {
disableWarnings: true,
});
}
return auth;
}),
also note that the provider for auth needs http://localhost instead of localhost to solve another error thrown from the auth provider
I did have to downgrade from @angular/fire 7.5.0 to 7.4.1 to fix some typing errors (this should be fixed soon - see this issue)
This got auth, firestore, and storage emulators working with my app. Once this POC was working I duplicated the settings in my NX workspace and it is now working there as well.
here is my environment:
Version info
Angular CLI: 15.1.4
Node: 18.12.1
Package Manager: npm 6.14.18
OS: win32 x64
Angular: 15.1.2
... animations, common, compiler, core, forms, platform-browser
... platform-browser-dynamic, router
Package Version
@angular-devkit/architect 0.1501.4
@angular-devkit/build-angular 15.1.4
@angular-devkit/core 14.2.10
@angular-devkit/schematics 14.2.10
@angular/cli 15.1.4
@angular/compiler-cli 15.1.3
@angular/fire 7.4.1
@schematics/angular 14.2.10
rxjs 7.8.0
typescript 4.9.5