借助 Firebase Data Connect 客户端 SDK,您可以直接从 Firebase 应用调用服务器端查询和突变。在设计部署到 Data Connect 服务的架构、查询和突变时,您可以并行生成自定义客户端 SDK。然后,将此 SDK 中的方法集成到您的客户端逻辑中。
正如我们在其他地方提到的,请务必注意,Data Connect查询和突变不是由客户端代码提交的,而是在服务器上执行的。相反,部署后,Data Connect 操作会像 Cloud Functions 一样存储在服务器上。这意味着您需要部署相应的客户端更改,以避免影响现有用户(例如,使用旧版应用的用户)。
因此,Data Connect 为您提供了一个开发者环境和工具,让您可以对服务器部署的架构、查询和突变进行原型设计。它还会在您进行原型设计时自动生成客户端 SDK。
当您对服务和客户端应用进行迭代更新后,服务器端和客户端更新即可部署。
客户端开发工作流程是怎样的?
如果您按照使用入门中的说明操作,则已了解 Data Connect 的整体开发流程。在本指南中,您可以详细了解如何从架构生成 Web SDK,以及如何处理客户端查询和变更。
总而言之,如需在客户端应用中使用生成的 Web SDK,您需要先完成以下前提步骤:
- 将 Firebase 添加到您的网页应用。
然后:
- 开发应用架构。
- 使用 JavaScript SDK 或 React/Angular 库初始化客户端代码。
- 对于 React 和 Angular,安装 Tanstack Query 软件包
设置 SDK 生成:
- 使用 Data Connect VS Code 扩展程序中的将 SDK 添加到应用按钮
- 通过更新 JavaScript SDK、React 或 Angular 的
connector.yaml
。
使用 JavaScript SDK、React 或 Angular 导入库和生成的代码。
使用 JavaScript SDK 或 React/Angular 实现对查询和突变的调用。
通过使用 JavaScript SDK 或 React/Angular 设置 Data Connect 模拟器进行测试。
使用 Firebase JavaScript SDK 实现客户端代码
本部分介绍了如何使用 Firebase JavaScript SDK 实现客户端。
如果您使用的是 React 或 Angular,请参阅有关为框架生成 Data Connect SDK 的替代设置说明和指向其他文档的链接。
初始化您的应用
首先,使用标准 Firebase 序列初始化您的应用。
initializeApp({...});
生成 JavaScript SDK
与大多数 Firebase 项目一样,Firebase Data Connect客户端Firebase Data Connect代码的开发工作在本地项目目录中进行。Data Connect VS Code 扩展程序和 Firebase CLI 都是用于生成和管理客户端代码的重要本地工具。
SDK 生成选项与您初始化项目时生成的 dataconnect.yaml
文件中的多个条目相关联。
初始化 SDK 生成
在connector.yaml
中,添加 outputDir
、package
和(对于 Web SDK)packageJsonDir
。
generate:
javascriptSdk:
outputDir: "../movies-generated"
package: "@movie-app/movies"
packageJsonDir: "../../"
outputDir
用于指定生成的 SDK 应输出到何处。
package
指定软件包名称。
packageJsonDir
指定软件包的安装位置。
在这种情况下,请安装 firebase@latest
以确保满足此对等依赖项。
初始化 JavaScript SDK
使用您在设置 Data Connect 时所用的信息(全部可在 Firebase 控制台的“Data Connect”标签页中找到)初始化 Data Connect 实例。
ConnectorConfig 对象
SDK 需要连接器配置对象。
此对象是根据 dataconnect.yaml
中的 serviceId
和 location
以及 connector.yaml
中的 connectorId
自动生成的。
导入库
初始化客户端代码需要两组导入:常规 Data Connect 导入和特定的已生成 SDK 导入。
请注意,常规导入中包含 ConnectorConfig
对象。
// general imports
import { ConnectorConfig, DataConnect, getDataConnect, QueryRef, MutationRef, QueryPromise, MutationPromise } from 'firebase/data-connect';
// generated queries and mutations from SDK
import { listMovies, ListMoviesResponse, createMovie, connectorConfig } from '@myorg/myconnector';
使用 JavaScript SDK 中的查询
生成的代码将已包含预定义的查询引用。您只需导入这些模型并对其调用 execute。
import { executeQuery } from 'firebase/data-connect';
import { listMoviesRef } from '@movie-app/movies';
const ref = listMoviesRef();
const { data } = await executeQuery(ref);
console.log(data.movies);
调用 SDK 查询方法
以下示例使用了这些操作快捷方式函数:
import { listMovies } from '@movie-app/movies';
function onBtnClick() {
// This will call the generated JS from the CLI and then make an HTTP request out
// to the server.
listMovies().then(data => showInUI(data)); // == executeQuery(listMoviesRef);
}
订阅更改
您可以订阅更改(这样,每次执行查询时都会进行更新)。
const listRef = listAllMoviesRef();
// subscribe will immediately invoke the query if no execute was called on it previously.
subscribe(listRef, ({ data }) => {
updateUIWithMovies(data.movies);
});
await createMovie({ title: 'Empire Strikes Back', releaseYear: 1980, genre: "Sci-Fi", rating: 5 });\
await listMovies(); // will update the subscription above`
使用 JavaScript SDK 中的突变
突变的访问方式与查询相同。
import { executeMutation } from 'firebase/data-connect';
import { createMovieRef } from '@movie-app/movies';
const { data } = await executeMutation(createMovieRef({ movie: 'Empire Strikes Back' }));
连接到 Data Connect 模拟器
(可选)您可以通过调用 connectDataConnectEmulator
并传入 Data Connect 实例来连接到模拟器,如下所示:
import { connectDataConnectEmulator } from 'firebase/data-connect';
import { connectorConfig } from '@myorg/myconnector'; // Replace with your package name
const dataConnect = getDataConnect(connectorConfig);
connectDataConnectEmulator(dataConnect, 'localhost', 9399);`
// Make calls from your app
如需切换到生产资源,请注释掉用于连接到模拟器的行。
为 React 和 Angular 实现客户端代码
Firebase Data Connect 提供了一个生成的 SDK,其中包含使用 Invertase 合作伙伴提供的库(即 TanStack Query Firebase)的 React 和 Angular 钩子。
此库提供了一组钩子,可大大简化在应用中使用 Firebase 处理异步任务的操作。
初始化您的应用
首先,与任何 Firebase Web 应用一样,使用标准 Firebase 序列初始化您的应用。
initializeApp({...});
安装 TanStack Query Firebase 软件包
在项目中安装 TanStack Query 的软件包。
回应
npm i --save @tanstack/react-query @tanstack-query-firebase/react
npm i --save firebase@latest # Note: React has a peer dependency on ^11.3.0
Angular
ng add @angular/fire
生成 React 或 Angular SDK
与标准 Web SDK 一样(如前文所述),Firebase 工具会根据您的架构和操作自动生成 SDK。
如需为项目生成 React SDK,请向 connector.yaml
配置文件添加 react
键。
回应
generate:
javascriptSdk:
react: true
outputDir: "../movies-generated"
package: "@movie-app/movies"
packageJsonDir: "../../"
Angular
generate:
javascriptSdk:
angular: true
outputDir: "../movies-generated"
package: "@movie-app/movies"
packageJsonDir: "../../"
导入库
您需要四组导入才能初始化 React 或 Angular 客户端代码:常规 Data Connect 导入、常规 TanStack 导入,以及针对 JS 和 React 生成的 SDK 的特定导入。
请注意,常规导入中包含 ConnectorConfig
类型。
回应
// general imports
import { ConnectorConfig, DataConnect, getDataConnect, QueryRef, MutationRef, QueryPromise, MutationPromise } from 'firebase/data-connect';
// TanStack Query-related functions
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
// generated queries and mutations from SDK
import { ListMoviesResponse, connectorConfig } from '@myorg/myconnector';
// generated React hooks from SDK
import { useListAllMovies, useCreateMovie } from "@myorg/connector/react";
Angular
// general imports
import { ConnectorConfig, DataConnect, getDataConnect, QueryRef, MutationRef, QueryPromise, MutationPromise } from 'firebase/data-connect';
// TanStack Query-related functions
import { provideTanStackQuery, QueryClient } from "@tanstack/angular-query-experimental";
// generated queries and mutations from SDK
import { ListMoviesResponse, connectorConfig } from '@myorg/myconnector';
// generated React hooks from SDK
import { injectListAllMovies, injectCreateMovie } from "@myorg/connector/angular";
在 React 或 Angular 客户端中使用查询和 mutation
设置完成后,您就可以使用生成的 SDK 中的方法了。
在以下代码段中,请注意以 use
为前缀的 React 方法 useListAllMovies
和以 inject
为前缀的 Angular 方法 injectListAllMovies
,这两个方法均来自生成的 SDK。
回应
生成的 SDK 中的所有此类操作(包括查询和 mutation)都会调用 TanStackQuery 绑定:
- 查询调用并返回 TanStack
useDataConnectQuery
hook - mutation 调用并返回 TanStack
useDataConnectMutation
hook
import { useListAllMovies } from '@movies-app/movies/react';
function MyComponent() {
const { isLoading, data, error } = useListAllMovies();
if(isLoading) {
return <div>Loading...</div>
}
if(error) {
return <div> An Error Occurred: {error} </div>
}
}
// App.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import MyComponent from './my-component';
function App() {
const queryClient = new QueryClient();
return <QueryClientProvider client={queryClient}>
<MyComponent />
</QueryClientProvider>
}
Angular
import { injectAllMovies, connectorConfig } from '@movies-app/movies/angular';
import { provideDataConnect, getDataConnect } from '@angular/fire/data-connect';
import { provideTanStackQuery, QueryClient } from "@tanstack/angular-query-experimental";
const queryClient = new QueryClient();
...
providers: [
...
provideTanStackQuery(queryClient),
provideDataConnect(() => {
const dc = getDataConnect(connectorConfig);
return dc;
})
]
在 React 和 Angular 中使用自动重新加载查询
您可以将查询配置为在数据发生变化时自动重新加载。
回应
export class MovieListComponent {
movies = useListAllMovies();
}
export class AddPostComponent {
const mutation = useCreateMovie({ invalidate: [listAllMoviesRef()] });
addMovie() {
// The following will automatically cause Tanstack to reload its listAllMovies query
mutation.mutate({ title: 'The Matrix });
}
}
Angular
// class
export class MovieListComponent {
movies = injectListAllMovies();
}
// template
@if (movies.isPending()) {
Loading...
}
@if (movies.error()) {
An error has occurred: {{ movies.error() }}
}
@if (movies.data(); as data) {
@for (movie of data.movies; track movie.id) {
<mat-card appearance="outlined">
<mat-card-content>{{movie.description}}</mat-card-content>
</mat-card>
} @empty {
<h2>No items!</h2>
}
}
连接到 Data Connect 模拟器
(可选)您可以通过调用 connectDataConnectEmulator
连接到模拟器,然后将 Data Connect 实例传递给生成的钩子,如下所示:
React
import { getDataConnect, connectDataConnectEmulator } from 'firebase/data-connect';
import { connectorConfig } from '@movies-app/movies';
import { useListAllMovies } from '@movies-app/movies/react';
const dc = getDataConnect(connectorConfig);
connectDataConnectEmulator(dc, 'localhost', 9399);
class AppComponent() {
...
const { isLoading, data, error } = useListAllMovies(dc);
...
}
Angular
// app.config.ts
import { provideDataConnect } from '@angular/fire/data-connect';
import { getDataConnect, connectDataConnectEmulator } from 'firebase/data-connect';
provideDataConnect(() => {
const dc = getDataConnect(connectorConfig);
connectDataConnectEmulator(dc, 'localhost', 9399);
return dc;
}),
如需切换到生产资源,请注释掉用于连接到模拟器的行。
SDK 中的数据类型
Data Connect 服务器表示常见的 GraphQL 数据类型。在 SDK 中,这些参数表示如下。
数据连接类型 | TypeScript |
---|---|
时间戳 | 字符串 |
日期 | 字符串 |
UUID | 字符串 |
Int64 | 字符串 |
双精度型 | 数字 |
浮点数 | 数字 |
SDK 生成的特殊注意事项
配置相对于 node_modules
的路径
对于 JavaScript SDK,由于 Data Connect 使用 npm link
安装您的 SDK,因此生成的 SDK 需要输出到与 node_modules
路径处于同一级别的目录或可访问 node_modules
的子目录中。
换句话说,生成的 SDK 需要有权访问 firebase
节点模块才能正常运行。
例如,如果您的 node_modules
位于 my-app/
中,则输出目录应为 my-app/js-email-generated
,以便 js-email-generated
可以从其父级 node_modules
文件夹导入。
my-app/
dataconnect/
connector/
connector.yaml
node_modules/
firebase/
js-email-generated/
// connector.yaml
connectorId: "my-connector"
generate:
javascriptSdk:
outputDir: "../../js-email-generated"
package: "@myapp/my-connector"
或者,如果您有一个模块托管在根目录中的单体代码库,则可以将输出目录放在单体代码库中的任何文件夹中。
my-monorepo/
dataconnect/
connector/
connector.yaml
node_modules/
firebase/
my-app/
js-email-generated/
package.json
// connector.yaml
connectorId: "my-connector"
generate:
javascriptSdk:
outputDir: "../../my-app/js-email-generated" # You can also output to ../../js-email-generated
在原型设计期间更新 SDK
如果您使用 Data Connect VS Code 扩展程序及其 Data Connect 模拟器进行交互式原型设计,那么在您修改定义架构、查询和变更的 .gql
文件时,系统会自动生成并更新 SDK 源文件。在热(重新)加载工作流中,这可能是一项实用功能。
.gql
更新,还可以自动更新 SDK 来源。
或者,您也可以使用 CLI 在每次更改 .gql 文件时重新生成 SDK:
firebase dataconnect:sdk:generate --watch
生成用于集成和正式版发布的 SDK
在某些情况下(例如准备要提交以进行 CI 测试的项目源),您可以调用 Firebase CLI 进行批量更新。
在这些情况下,请使用 firebase dataconnect:sdk:generate
。