From 3cebaa921a235d5f56adc9344cf1eddc9c29f0af Mon Sep 17 00:00:00 2001 From: James Daniels Date: Thu, 20 Feb 2020 13:32:37 -0800 Subject: [PATCH] Refactoring use/preload and more (#215) * Drop `initPerformance` (closes #207) * Cleaning up the use/preload types * Use my good friend `Proxy` to allow access to both the `serviceProps` and the initialized instance without double calling (e.g, `useAuth()()`) * More checks against double initializing * Added binding to the initialize call (closes #213) * `SuspenseWithPerf` now lazy loads performance monitoring and uses the user timing API * Fixed the CJS build with a better external test (closes #214) --- reactfire/.npmignore | 1 - reactfire/auth/index.tsx | 4 +- reactfire/firebaseApp/firebaseApp.test.tsx | 19 - reactfire/firebaseApp/index.tsx | 18 +- reactfire/firebaseApp/sdk.tsx | 405 ++++++++++----------- reactfire/firestore/index.tsx | 2 +- reactfire/performance/index.tsx | 38 +- reactfire/performance/performance.test.tsx | 126 +++---- reactfire/remote-config/index.tsx | 2 +- reactfire/rollup.config.js | 12 +- sample/package.json | 3 +- sample/src/Auth.js | 4 +- sample/src/Firestore.js | 8 +- sample/src/RealtimeDatabase.js | 4 +- sample/src/Storage.js | 2 +- sample/src/index.js | 2 +- 16 files changed, 262 insertions(+), 388 deletions(-) diff --git a/reactfire/.npmignore b/reactfire/.npmignore index 954c1245..2de870cd 100644 --- a/reactfire/.npmignore +++ b/reactfire/.npmignore @@ -1,3 +1,2 @@ -cjs/index.esm-* **/*.test.d.ts **/*.test.js \ No newline at end of file diff --git a/reactfire/auth/index.tsx b/reactfire/auth/index.tsx index f91c5a56..9df598a1 100644 --- a/reactfire/auth/index.tsx +++ b/reactfire/auth/index.tsx @@ -13,7 +13,7 @@ import { from } from 'rxjs'; export function preloadUser(firebaseApp: firebase.app.App) { return preloadAuth(firebaseApp).then(auth => { const result = preloadObservable( - user(auth() as firebase.auth.Auth), + user(auth()), `auth:user:${firebaseApp.name}` ); return result.toPromise(); @@ -30,7 +30,7 @@ export function useUser( auth?: auth.Auth, options?: ReactFireOptions ): User | T { - auth = auth || useAuth()(); + auth = auth || useAuth(); const currentUser = auth.currentUser || options?.startWithValue; return useObservable(user(auth), `auth:user:${auth.app.name}`, currentUser); } diff --git a/reactfire/firebaseApp/firebaseApp.test.tsx b/reactfire/firebaseApp/firebaseApp.test.tsx index e43f5908..e3ac4ac5 100644 --- a/reactfire/firebaseApp/firebaseApp.test.tsx +++ b/reactfire/firebaseApp/firebaseApp.test.tsx @@ -29,25 +29,6 @@ describe('FirebaseAppProvider', () => { spy.mockRestore(); }); - it('initializes fireperf if specified', async () => { - const mockPerf = jest.fn(); - firebase['performance' as any] = mockPerf; - const app: firebase.app.App = { performance: mockPerf } as any; - - render(); - - expect(mockPerf).toBeCalled(); - }); - - it('does not initialize fireperf if not specified', async () => { - const mockPerf = jest.fn(); - firebase['performance' as any] = mockPerf; - const app: firebase.app.App = { performance: mockPerf } as any; - - render(); - - expect(mockPerf).not.toBeCalled(); - }); }); describe('useFirebaseApp', () => { diff --git a/reactfire/firebaseApp/index.tsx b/reactfire/firebaseApp/index.tsx index df03183b..8e09c9b1 100644 --- a/reactfire/firebaseApp/index.tsx +++ b/reactfire/firebaseApp/index.tsx @@ -6,14 +6,13 @@ export * from './sdk'; type FirebaseAppContextValue = firebase.app.App; // INVESTIGATE I don't like magic strings, can we have export this in js-sdk? -const DEFAULT_APP_NAME = '[DEFAULT]'; +export const DEFAULT_APP_NAME = '[DEFAULT]'; const FirebaseAppContext = React.createContext< FirebaseAppContextValue | undefined >(undefined); type Props = { - initPerformance?: boolean; firebaseApp?: firebase.app.App; firebaseConfig?: Object; appName?: string; @@ -24,7 +23,7 @@ const shallowEq = (a: Object, b: Object) => [...Object.keys(a), ...Object.keys(b)].every(key => a[key] == b[key]); export function FirebaseAppProvider(props: Props & { [key: string]: unknown }) { - const { firebaseConfig, appName, initPerformance = false } = props; + const { firebaseConfig, appName } = props; const firebaseApp: firebase.app.App = props.firebaseApp || React.useMemo(() => { @@ -43,19 +42,6 @@ export function FirebaseAppProvider(props: Props & { [key: string]: unknown }) { } }, [firebaseConfig, appName]); - React.useMemo(() => { - if (initPerformance === true) { - if (firebaseApp.performance) { - // initialize Performance Monitoring - firebaseApp.performance(); - } else { - throw new Error( - 'firebase.performance not found. Did you forget to import it?' - ); - } - } - }, [initPerformance, firebaseApp]); - return ; } diff --git a/reactfire/firebaseApp/sdk.tsx b/reactfire/firebaseApp/sdk.tsx index 90a67c54..b5b3ae29 100644 --- a/reactfire/firebaseApp/sdk.tsx +++ b/reactfire/firebaseApp/sdk.tsx @@ -1,218 +1,195 @@ -import { useFirebaseApp } from '..'; -import { preloadObservable, useObservable } from '../useObservable'; -import { from } from 'rxjs'; - -type RemoteConfig = import('firebase/app').remoteConfig.RemoteConfig; -type Storage = import('firebase/app').storage.Storage; -type Firestore = import('firebase/app').firestore.Firestore; -type Performance = import('firebase/app').performance.Performance; -type Messaging = import('firebase/app').messaging.Messaging; -type Functions = import('firebase/app').functions.Functions; -type Database = import('firebase/app').database.Database; -type Auth = import('firebase/app').auth.Auth; - -type FirebaseSDK = - | (() => firebase.analytics.Analytics) - | (() => firebase.auth.Auth) - | ((url?: string) => firebase.database.Database) - | (() => firebase.firestore.Firestore) - | ((region?: string) => firebase.functions.Functions) - | (() => firebase.messaging.Messaging) - | (() => firebase.performance.Performance) - | (() => firebase.remoteConfig.RemoteConfig) - | ((url?: string) => firebase.storage.Storage); - -enum SDK { - ANALYTICS = 'analytics', - AUTH = 'auth', - DATABASE = 'database', - FIRESTORE = 'firestore', - FUNCTIONS = 'functions', - MESSAGING = 'messaging', - PERFORMANCE = 'performance', - REMOTE_CONFIG = 'remoteConfig', - STORAGE = 'storage' -} - -function fetchSDK( - sdk: SDK, - firebaseApp: firebase.app.App, - settingsCallback: (sdk: FirebaseSDK) => Promise | void = () => - Promise.resolve() -) { - if (!firebaseApp) { - throw new Error('Firebase app was not provided'); +import { DEFAULT_APP_NAME } from '../index'; +import { useFirebaseApp } from '.'; +import * as firebase from 'firebase/app'; + +type ComponentName = + | 'analytics' + | 'auth' + | 'database' + | 'firestore' + | 'functions' + | 'messaging' + | 'performance' + | 'remoteConfig' + | 'storage'; + +type ValueOf = T[keyof T]; +type App = firebase.app.App; +type FirebaseInstanceFactory = ValueOf>; +type FirebaseNamespaceComponent = ValueOf>; + +function importSDK(sdk: ComponentName) { + switch (sdk) { + case 'analytics': + return import(/* webpackChunkName: "analytics" */ 'firebase/analytics'); + case 'auth': + return import(/* webpackChunkName: "auth" */ 'firebase/auth'); + case 'database': + return import(/* webpackChunkName: "database" */ 'firebase/database'); + case 'firestore': + return import(/* webpackChunkName: "firestore" */ 'firebase/firestore'); + case 'functions': + return import(/* webpackChunkName: "functions" */ 'firebase/functions'); + case 'messaging': + return import(/* webpackChunkName: "messaging" */ 'firebase/messaging'); + case 'performance': + return import( + /* webpackChunkName: "performance" */ 'firebase/performance' + ); + case 'remoteConfig': + return import( + /* webpackChunkName: "remoteConfig" */ 'firebase/remote-config' + ); + case 'storage': + return import(/* webpackChunkName: "storage" */ 'firebase/storage'); } +} - let sdkPromise: Promise; - - if (firebaseApp[sdk]) { - // Don't apply settings here. Only needed for lazy loaded SDKs. - // If not lazy loaded, user can provide settings as normal - sdkPromise = Promise.resolve(firebaseApp[sdk]); - } else { - switch (sdk) { - case SDK.ANALYTICS: - sdkPromise = import( - /* webpackChunkName: "analytics" */ 'firebase/analytics' - ); - break; - case SDK.AUTH: - sdkPromise = import(/* webpackChunkName: "auth" */ 'firebase/auth'); - break; - case SDK.DATABASE: - sdkPromise = import( - /* webpackChunkName: "database" */ 'firebase/database' - ); - break; - case SDK.FIRESTORE: - sdkPromise = import( - /* webpackChunkName: "firestore" */ 'firebase/firestore' - ); - break; - case SDK.FUNCTIONS: - sdkPromise = import( - /* webpackChunkName: "functions" */ 'firebase/functions' - ); - break; - case SDK.MESSAGING: - sdkPromise = import( - /* webpackChunkName: "messaging" */ 'firebase/messaging' - ); - break; - case SDK.PERFORMANCE: - sdkPromise = import( - /* webpackChunkName: "performance" */ 'firebase/performance' - ); - break; - case SDK.REMOTE_CONFIG: - sdkPromise = import( - /* webpackChunkName: "remoteConfig" */ 'firebase/remote-config' - ); - break; - case SDK.STORAGE: - sdkPromise = import( - /* webpackChunkName: "storage" */ 'firebase/storage' +function proxyComponent(componentName: 'auth'): typeof firebase.auth; +function proxyComponent(componentName: 'analytics'): typeof firebase.analytics; +function proxyComponent(componentName: 'database'): typeof firebase.database; +function proxyComponent(componentName: 'firestore'): typeof firebase.firestore; +function proxyComponent(componentName: 'functions'): typeof firebase.functions; +function proxyComponent(componentName: 'messaging'): typeof firebase.messaging; +function proxyComponent( + componentName: 'performance' +): typeof firebase.performance; +function proxyComponent( + componentName: 'remoteConfig' +): typeof firebase.remoteConfig; +function proxyComponent(componentName: 'storage'): typeof firebase.storage; +function proxyComponent( + componentName: ComponentName +): FirebaseNamespaceComponent { + let contextualApp: App | undefined; + const useComponent = () => { + contextualApp = useFirebaseApp(); + if (!firebase[componentName]) { + throw importSDK(componentName); + } + return firebase[componentName]; + }; + return new Proxy(useComponent, { + get: (target, p) => target()[p], + apply: (target, _this, args) => { + const component = target().bind(_this); + // If they don't pass an app, assume the app in context rather than [DEFAULT] + if (!args[0]) { + args[0] = contextualApp; + } + return component(...args); + } + }) as any; +} + +export const useAuth = proxyComponent('auth'); +export const useAnalytics = proxyComponent('analytics'); +export const useDatabase = proxyComponent('database'); +export const useFirestore = proxyComponent('firestore'); +export const useFunctions = proxyComponent('functions'); +export const useMessaging = proxyComponent('messaging'); +export const usePerformance = proxyComponent('performance'); +export const useRemoteConfig = proxyComponent('remoteConfig'); +export const useStorage = proxyComponent('storage'); + +export const auth = useAuth; +export const analytics = useAnalytics; +export const database = useDatabase; +export const firestore = useFirestore; +export const functions = useFunctions; +export const messaging = useMessaging; +export const performance = usePerformance; +export const remoteConfig = useRemoteConfig; +export const storage = useStorage; + +function preload( + componentName: 'auth' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['auth']) => any +) => Promise; +function preload( + componentName: 'analytics' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['analytics']) => any +) => Promise; +function preload( + componentName: 'database' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['database']) => any +) => Promise; +function preload( + componentName: 'firestore' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['firestore']) => any +) => Promise; +function preload( + componentName: 'functions' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['functions']) => any +) => Promise; +function preload( + componentName: 'messaging' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['messaging']) => any +) => Promise; +function preload( + componentName: 'performance' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['performance']) => any +) => Promise; +function preload( + componentName: 'remoteConfig' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['remoteConfig']) => any +) => Promise; +function preload( + componentName: 'storage' +): ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: App['storage']) => any +) => Promise; +function preload(componentName: ComponentName) { + return async ( + firebaseApp?: App, + settingsCallback?: (instanceFactory: FirebaseInstanceFactory) => any + ) => { + const app = firebaseApp || useFirebaseApp(); + const initialized = !!app[componentName]; + if (!initialized) { + await importSDK(componentName); + } + const instanceFactory = app[componentName].bind( + app + ) as FirebaseInstanceFactory; + if (initialized) { + if (settingsCallback) { + console.warn( + `${componentName} was already initialized on ${ + app.name == DEFAULT_APP_NAME ? 'the default app' : app.name + }, ignoring settingsCallback` ); - break; + } + } else if (settingsCallback) { + await Promise.resolve(settingsCallback(instanceFactory)); } - sdkPromise = sdkPromise - .then(() => settingsCallback(firebaseApp[sdk])) - .then(() => firebaseApp[sdk]); - } - preloadObservable( - from(sdkPromise), - `firebase:sdk-${sdk}:${firebaseApp.name}` - ); - - return sdkPromise; -} - -function useSDK(sdk: SDK, firebaseApp?: firebase.app.App) { - firebaseApp = firebaseApp || useFirebaseApp(); - - // use the request cache so we don't issue multiple fetches for the sdk - return useObservable( - from(fetchSDK(sdk, firebaseApp)), - `firebase:sdk-${sdk}:${firebaseApp.name}` - ); -} - -export function preloadAuth( - firebaseApp: firebase.app.App, - settingsCallback?: (auth: () => Auth) => void -) { - return fetchSDK(SDK.AUTH, firebaseApp, settingsCallback); -} - -export function useAuth(firebaseApp?: firebase.app.App) { - return useSDK(SDK.AUTH, firebaseApp) as () => firebase.auth.Auth; -} - -export function preloadAnalytics(firebaseApp: firebase.app.App) { - return fetchSDK(SDK.ANALYTICS, firebaseApp); -} - -export function useAnalytics(firebaseApp?: firebase.app.App) { - return useSDK(SDK.ANALYTICS, firebaseApp); -} - -export function preloadDatabase( - firebaseApp: firebase.app.App, - settingsCallback?: (database: () => Database) => void -) { - return fetchSDK(SDK.DATABASE, firebaseApp, settingsCallback); -} - -export function useDatabase(firebaseApp?: firebase.app.App) { - return useSDK(SDK.DATABASE, firebaseApp); -} - -export function preloadFirestore( - firebaseApp: firebase.app.App, - settingsCallback?: (firestore: () => Firestore) => Promise -) { - return fetchSDK(SDK.FIRESTORE, firebaseApp, settingsCallback); -} - -export function useFirestore(firebaseApp?: firebase.app.App) { - return useSDK(SDK.FIRESTORE, firebaseApp); -} - -export function preloadFunctions( - firebaseApp?: firebase.app.App, - settingsCallback?: (functions: () => Functions) => void -) { - return fetchSDK(SDK.FUNCTIONS, firebaseApp, settingsCallback); -} - -export function useFunctions(firebaseApp?: firebase.app.App) { - return useSDK(SDK.FUNCTIONS, firebaseApp); -} - -export function preloadMessaging( - firebaseApp: firebase.app.App, - settingsCallback?: (messaging: () => Messaging) => void -) { - return fetchSDK(SDK.MESSAGING, firebaseApp, settingsCallback); -} - -export function useMessaging(firebaseApp?: firebase.app.App) { - return useSDK(SDK.MESSAGING, firebaseApp); -} - -export function preloadPerformance( - firebaseApp: firebase.app.App, - settingsCallback?: (performance: () => Performance) => void -) { - return fetchSDK(SDK.PERFORMANCE, firebaseApp, settingsCallback); -} - -export function usePerformance(firebaseApp?: firebase.app.App) { - return useSDK(SDK.PERFORMANCE, firebaseApp); -} - -export function preloadRemoteConfig( - firebaseApp: firebase.app.App, - settingsCallback?: (remoteConfig: () => RemoteConfig) => Promise -) { - return fetchSDK(SDK.REMOTE_CONFIG, firebaseApp, settingsCallback); -} - -export function useRemoteConfig(firebaseApp?: firebase.app.App) { - return useSDK( - SDK.REMOTE_CONFIG, - firebaseApp - ) as () => firebase.remoteConfig.RemoteConfig; -} - -export function preloadStorage( - firebaseApp: firebase.app.App, - settingsCallback: (storage: () => Storage) => Promise -) { - return fetchSDK(SDK.STORAGE, firebaseApp, settingsCallback); -} - -export function useStorage(firebaseApp?: firebase.app.App) { - return useSDK(SDK.STORAGE, firebaseApp); -} + return instanceFactory; + }; +} + +export const preloadAuth = preload('auth'); +export const preloadAnalytics = preload('analytics'); +export const preloadDatabase = preload('database'); +export const preloadFirestore = preload('firestore'); +export const preloadFunctions = preload('functions'); +export const preloadMessaging = preload('messaging'); +export const preloadPerformance = preload('performance'); +export const preloadRemoteConfig = preload('remoteConfig'); +export const preloadStorage = preload('storage'); diff --git a/reactfire/firestore/index.tsx b/reactfire/firestore/index.tsx index 0b3e7d9a..11aac72e 100644 --- a/reactfire/firestore/index.tsx +++ b/reactfire/firestore/index.tsx @@ -28,7 +28,7 @@ export function preloadFirestoreDoc( firebaseApp: firebase.app.App ) { return preloadFirestore(firebaseApp).then(firestore => { - const ref = refProvider(firestore() as firebase.firestore.Firestore); + const ref = refProvider(firestore()); return preloadObservable( doc(ref), `firestore:doc:${ref.firestore.app.name}:${ref.path}` diff --git a/reactfire/performance/index.tsx b/reactfire/performance/index.tsx index 843d381d..cf92ec04 100644 --- a/reactfire/performance/index.tsx +++ b/reactfire/performance/index.tsx @@ -1,31 +1,11 @@ -import { performance } from 'firebase/app'; import * as React from 'react'; -import { useFirebaseApp } from '..'; +import { preloadPerformance } from '../firebaseApp'; export interface SuspensePerfProps { children: React.ReactNode; traceId: string; fallback: React.ReactNode; - firePerf?: performance.Performance; -} - -function getPerfFromContext(): performance.Performance { - const firebaseApp = useFirebaseApp(); - if (!firebaseApp) { - throw new Error( - 'Firebase not found in context. Either pass it directly to a reactfire hook, or wrap your component in a FirebaseAppProvider' - ); - } - - const perfFunc = firebaseApp.performance; - - if (!perfFunc || !perfFunc()) { - throw new Error( - "No perf object off of Firebase. Did you forget to import 'firebase/performance' in a component?" - ); - } - - return perfFunc(); + firePerf?: import('firebase/app').performance.Performance; } export function SuspenseWithPerf({ @@ -34,15 +14,21 @@ export function SuspenseWithPerf({ fallback, firePerf }: SuspensePerfProps): JSX.Element { - firePerf = firePerf || getPerfFromContext(); + if (!firePerf) { + preloadPerformance().then(perf => perf()); + } + + const entries = performance?.getEntriesByName(traceId, 'measure') || []; + const startMarkName = `_${traceId}Start[${entries.length}]`; + const endMarkName = `_${traceId}End[${entries.length}]`; const Fallback = () => { React.useLayoutEffect(() => { - const trace = firePerf.trace(traceId); - trace.start(); + performance?.mark(startMarkName); return () => { - trace.stop(); + performance?.mark(endMarkName); + performance?.measure(traceId, startMarkName, endMarkName); }; }, [traceId]); diff --git a/reactfire/performance/performance.test.tsx b/reactfire/performance/performance.test.tsx index c977ded4..e966e87f 100644 --- a/reactfire/performance/performance.test.tsx +++ b/reactfire/performance/performance.test.tsx @@ -1,5 +1,4 @@ import { act, cleanup, render, waitForElement } from '@testing-library/react'; -import { performance } from 'firebase/app'; import '@testing-library/jest-dom/extend-expect'; import * as React from 'react'; import { Subject } from 'rxjs'; @@ -14,14 +13,22 @@ const createTrace = jest.fn(() => ({ stop: traceEnd })); -const mockPerf = jest.fn(() => { +const mockPerf = (jest.fn(() => { return { trace: createTrace }; -}); +}) as any) as () => firebase.performance.Performance; const mockFirebase: firebase.app.App = { performance: mockPerf } as any; +const mark = jest.fn(); +const measure = jest.fn(); +const getEntriesByName = jest.fn(() => []); + +window.performance.mark = mark; +window.performance.measure = measure; +window.performance.getEntriesByName = getEntriesByName; + const PromiseThrower = () => { throw new Promise((resolve, reject) => {}); return

Hello world

; @@ -61,7 +68,11 @@ describe('SuspenseWithPerf', () => { const SuspenseWithPerfComp = () => { return ( - } traceId="test"> + } + traceId="test" + firePerf={mockPerf()} + > @@ -90,13 +101,18 @@ describe('SuspenseWithPerf', () => { render( - + ); - expect(createTrace).toHaveBeenCalledWith(traceName); + expect(mark).toBeCalledWith('_traceStart[0]'); + expect(mark).toHaveBeenCalledTimes(1); }); it('starts a trace when a promise is thrown and stops when it resolves', async () => { @@ -122,7 +138,11 @@ describe('SuspenseWithPerf', () => { const { getByTestId } = render( - } traceId="test lifecycle"> + } + traceId="test lifecycle" + firePerf={mockPerf()} + > @@ -130,17 +150,26 @@ describe('SuspenseWithPerf', () => { expect(getByTestId('fallback')).toBeInTheDocument(); - expect(traceStart).toHaveBeenCalledTimes(1); - expect(traceEnd).toHaveBeenCalledTimes(0); + expect(mark).toBeCalledWith('_test lifecycleStart[0]'); + expect(mark).toHaveBeenCalledTimes(1); + expect(measure).toHaveBeenCalledTimes(0); act(() => o$.next('a')); await waitForElement(() => getByTestId('child')); expect(getByTestId('child')).toBeInTheDocument(); - expect(traceStart).toHaveBeenCalledTimes(1); - expect(traceEnd).toHaveBeenCalledTimes(1); + expect(mark).toBeCalledWith('_test lifecycleEnd[0]'); + expect(mark).toHaveBeenCalledTimes(2); + expect(measure).toHaveBeenCalledTimes(1); + expect(measure).toHaveBeenCalledWith( + 'test lifecycle', + '_test lifecycleStart[0]', + '_test lifecycleEnd[0]' + ); }); + it.todo('can find fireperf from Context'); + /* it('can find fireperf from Context', () => { render( @@ -152,78 +181,5 @@ describe('SuspenseWithPerf', () => { expect(mockPerf).toHaveBeenCalled(); }); - - it('can use firePerf from props', () => { - const propPerf = mockPerf(); - propPerf.trace = jest.fn(() => ({ - start: traceStart, - stop: traceEnd - })); - render( - - - - ); - - // call the createTrace provided, not the one in context - expect(propPerf.trace).toHaveBeenCalled(); - expect(createTrace).not.toHaveBeenCalled(); - }); - - it('Does not reuse a trace object', async () => { - // traces throw if you call start() twice, - // even if you've called stop() in between: - // https://github.com/firebase/firebase-js-sdk/blob/dd098c6a87f23ddf54a7f9b21b87f7bb3fd56bdd/packages/performance/src/resources/trace.test.ts#L52 - // - // this test covers the scenario where a component - // is rendered, and uses suspenseWithPerf, is then - // hidden, and then re-rendered, triggering another - // suspenseWithPerf - // - // I ran into this when I loaded a site while logged - // in, rendering a component that used a reactfire hook, - // then logged out, hiding that component. When I logged - // back in without reloading the page, perfmon threw an error - // because SuspenseWithPerf tried to reuse a trace. - - const o$ = new Subject(); - - const Comp = () => { - const val = useObservable(o$, 'perf-test-2'); - - if (val === 'throw') { - throw new Promise(() => {}); - } - - return

Actual

; - }; - - const Component = () => { - return ( - - - - ); - }; - - // render SuspenseWithPerf and go through normal trace start -> trace stop - const { getByTestId, rerender } = render(); - expect(createTrace).toHaveBeenCalledTimes(1); - act(() => o$.next('some value')); - await waitForElement(() => getByTestId('child')); - - // this is a magic value that will cause the child to throw a Promise again - act(() => o$.next('throw')); - - // if createTrace is only called once, the firebase SDK will throw - expect(createTrace).toHaveBeenCalledTimes(2); - }); +*/ }); diff --git a/reactfire/remote-config/index.tsx b/reactfire/remote-config/index.tsx index b09fdccf..f16d7e71 100644 --- a/reactfire/remote-config/index.tsx +++ b/reactfire/remote-config/index.tsx @@ -32,7 +32,7 @@ function typeSafeUse( getter: Getter$, remoteConfig?: RemoteConfig ): T { - remoteConfig = remoteConfig || useRemoteConfig()(); + remoteConfig = remoteConfig || useRemoteConfig(); // INVESTIGATE need to use a public API to get at the app name, one doesn't appear to exist... // we might need to iterate over the Firebase apps and check for remoteConfig equality? this works for now const appName = (remoteConfig as RemoteConfigWithPrivate)._storage?.appName; diff --git a/reactfire/rollup.config.js b/reactfire/rollup.config.js index ea656c44..f0d4c25f 100644 --- a/reactfire/rollup.config.js +++ b/reactfire/rollup.config.js @@ -7,16 +7,6 @@ export default { format: 'cjs', name: 'reactfire' }, - external: [ - 'react', - 'firebase/app', - 'rxfire/auth', - 'rxfire/database', - 'rxfire/firestore', - 'rxfire/storage', - 'rxjs', - 'rxjs/operators', - 'tslib' - ], + external: id => !id.startsWith('.'), plugins: [resolve()] }; diff --git a/sample/package.json b/sample/package.json index 56fd114b..21d40576 100644 --- a/sample/package.json +++ b/sample/package.json @@ -8,8 +8,7 @@ "react": "0.0.0-experimental-f42431abe", "react-dom": "0.0.0-experimental-f42431abe", "react-firebaseui": "^4.0.0", - "react-scripts": "3.3.0", - "reactfire": "2.0.0" + "react-scripts": "3.3.0" }, "scripts": { "start": "react-scripts start", diff --git a/sample/src/Auth.js b/sample/src/Auth.js index a09b06ff..8d38ab4e 100644 --- a/sample/src/Auth.js +++ b/sample/src/Auth.js @@ -3,7 +3,7 @@ import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth'; import { SuspenseWithPerf, useUser, useAuth } from 'reactfire'; const signOut = auth => - auth() + auth .signOut() .then(() => console.log('signed out')); @@ -25,7 +25,7 @@ const UserDetails = ({ user }) => { }; const SignInForm = () => { - const auth = useAuth(); + const auth = useAuth; const uiConfig = { signInFlow: 'popup', diff --git a/sample/src/Firestore.js b/sample/src/Firestore.js index 282c641d..4267abf0 100644 --- a/sample/src/Firestore.js +++ b/sample/src/Firestore.js @@ -10,8 +10,8 @@ import { } from 'reactfire'; const Counter = props => { - const firestore = useFirestore(); - + const firestore = useFirestore; + const serverIncrement = firestore.FieldValue.increment; const ref = firestore().doc('count/counter'); @@ -36,7 +36,7 @@ const Counter = props => { const StaticValue = props => { const firestore = useFirestore(); - const ref = firestore().doc('count/counter'); + const ref = firestore.doc('count/counter'); const { value } = useFirestoreDocDataOnce(ref); @@ -86,7 +86,7 @@ const List = ({ query, removeAnimal }) => { const FavoriteAnimals = props => { const firestore = useFirestore(); - const baseRef = firestore().collection('animals'); + const baseRef = firestore.collection('animals'); const [isAscending, setIsAscending] = useState(true); const query = baseRef.orderBy('commonName', isAscending ? 'asc' : 'desc'); const [startTransition, isPending] = useTransition({ diff --git a/sample/src/RealtimeDatabase.js b/sample/src/RealtimeDatabase.js index 3c64dcdf..85025bfd 100644 --- a/sample/src/RealtimeDatabase.js +++ b/sample/src/RealtimeDatabase.js @@ -9,7 +9,7 @@ import { const Counter = props => { const database = useDatabase(); - const ref = database().ref('counter'); + const ref = database.ref('counter'); const increment = amountToIncrement => { ref.transaction(counterVal => { return counterVal + amountToIncrement; @@ -56,7 +56,7 @@ const AnimalEntry = ({ saveAnimal }) => { const List = props => { const database = useDatabase(); - const ref = database().ref('animals'); + const ref = database.ref('animals'); const animals = useDatabaseListData(ref, { idField: 'id' }); const addNewAnimal = commonName => { diff --git a/sample/src/Storage.js b/sample/src/Storage.js index 4ba8b96a..907b9175 100644 --- a/sample/src/Storage.js +++ b/sample/src/Storage.js @@ -27,7 +27,7 @@ const ImageUploadButton = props => { const fileList = event.target.files; const fileToUpload = fileList[0]; const fileName = fileToUpload.name; - const newRef = storage() + const newRef = storage .ref('images') .child(fileName); setRef(newRef); diff --git a/sample/src/index.js b/sample/src/index.js index 303030cd..24f81b0f 100644 --- a/sample/src/index.js +++ b/sample/src/index.js @@ -18,7 +18,7 @@ const config = { ReactDOM.createRoot(document.getElementById('root')).render( - +