我正在尝试理解AngularFireFunctions文档。我做了一个新的Angular项目和一个新的Firestore数据库,安装了AngularFire和Firebase,将Firebase凭据连接到environments.ts
,并初始化了firebase-functions
、firebase-admin
和firestore
。
我修复了functions/package.json
中的一个错误。初始化程序创建以下行:
"main": "lib/index.js",
应该是
"main": "src/index.ts",
我的目录结构如下所示:
myproject
+- .firebaserc # Hidden file that helps you quickly switch between
| # projects with `firebase use`
|
+- firebase.json # Describes properties for your project
|
+- functions/ # Directory containing all your functions code
|
+- node_modules/ # directory where your dependencies (declared in # package.json) are installed
|
+- package-lock.json
|
+- src/
|
+- index.js # main source file for your Cloud Functions code
|
+- tsconfig.json # if you chose TypeScript
|
+- package.json # npm package file describing your Cloud Functions code
我启动了一个新的 Angular 项目,并完全按照 AngularFireFunctions 文档的建议设置app.module.ts
:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AngularFireModule } from '@angular/fire/compat';
import { AngularFireFunctionsModule, USE_EMULATOR } from '@angular/fire/compat/functions';
import { environment } from '../environments/environment';
@NgModule({
imports: [
BrowserModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFireFunctionsModule
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ],
providers: [
{ provide: USE_EMULATOR, useValue: ['localhost', 5001] }
]
})
export class AppModule {}
我在 HTML 视图中制作了一个按钮来调用 Firebase Cloud Function:
<div>
<button mat-raised-button color="basic" (click)='callMe()'>Call me!</button>
</div>
我按照文档的建议将firebase-functions
和firebase-admin
导入index.ts
。然后我取消注释了index.ts
附带的默认函数并添加了一个console.log
.
// The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
export const helloWorld = functions.https.onRequest((request, response) => {
console.log("Hello world!")
functions.logger.info("Hello logs!", {structuredData: true});
response.send("Hello from Firebase!");
});
最后我们到了app.component.ts
.我不理解文档中提供的代码,它抛出错误,所以我编写了自己的控制器:
import { Component } from '@angular/core';
import { AngularFireFunctions } from '@angular/fire/compat/functions';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private fns: AngularFireFunctions) {}
callMe() {
console.log("Calling...");
this.fns.httpsCallable('helloWorld');
}
}
当我运行firebase emulators:start
时,我看到一条错误消息:
functions: Failed to load function definition from source: FirebaseError: Failed to load function definition from source: Failed to generate manifest from function source: SyntaxError: Unexpected token 'export'
它在app.module.ts
和app.component.ts
中反对这些行:
export class AppModule {}
export class AppComponent {}
这些不是错误,模拟器会恢复并启动。
✔ All emulators ready! It is now safe to connect your app. │
│ i View Emulator UI at http://localhost:4000
我单击 HTML 视图中的按钮,查看控制台日志中的Calling...
,模拟器日志中没有任何反应。我希望在模拟器日志中看到Hello world
。为什么我的 Angular 应用不调用 Firebase Cloud Function?
这没有定义可调用的函数:functions.https.onRequest
.相反,它定义了一个常规的 HTTP 函数,您可以使用类似fetch
的东西调用它。
可调用的云函数使用functions.https.onCall
定义。要实现可调用函数,请查看有关编写可调用云函数的文档。
此外,此代码尚未调用该函数,而只是查找它:
this.fns.httpsCallable('helloWorld');
要调用它,您需要使用一些额外的括号来调用它,或者将其存储在变量中,然后按照文档中所示调用它。
const callable = fns.httpsCallable('my-fn-name');
this.data$ = callable({ name: 'some-data' });
我写了一个教程来回答这个问题。这是app.module.ts
:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { environment } from '../environments/environment';
// AngularFire 7
// import { initializeApp, provideFirebaseApp } from '@angular/fire/app';
// import { provideFirestore, getFirestore } from '@angular/fire/firestore';
// import { provideFunctions, getFunctions, connectFunctionsEmulator } from '@angular/fire/functions'; // https://firebase.google.com/docs/emulator-suite/connect_functions#instrument_your_app_to_talk_to_the_emulators
// AngularFire 6
import { AngularFireModule } from '@angular/fire/compat';
import { AngularFireFunctionsModule } from '@angular/fire/compat/functions';
import { USE_EMULATOR } from '@angular/fire/compat/functions'; // comment out to run in the cloud
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
// AngularFire 7
// provideFirebaseApp(() => initializeApp(environment.firebase)),
// provideFirestore(() => getFirestore()),
// provideFunctions(() => getFunctions()),
// AngularFire 6
AngularFireModule.initializeApp(environment.firebase),
AngularFireFunctionsModule
],
providers: [
{ provide: USE_EMULATOR, useValue: ['localhost', 5001] } // comment out to run in the cloud
],
bootstrap: [AppComponent]
})
export class AppModule { }
这使用AngularFire 6。我无法让 AngularFire 7 使用可调用函数。
这将运行模拟器中的函数。要在云中运行函数,请注释掉两行。
以下是app.component.ts
:
import { Component } from '@angular/core';
// AngularFire 7
// import { getApp } from '@angular/fire/app';
// import { provideFunctions, getFunctions, connectFunctionsEmulator, httpsCallable } from '@angular/fire/functions'; // https://firebase.google.com/docs/emulator-suite/connect_functions#instrument_your_app_to_talk_to_the_emulators
// import { Firestore, doc, getDoc, getDocs, collection, updateDoc } from '@angular/fire/firestore';
// AngularFire 6
import { AngularFireFunctions } from '@angular/fire/compat/functions';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
data$: any;
constructor(private functions: AngularFireFunctions) {
const callable = this.functions.httpsCallable('executeOnPageLoad');
this.data$ = callable({ name: 'Charles Babbage' });
}
callMe() {
console.log("Calling...");
const callable = this.functions.httpsCallable('callMe');
this.data$ = callable({ name: 'Ada Lovelace' });
};
}
又是这个棱角火6。变量data$
处理从云函数返回的数据。
httpsCallable
采用一个参数,即函数的名称。
callable
执行函数并接受一个参数,即保存要发送到函数的数据的对象。
HTML 视图:
<div>
<button mat-raised-button color="basic" (click)='callMe()'>Call me!</button>
</div>
{{ data$ | async }}
该视图显示用户单击的按钮以及从函数返回的数据。
云index.js
功能:
// The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
// executes on page load
exports.executeOnPageLoad = functions.https.onCall((data, context) => {
console.log("The page is loaded!")
console.log(data);
console.log(data.name);
// console.log(context);
return 22
});
// executes on user input
exports.callMe = functions.https.onCall((data, context) => {
console.log("Thanks for calling!")
console.log(data);
console.log(data.name);
// console.log(context);
return 57
});
每个函数都使用https.onCall((data, context) => {}
使其成为可调用的函数,即可从 Angular 调用。data
是从Angular发送的数据。context
是有关函数执行的元数据。每个函数返回数据显示在 HTML 视图中的数据。
要运行这些函数,请使用模拟器:
firebase emulators:start --only functions