Skip to content

Feat(Firestore) JSON serialization of types to improve SSR support. #8926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Jun 23, 2025

Conversation

DellaBitta
Copy link
Contributor

@DellaBitta DellaBitta commented Apr 15, 2025

Discussion

Support the ability to resume onSnapshot listeners in the CSR phase based on serialized DataSnapshots and QuerySnapshots built in the SSR phase. Allow Firestore result types to be serialized with toJSON and then deserialized with fromJSON methods on the objects.

DocumentSnapshot and QuerySnapshot deserialization methods will be standalone, tree-shakable functions dataSnapshotFromJSON and querySnapshotFromJSON.

Testing

Integration Tests.
Unit Tests.
Locally tested with Next.JS.

Will add to our Next.js End to End test suite when the change has been staged.

API Changes

Approved go/fs-js-json-serialization.

DellaBitta and others added 3 commits April 1, 2025 15:23
…ure branch (#8872)

Merge the initial bundler implementation into the Firestore Result Serialization feature branch.
Implementation includes the ability to invoke `toJSON()` on `QuerySnapshot` and `DocumentSnapshot` instances.
…8896)

Pull request to add onSnapshot listeners support for bundles to the Firestore SSR serialization feature branch.

This change adds a series of onSnapshot overloads that match the existing onSnapshot variants (observer, individual callback functions, etc) but accepts a bundle instead of a QuerySnapshot or a DocumentSnapshot.

The toJSON methods of `QuerySnapshot` and `DocumentSnapshot` have also been updated to explicitly name the fields in the object return type.

Fixed an issue in the bundle builder where the bundleName for `DocumentSnapshots` didn't match the `ResourcePath` of the document, which is needed when reconstituting the `DocumentReference` in `onSnapshot`.

Finally, I cleaned up the text wrapping for the `onSnapshot` reference doc comments so they take up fewer lines of source code.
Copy link

changeset-bot bot commented Apr 15, 2025

⚠️ No Changeset found

Latest commit: 67cd379

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Apr 15, 2025

Size Report 1

Affected Products

  • @firebase/firestore

    TypeBase (13e6cce)Merge (3503366)Diff
    browser385 kB395 kB+9.29 kB (+2.4%)
    main596 kB615 kB+19.5 kB (+3.3%)
    module385 kB395 kB+9.29 kB (+2.4%)
    react-native386 kB395 kB+9.29 kB (+2.4%)
  • @firebase/firestore-lite

    TypeBase (13e6cce)Merge (3503366)Diff
    browser114 kB117 kB+2.56 kB (+2.2%)
    main157 kB160 kB+2.92 kB (+1.9%)
    module114 kB117 kB+2.56 kB (+2.2%)
    react-native114 kB117 kB+2.56 kB (+2.2%)
  • bundle

    15 size changes

    TypeBase (13e6cce)Merge (3503366)Diff
    firestore (CSI Auto Indexing Disable and Delete)280 kB290 kB+10.3 kB (+3.7%)
    firestore (CSI Auto Indexing Enable)280 kB290 kB+10.3 kB (+3.7%)
    firestore (Persistence)311 kB321 kB+10.3 kB (+3.3%)
    firestore (Query Cursors)256 kB260 kB+3.71 kB (+1.4%)
    firestore (Query)254 kB258 kB+3.71 kB (+1.5%)
    firestore (Read data once)242 kB247 kB+5.63 kB (+2.3%)
    firestore (Read Write w Persistence)336 kB341 kB+5.50 kB (+1.6%)
    firestore (Realtime updates)244 kB248 kB+3.83 kB (+1.6%)
    firestore (Transaction)221 kB226 kB+5.50 kB (+2.5%)
    firestore (Write data)220 kB228 kB+7.12 kB (+3.2%)
    firestore-lite (Query Cursors)109 kB111 kB+2.03 kB (+1.9%)
    firestore-lite (Query)105 kB107 kB+2.03 kB (+1.9%)
    firestore-lite (Read data once)80.6 kB82.8 kB+2.16 kB (+2.7%)
    firestore-lite (Transaction)106 kB108 kB+2.03 kB (+1.9%)
    firestore-lite (Write data)90.2 kB92.3 kB+2.03 kB (+2.2%)

  • firebase

    TypeBase (13e6cce)Merge (3503366)Diff
    firebase-compat.js802 kB806 kB+3.61 kB (+0.4%)
    firebase-firestore-compat.js347 kB351 kB+3.60 kB (+1.0%)
    firebase-firestore-lite.js137 kB140 kB+2.56 kB (+1.9%)
    firebase-firestore.js449 kB458 kB+9.26 kB (+2.1%)

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/JU8yIx7tIn.html

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Apr 15, 2025

Size Analysis Report 1

This report is too large (1,176,362 characters) to be displayed here in a GitHub comment. Please use the below link to see the full report on Google Cloud Storage.

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/yd6aEBMMWd.html

@DellaBitta DellaBitta changed the title [Feat] WIP Firestore Snapshot serialization [Feat] WIP FS SSR serialization Apr 15, 2025
DellaBitta and others added 6 commits April 24, 2025 15:59
commit 05338d8
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 15:58:18 2025 -0400

    test fixes

commit 28c6da9
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 15:39:22 2025 -0400

    update vector_value

commit 0aa81ce
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 15:39:11 2025 -0400

    update reference

commit e20bac9
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 15:24:50 2025 -0400

    update timestamp

