Skip to content

Commit 33cdc0e

Browse files
committed
docs(firestore): add and update documentation for bundles
Adds new documentation and updates existing documentation for Firestore data bundles. The new `bundles.md` file provides a deep dive into the concept of bundles, their primary use case for SSR hydration, and other benefits. The `architecture.md` file has been updated to include a high-level overview of bundles and their data flow, consistent with the rest of the document.
1 parent dbe95e5 commit 33cdc0e

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

packages/firestore/devdocs/architecture.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ All data modifications—creates, updates, and deletes—are treated as "writes.
5757

5858
* **Transactions**: For grouping multiple write operations into a single atomic unit, the SDK provides `runTransaction`. Unlike standard writes, transactions do not use the optimistic, offline-capable write pipeline. Instead, they are sent directly to the backend, which requires an active internet connection. This ensures atomicity but means transactions do not benefit from the offline capabilities of the standard write pipeline.
5959

60+
### Data Bundles
61+
62+
A Firestore data bundle is a serialized collection of documents and query results, created on a server using the Firebase Admin SDK. Bundles are used to efficiently deliver a pre-packaged set of data to the client, which can then be loaded directly into the SDK's local cache. This is useful for:
63+
64+
* **Seeding initial data** for an application, allowing users to have a complete offline experience on their first use.
65+
* **Distributing curated datasets** to clients in a single, efficient package.
66+
67+
When a bundle is loaded, its contents are unpacked and stored in the local cache, making the data available for immediate querying without needing to connect to the Firestore backend. For more details, see the [Bundles documentation](./bundles.md).
68+
6069

6170
# Data Flow
6271

@@ -85,4 +94,11 @@ Here's a step-by-step walkthrough of how data flows through the SDK for a write
8594
8. **Remote Table (in Local Store)**: The Remote Store receives the documents and saves them to the Remote Table in the Local Store, overwriting any previously cached versions of those documents.
8695
9. **Sync Engine**: The Sync Engine is notified of the updated documents. It re-calculates the query view by combining the new data from the Remote Table with any applicable pending mutations from the **Mutation Queue**.
8796
10. **API Layer**: If the query results have changed after this reconciliation, the new results are sent to the user's `onSnapshot` callback. This is why a listener may fire twice initially.
88-
11. **Real-time Updates**: From now on, any changes on the backend that affect the query are pushed to the Remote Store, which updates the Remote Table, triggering the Sync Engine to re-calculate the view and notify the listener.
97+
11. **Real-time Updates**: From now on, any changes on the backend that affect the query are pushed to the Remote Store, which updates the Remote Table, triggering the Sync Engine to re-calculate the view and notify the listener.
98+
99+
## Bundle Loading Data Flow
100+
101+
1. **API Layer**: The user initiates a bundle load via the public API.
102+
2. **Sync Engine**: The Sync Engine receives the bundle and begins processing it.
103+
3. **Local Store**: The Sync Engine unpacks the bundle and saves its contents (documents and named queries) into the **Local Store**.
104+
4. **API Layer**: The user is notified of the progress and completion of the bundle loading operation via the task returned by the API.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Firestore Data Bundles
2+
3+
This document provides a deep dive into the concept of Firestore data bundles, how they are processed, and how they are used within the SDK.
4+
5+
## What is a Bundle?
6+
7+
A Firestore data bundle is a serialized, read-only collection of documents and named query results. Bundles are created on a server using the Firebase Admin SDK and can be efficiently distributed to clients.
8+
9+
While bundles can be used for several purposes, their primary design motivation is to optimize Server-Side Rendering (SSR) workflows. In an SSR setup, a server pre-renders a page with data from Firestore. This data can be packaged into a bundle and sent to the client along with the HTML. The client-side SDK can then load this bundle and "hydrate" a real-time query with the pre-existing data, avoiding the need to re-fetch the same documents from the backend. This results in a significant performance improvement and cost savings.
10+
11+
## Primary Use Case: Server-Side Rendering (SSR) Hydration
12+
13+
The main workflow for bundles is as follows:
14+
15+
1. **Server-Side:** A server fetches data from Firestore to render a page.
16+
2. **Bundling:** The server packages the fetched documents and the corresponding query into a bundle.
17+
3. **Transmission:** The bundle is embedded in the HTML page sent to the client.
18+
4. **Client-Side:** The client-side JavaScript calls `loadBundle()` to load the data from the bundle into the SDK's local cache.
19+
5. **Hydration:** The client then attaches a real-time listener to the same query that was bundled. The SDK finds the query results in the local cache and immediately fires the listener with the initial data, avoiding a costly roundtrip to the backend.
20+
21+
## Other Benefits and Use Cases
22+
23+
Beyond SSR hydration, bundles offer several other advantages:
24+
25+
* **Enhanced Offline Experience:** Bundles can be shipped with an application's initial assets, allowing users to have a more complete offline experience from the first launch, reducing the need to sync every document individually.
26+
* **Efficient Data Distribution:** They provide an efficient way to deliver curated or static datasets to clients in a single package. For instance, an application could bundle a list of popular items or configuration data.
27+
28+
## The Loading Process
29+
30+
The process of loading a bundle into the Firestore SDK is initiated by the `loadBundle()` method. This method returns a `LoadBundleTask`, which allows the developer to track the progress of the loading operation.
31+
32+
Here's a step-by-step walkthrough of what happens when `loadBundle()` is called:
33+
34+
1. **`loadBundle()` called:** The developer calls `loadBundle()` with the bundle data (as a `ReadableStream` or `ArrayBuffer`).
35+
2. **`LoadBundleTask` created:** A `LoadBundleTask` is created and returned to the developer. This task acts as a `Promise` and also provides progress updates.
36+
3. **`BundleLoader` initiated:** Internally, a `BundleLoader` is created to process the bundle.
37+
4. **Bundle processing:** The `BundleLoader` reads the bundle element by element. The bundle is a sequence of JSON objects, each representing a metadata element, a named query, or a document.
38+
5. **Data caching:** As the `BundleLoader` processes the bundle, it saves the data to the local store:
39+
* **Bundle Metadata:** The bundle's metadata is saved to the `BundleCache`. This is used to track which bundles have been loaded.
40+
* **Named Queries:** Named queries are saved to the `BundleCache`.
41+
* **Documents:** Documents are saved to the `RemoteDocumentCache`.
42+
6. **Progress updates:** The `LoadBundleTask` is updated with progress information (e.g., bytes loaded, documents loaded) as the `BundleLoader` processes the bundle.
43+
7. **Completion:** Once the `BundleLoader` has finished processing the bundle, the `LoadBundleTask` is marked as complete.
44+
45+
## Error Handling
46+
47+
Errors can occur during the bundle loading process for a variety of reasons, such as a malformed bundle or a storage issue.
48+
49+
When an error occurs, the `LoadBundleTask` is put into an `'Error'` state. The error is surfaced to the developer in two ways:
50+
51+
* **Promise rejection:** The `LoadBundleTask`'s promise is rejected with a `FirestoreError`.
52+
* **`onProgress` observer:** If an `error` callback is provided to the `onProgress` method, it will be called with the `FirestoreError`.
53+
54+
## Interacting with Bundled Data
55+
56+
Once a bundle has been loaded, the data it contains is available for querying. If the bundle included named queries, you can use the `getNamedQuery()` method to retrieve a `Query` object, which can then be executed.
57+
58+
When a named query is executed, the Firestore SDK will first attempt to fulfill the query from the local cache. If the results for the named query are available in the cache (because they were loaded from a bundle), they will be returned immediately, without a server roundtrip.

0 commit comments

Comments
 (0)