Repository navigation
Conversation
tyler-reitz
left a comment
There was a problem hiding this comment.
Requesting changes for one thing, which only shows up together with #839.
Tree-shaking works as described: on Vite 8.3.5 with firebase 12, an auth-only app goes from 240 KB to 82 KB gzipped with no Firestore, Database, Storage or Functions code. The 74 ESM and CJS exports match main, and #835's import-time registration survives "sideEffects": false.
Blocking: rxjs 6 apps. Externalizing rxjs and rxfire splits them: in an rxjs 6.6.7 app, reactfire's code loads a nested rxjs 7.8.2 while rxfire loads the app's 6.6.7, and teardown doesn't cross that boundary. On its own that's invisible, since shareReplay never tears down, but with #839 merged too, useUser and useFirestoreDocData each leak one listener per remount (1,2,3,4,5 after five cycles; 0 on rxjs 7). Making rxjs a ^7.1.0 peer dependency turns this into an install error. Whichever of this and #839 lands first should carry it, plus a !, and the body's "runtime behavior and npm install are unchanged" needs updating for these apps.
Non-blocking: target: es2021 also avoids the tslib chunk and keeps dist at ES2020; es2024 raises it to ES2022 (native class fields), one level above main.
Summary
Previously,
vite.config.tsbundled all ofsrc/*into a single monolithicdist/index.jsthat imported every Firebase product (firebase/firestore,firebase/auth,firebase/database,firebase/storage,firebase/functions,firebase/remote-config,firebase/performance) at the top of one file. Because all product imports lived inside a single pre-bundled chunk, consumer bundlers could not tree-shake unused Firebase SDKs or split them behindReact.lazy.This PR:
preserveModules: true, preserveModulesRoot: 'src', entryFileNames: '[name].js') alongsidedist/index.umd.cjs.rxjs,rxjs/operators, andrxfire/*(declared independencies) so consumer bundlers resolve and tree-shake them directly instead of inlining a duplicate copy."rxjs"independenciesfrom"^6.6.3 || ^7.0.1"to"^7.1.0"so external resolution always provides RxJS ≥ 7.1 (required byshare({ resetOnRefCountZero: () => timer(...) }))."sideEffects": falsetopackage.json."target": "es2024"intsconfig.json(Baseline-certified) so TypeScript does not inject virtual_tslib.jshelper chunks underpreserveModules: true.Bundle Size Impact
Measured with Vite 8.3.5 production builds against
firebase@13.1.0(gzip -9of the emitted application bundle):reactfire@4.2.6(main)preserveModules: true)4.2.6useUser)95,988 B)269,074 B) — bundles Firestore, RTDB, Storage, Perf, Functions, RC103,791 B) — onlyfirebase/auth+rxjs+rxfire/authuseFirestoreCollection)206,792 B)279,049 B) — bundles Auth, RTDB, Storage, Perf, Functions, RC214,541 B) — onlyfirebase/firestore+rxjs+rxfire/firestoreBackwards Compatibility & Release Notes
import * as RF from 'reactfire'(dist/index.js) andrequire('reactfire')(dist/index.umd.cjs) expose the exact same 74 named exports asv4.2.6.package.json"main"(dist/index.umd.cjs),"exports"("." -> { "import": "./dist/index.js", "require": "./dist/index.umd.cjs" }), and"typings"(dist/index.d.ts) are unchanged."sideEffects": false: AllglobalThiscaches (_reactFirePreloadedObservables,_reactFireFirestoreQueryCache,_reactFireDatabaseCachedQueries) are initialized inside the modules that read them (useObservable.ts,firestore.tsx,database.tsx), so dropping an unused product module (e.g.,dist/database.jsordist/performance.js) never drops state needed by used modules.rxjs^7.1.0): Becauserxjsis a regular dependency (andv4.2.6already bundledrxjs@7.8.1), runtime behavior andnpm installare unchanged. However, TypeScript applications still onrxjs@6that pass their own customObservableinstances directly intouseObservableorpreloadObservablewill need to upgrade torxjs@^7.1.0so TypeScript'sObservabletypes match.Closes #489
Closes #488
Refs #480