Reputation: 1985
I am trying to use the freshly introduced Firestore emulator in my Angular7 application.
According to this documentation, I run the dev server on 127.0.0.1:8080
with :
firebase serve --only firestore
Then, after ng serve
, how can I make my AngularFire module use the database emulator ?
I tried the following in my environment.ts
:
export const environment = {
production: false,
name: 'local',
firebase: {
databaseURL: "http://127.0.0.1:8080"
}
};
But it does not work since it needs a "projectId". I tried to set it to my pre-production Firestore database, but then the dev server is not used.
Any thought about it ?
Here is my app.module.ts
:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from '@app/app-routing.module';
import { AppComponent } from '@app/app.component';
import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { AngularFireAuthModule } from '@angular/fire/auth';
import { environment } from '@env/environment';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
AngularFireModule.initializeApp(environment.firebase, 'my-super-cool-app'),
AngularFirestoreModule,
AngularFireAuthModule,
AngularFireStorageModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Upvotes: 35
Views: 12132
Reputation: 349
VERSION 16+ (or before too, I started on 16 here)
uses another syntax/method.
This also enables persistent cache, and sets region for functions:
// omitted some imports for brevity
import { connectFunctionsEmulator } from '@angular/fire/functions';
import { connectAuthEmulator } from "@angular/fire/auth";
import { connectFirestoreEmulator } from '@angular/fire/firestore';
//provideFunctions(() => getFunctions()), // standard, from docs
provideFunctions(() => {
const functions = getFunctions();
functions.region = "us-central1";
if (!environment.production) {
connectFunctionsEmulator(functions, "localhost", 5001);
}
return functions;
}),
provideAuth(() => {
const auth = getAuth();
if (!environment.production) {
connectAuthEmulator(auth, "http://localhost:9099", {
disableWarnings: false,
});
}
return auth;
}),
provideFirestore(() => {
const firestore = initializeFirestore(getApp(), {
localCache: persistentLocalCache({
tabManager: persistentMultipleTabManager(),
}),
});
if (!environment.production) {
connectFirestoreEmulator(firestore, "localhost", 8080);
}
return firestore;
}),
and so on for the other emulators (haven't tried all of them yet)
Upvotes: 2
Reputation: 4808
based on this documentation since version 6.1.0 you could do:
import { USE_EMULATOR as USE_FIRESTORE_EMULATOR } from '@angular/fire/firestore';
@NgModule({
// ... Existing configuration
providers: [
{ provide: USE_FIRESTORE_EMULATOR, useValue: ['localhost', 8081] }
]
})
export class AppModule { }
VERSION 7
Since version 7 you need to use these methods in your modules
...
@NgModule({
imports: [
provideFirebaseApp(() => {
const firebaseApp = initializeApp(environment.firebaseConfig)
return (firebaseApp);
}),
provideAuth(() => {
const auth = getAuth();
if (!environment.production)
connectAuthEmulator(auth, `http://localhost:9099`)
return (auth);
}),
provideDatabase( () => {
const db = getDatabase()
if ( !environment.production )
connectDatabaseEmulator( db, 'localhost' , 9000 );
return ( db );
} ),
provideFirestore( () => {
const firestore = getFirestore()
if ( !environment.production )
connectFirestoreEmulator( firestore, 'localhost' , 8080 );
return ( firestore );
} ) ]
...
Upvotes: 10
Reputation: 719
For one who are using AngularFire v7 without compat module, you can find an exmaple app.module.ts
to use emulators. I worked with @amgular/fire
v7.2.1.
Upvotes: 6
Reputation: 15113
Using "the Firebase emulator" is not as obvious as it first seems, as "the emulator" is actually a collection of emulators. Setting one doesn't mean setting them all. You can even set some to run locally while others are remote, depending on your needs.
To set all emulators to run locally, you can use these providers:
import { AngularFireAuthModule, USE_EMULATOR as AUTH_EMULATOR } from '@angular/fire/auth';
import { USE_EMULATOR as FIRESTORE_EMULATOR } from '@angular/fire/firestore';
import { USE_EMULATOR as DATABASE_EMULATOR } from '@angular/fire/database';
import { USE_EMULATOR as FUNCTIONS_EMULATOR } from '@angular/fire/functions';
...
providers: [
{
provide: AUTH_EMULATOR,
useValue: environment.production ? undefined : ['localhost', 9099],
},
{
provide: FIRESTORE_EMULATOR,
useValue: environment.production ? undefined : ['localhost', 8080],
},
{
provide: DATABASE_EMULATOR, // i.e., Realtime Database
useValue: environment.production ? undefined : ['localhost', 9000],
},
{
provide: FUNCTIONS_EMULATOR,
useValue: environment.production ? undefined : ['localhost', 5001],
},
],
Upvotes: 14
Reputation: 681
Following this Article from Dev.to, I managed to setup my Angular 8 application to communicate with my emulated firebase functions, firestore and realtime db.
Please do not have your API keys and vital information exposed on the frontend in a production application.
How to (For those not setup): The emulating Firebase may be followed in the article above or official documentation: Setup Firebase Emulators, Run Functions Locally.
Below are snippets from the article in regards to Angular's Configuration.
src/environments/environment.ts
{ ...
emulator:true
}
src/app/app.module.ts
import {AngularFirestoreModule, SETTINGS} from "@angular/fire/firestore";
@NgModule({
declarations: [
...
],
imports: [
...
],
providers: [{
provide: SETTINGS,
useValue: environment.emulator ? {
host: 'localhost:8080',
ssl: false
} : undefined
}],
bootstrap: [...]
})
export class AppModule {
}
src/app/app.component.ts
Snippet from the article:
public ngOnInit() {
if (environment.emulator) {
this.aff.useFunctionsEmulator('http://localhost:5001').then(() => console.log('Using functions emulator'))
}
}
Vs: What I implemented instead:
constructor(...
private app: FirebaseApp) {...}
...
ngOnInit() {
if (environment.emulator) {
this.app.functions().useFunctionsEmulator('http://localhost:5001');
console.log('Using functions emulator');
}
}
Note in article which applies to database / firestore instead of functions:
NOTE: The overall concept is the same for the other firebase client sdk's but the syntax will change between implementations. The main goal is to really just tell the firebase sdk's that you want to use a different url for that service to point to.
Angular: Why this way?
It allows you to emulate multiple environments, without changing the infrastructure of the environment (file) you're emulating (no hard-coded changes to localhost, but rather the app will change these values itself).
I would recommend only using this as a template and customizing it for your application - for instance, the localhost:8080
in app.modules
can be dynamic and associated to an environment variable for tidier configuration.
Upvotes: 4
Reputation: 324
I got it working by adding a provider in the main app module that overrides some of the variables set by the environment file.
See This answer to an issue at the angularfire repo. Example (from the answer):
{
provide: FirestoreSettingsToken,
useValue: environment.production ? undefined : {
host: 'localhost:8081',
ssl: false
}
}
As i have a couple of different environments, I let the conditional look for an 'emulator' attribute in the environment and return undefined if it's false or undefined, instead of looking for the production attribute and returning undefined if it's present:
{
provide: FirestoreSettingsToken, useValue: environment.emulator ? {
host: 'localhost:8081',
ssl: false
} : undefined
}
Update as of AngularFire v6.x.x:
FirestoreSettingsToken
has changed to SETTINGS
in @angular/fire/firestore
module
Upvotes: 22
Reputation: 2626
I'm able to run it directly from environment.ts
file without raising any errors.
export const environment = {
production: false,
firebaseConfig: {
host: 'localhost:8081',
ssl: false,
apiKey: '<api-key>',
authDomain: '<project-id>.firebaseapp.com',
databaseURL: 'http://localhost:9000?ns=<project-id>',
projectId: '<project-id>',
appId: '<app-id>',
measurementId: '<measurement-id>',
},
};
Upvotes: 10