commit 05b29c4
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 15:24:39 2025 -0400

    update geopoint

commit 4cf66f2
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 15:16:15 2025 -0400

    convert DocumentReference to new JSON validator.

commit 00a2423
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 13:44:27 2025 -0400

    format fix.

commit 09eb5cf
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 13:43:13 2025 -0400

    Bytes prototype.

commit b753f49
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 24 13:26:41 2025 -0400

    Linter doesn't like it, but API extractor does

commit 775cc69
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 17 13:13:52 2025 -0400

    lower case types

commit 188c86f
Author: DellaBitta <drsanta@google.com>
Date:   Thu Apr 17 10:41:58 2025 -0400

    DocumentReference unit and integration tests

commit 44d8045
Author: DellaBitta <drsanta@google.com>
Date:   Wed Apr 16 20:39:55 2025 -0400

    map Timestamp fields to DbTimestamp fields

commit f305182
Author: DellaBitta <drsanta@google.com>
Date:   Wed Apr 16 15:54:23 2025 -0400

    DocumentReference impl

commit 05a49aa
Author: DellaBitta <drsanta@google.com>
Date:   Wed Apr 16 11:14:00 2025 -0400

    Timestamp, GeoPoint, VectorValue

commit 1652e8b
Author: DellaBitta <drsanta@google.com>
Date:   Tue Apr 15 17:33:51 2025 -0400

    format

commit 8a081e1
Author: DellaBitta <drsanta@google.com>
Date:   Tue Apr 15 17:26:09 2025 -0400

    Bytes and VectorValue to/from JSON

commit 2a07791
Author: DellaBitta <drsanta@google.com>
Date:   Tue Apr 15 14:07:25 2025 -0400

    Bytes
Add a methods to parse bundles synchronously to extract single `DocumentSnapshots` or `QuerySnapshots` containing documents. Hook the new bundle parser up the `documentSnapshotFromJSON` and `querySnapshotFromJSON`.

### Testing

Local testing with Next.js app.
Added unit tests and integration tests.

### API Changes
go/fs-js-json-serialization
To reduce bundle size on clients, the `toJSON` methods of `DocumentSnapshot` and `QuerySnapshot` will not create bundles.

### Testing

Updated the integration and unit tests to test `fromJSON` functionality in node environments only.

I did attempt to create pre-packaged bundles so that we can test in browser still, but unforunately the bundle includes the project name, and the project that we test against varies depending on the profile of tests that were running (prod, local, etc). If these don't match then an error is thrown.

### API Changes

N/A
@DellaBitta DellaBitta changed the title [Feat] WIP FS SSR serialization [Feat] FS SSR serialization Jun 16, 2025
@DellaBitta DellaBitta marked this pull request as ready for review June 16, 2025 13:02
@DellaBitta DellaBitta requested review from a team as code owners June 16, 2025 13:02
Copy link
Contributor

@hsubox76 hsubox76 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferring to Firestore team for Firestore complexities but LG from my end minus some nits.

@DellaBitta DellaBitta requested a review from hsubox76 June 18, 2025 14:28
@DellaBitta DellaBitta changed the title [Feat] FS SSR serialization [Feat] Firestore SSR serialization Jun 18, 2025
Copy link
Contributor

@MarkDuckworth MarkDuckworth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I left a few questions, but nothing that should block, unless you want it to

* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
* snapshot stream is never-ending.
*
* @param firestore - The {@link Firestore} instance to enable persistence for.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment is wrong.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not related to enabling persistence

Copy link
Contributor Author

@DellaBitta DellaBitta Jun 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changed it to:

* @param firestore - The {@link Firestore} instance to enable the listener for.

* NOTE: Although an `onCompletion` callback can be provided, it will never be called because the
* snapshot stream is never-ending.
*
* @param firestore - The {@link Firestore} instance to enable persistence for.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

throw new FirestoreError(
Code.FAILED_PRECONDITION,
'QuerySnapshot.toJSON() attempted to serialize a document with pending writes. ' +
'Await waitForPendingWrites() before invoking toJSON().'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should put this statement in the TSDoc for this method. Might be a nice to have.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

);
}

// Create an internal Query object from the named query in the budnle.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in bundle

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks!

return new Timestamp(json.seconds, json.nanoseconds);
}
throw new FirestoreError(
Code.INTERNAL,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this switch from InvalidArgument to Internal? Should it be InvalidArgument?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm probably not remembering correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated it to InvalidParameter for all new fromJSON implementations.


/**
* Validates the JSON object based on the provided schema, and narrows the type to the provided
* JSON schaem.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@DellaBitta DellaBitta requested a review from MarkDuckworth June 20, 2025 19:30
@DellaBitta DellaBitta changed the title [Feat] Firestore SSR serialization Feat(Firestore) serialization of types to improve SSR support. Jun 23, 2025
@DellaBitta DellaBitta changed the title Feat(Firestore) serialization of types to improve SSR support. Feat(Firestore) JSON serialization of types to improve SSR support. Jun 23, 2025
@DellaBitta DellaBitta merged commit 7ae5b12 into main Jun 23, 2025
68 of 69 checks passed
@DellaBitta DellaBitta deleted the ddb-firestore-result-serialization branch June 23, 2025 18:57
@DellaBitta DellaBitta restored the ddb-firestore-result-serialization branch June 23, 2025 18:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants