Skip to content

Migrate the frontend to the modular Firebase SDK - #1714

Open
HugoGresse wants to merge 3 commits into
mainfrom
firestore-modular-sdk
Open

HugoGresse wants to merge 3 commits into
mainfrom
firestore-modular-sdk

Conversation

@HugoGresse

Copy link
Copy Markdown
Owner

Summary

Moves the feedback, admin and superadmin apps from the Firebase namespaced/compat API to the modular v9+ SDK (firebase/firestore, firebase/auth, firebase/storage, firebase/functions, firebase/analytics, firebase/performance), so bundles can be tree-shaken. Behaviour is meant to be identical: same document paths, queries, listeners/unsubscribes, merge options, error dispatches, and the fromCache offline check in inviteListener.

  • src/firebase.ts: initializeFirestore (forced long polling on the emulators) + connect*Emulator; initializeAuth with getAuth's persistence and popup resolver, plus debugErrorMap so auth errors keep the full messages compat installed.
  • Storage moves to src/admin/project/utils/storage/firebaseStorage.ts, so the voters' entry chunk no longer ships it.
  • Specs mock the modular functions and assert the document paths they write.
  • addVoteToDb and useFirestoreDocument had no callers, so they are deleted rather than migrated.

What still uses compat, and why

firebase/compat/app + firebase/compat/auth remain only in src/baseComponents/StyledFirebaseAuth.tsx:

  • firebaseui@6.1.0 (latest, unmaintained since 2023) needs a compat Auth instance and has a peer of firebase ^9 || ^10.
  • Its successor @firebase-oss/ui-react@7 needs React 19 and firebase 11/12.

The bridge wraps the modular [DEFAULT] app and reuses the modular Auth instance, including its emulator connection. It is lazy-loaded with the sign-in form, so only the login screens download compat + firebaseui. This also keeps firebase on 10.14.1: npm latest is 13.1.0, but firebaseui blocks the upgrade.

Dependency change: @firebase/testing → @firebase/rules-unit-testing@3.0.4

The code review found a real regression that this fixes:

  • Root cause. The deprecated @firebase/testing pulled in firebase@7 and hoisted @firebase/util@0.3.1. npm then nested a private copy of @firebase/auth/util under every firebase@10 package.
  • Effect. With firebase/auth (modular) and firebase/compat/auth (firebaseui) loaded together, the copies failed each other's instanceof FirebaseError. firebaseui reported every sign-in error as auth/network-request-failed: a wrong password showed "network error", and account linking and the anonymous-upgrade merge conflict never ran.
  • Fix. The rules spec now uses @firebase/rules-unit-testing 3.0.4, the last line with a firebase ^10 peer. Its helpers are unchanged: createApp() is an authenticated context, and organizations are seeded with the rules disabled. The re-lock hoists one copy of each @firebase/* package.
  • Guard. src/firebaseAuthSingleCopy.spec.ts fails if a future install nests a second @firebase/auth, util, app or component.
  • Lockfile. The diff is the removal of the firebase@7 tree plus a tslib consolidation.

Bundle (production build, gzip)

main this PR
Voter entry chunk (index-*.js) 940 KB / 281 KB gz 742 KB / 229 KB gz (-19%)
Chunk shared by admin + superadmin 321 KB / 97 KB gz 98 KB / 30 KB gz
compat + firebaseui in the entry on-demand StyledFirebaseAuth chunk
All JS 969 KB gz 933 KB gz

Not split into stacked PRs

The src/firebase.ts exports change for every area at once: serverTimestamp, auth and the other compat helpers are removed, and fireStoreMainInstance is now a modular Firestore. Per-area PRs would therefore not build on their own. The change is mechanical per file, so reviewing by folder works: src/feedback, src/core, src/admin/project, src/admin/{auth,users,organization}, src/superAdmin.

Test plan

  • npm run typecheck, npm run lint (same 4 pre-existing noConsole warnings as main), npm run lint:i18n
  • npm test (emulators:exec firestore): 48 files, 476 tests, including the migrated rules spec
  • Cypress E2E on the emulators: 16/16 specs pass
  • Manual check on the emulators:
    • admin login through firebaseui, and a wrong password now shows "The email and password you entered don't match"
    • dashboard stats
    • CSV export (Timestamps exported as ISO dates)
    • users list
    • invite creation, and opening it with ?inviteId=
    • vote on a talk, still there after a reload
  • /code-review max: the findings that hold up are fixed, and the remaining ones are listed below

No screenshots: nothing rendered changes, apart from firebaseui error messages that are correct again.

Follow-ups (not in this PR)

  • These bugs predate this PR and behave the same with compat:
    • the superadmin signInFailure merge handler calls currentUser.delete() after signInWithCredential, which signs the new user out;
    • the admin login sends the verification email twice on load;
    • deleteImageIfPossible URL-decodes paths incorrectly, so old images with spaces in their name are never deleted.
  • The superadmin vote count reads every vote document; modular getCountFromServer would cost about 1 read per 1,000 votes.
  • Replacing firebaseui would drop compat entirely and unblock firebase 13.

🤖 Generated with Claude Code

HugoGresse and others added 2 commits November 1, 2026 16:14
Replace the namespaced/compat API (firebase/compat/*, db.collection().doc(),
firebase.firestore.FieldValue, compat auth/storage/functions/analytics)
with the modular v9+ functions in the feedback, admin and superadmin apps.
Paths, queries, listeners, merge options, error handling and the
inviteListener fromCache check are unchanged.

- src/firebase.ts: initializeFirestore (long polling on the emulators) +
  connect*Emulator; initializeAuth with getAuth's persistence and popup
  resolver, plus debugErrorMap to keep compat's full error messages.
- Storage moves to an admin-only module, out of the voters' entry chunk.
- firebaseui@6 still needs a compat Auth: compat stays only in
  StyledFirebaseAuth, which wraps the modular [DEFAULT] app and Auth, and
  is now lazy-loaded with the sign-in form.
- Specs mock the modular functions and assert the document paths.
- Remove addVoteToDb and useFirestoreDocument, which had no callers.

Run the Firestore rules spec on @firebase/rules-unit-testing 3.0.4 (last
line with a `firebase ^10` peer) instead of the deprecated
@firebase/testing. Its firebase@7 tree hoisted @firebase/util@0.3.1, so
npm nested private copies of @firebase/auth, util, ... under every
firebase@10 package; with firebase/auth and firebase/compat/auth both
loaded, the copies failed each other's `instanceof FirebaseError` and
firebaseui reported every sign-in error as auth/network-request-failed.
The re-lock hoists one copy of each, and a spec guards it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	src/admin/users/core/actions/usersActions.ts
@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Preview for 7a6832f (sandbox project open-feedback-hugo, expires in 7 days): https://open-feedback-hugo--pr-1714-gt4mtqts.web.app

@cypress

cypress Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

open-feedback    Run #3159

Run Properties:  status check passed Passed #3159  •  git commit 7a6832f215: Merge branch 'main' of github.com:HugoGresse/open-feedback into firestore-modula...
Project open-feedback
Branch Review firestore-modular-sdk
Run status status check passed Passed #3159
Run duration 02m 15s
Commit git commit 7a6832f215: Merge branch 'main' of github.com:HugoGresse/open-feedback into firestore-modula...
Committer Hugo Gresse
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 1
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 16
View all changes introduced in this branch ↗︎

…tore-modular-sdk

# Conflicts:
#	config/firestore.rules.spec.js

This branch has not been deployed

No deployments
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.

1 participant