|
1 | | -import { DEFAULT_APP_NAME } from '../index'; |
2 | 1 | import { useFirebaseApp } from '.'; |
3 | 2 | import * as firebase from 'firebase/app'; |
| 3 | +import { Observable } from 'rxjs'; |
| 4 | +import { preloadObservable } from '../useObservable'; |
4 | 5 |
|
5 | 6 | type ComponentName = |
6 | 7 | | 'analytics' |
@@ -62,17 +63,19 @@ function proxyComponent( |
62 | 63 | componentName: ComponentName |
63 | 64 | ): FirebaseNamespaceComponent { |
64 | 65 | let contextualApp: App | undefined; |
65 | | - const useComponent = () => { |
| 66 | + const useComponent = (app?: App) => { |
66 | 67 | contextualApp = useFirebaseApp(); |
67 | | - if (!firebase[componentName]) { |
68 | | - throw importSDK(componentName); |
| 68 | + const sdkSubject = preload(componentName, app || contextualApp); |
| 69 | + if (!sdkSubject.hasValue) { |
| 70 | + throw sdkSubject.firstEmission; |
69 | 71 | } |
| 72 | + sdkSubject.value; // get value to throw if there's an error |
70 | 73 | return firebase[componentName]; |
71 | 74 | }; |
72 | 75 | return new Proxy(useComponent, { |
73 | 76 | get: (target, p) => target()[p], |
74 | 77 | apply: (target, _this, args) => { |
75 | | - const component = target().bind(_this); |
| 78 | + const component = target(args[0]).bind(_this); |
76 | 79 | // If they don't pass an app, assume the app in context rather than [DEFAULT] |
77 | 80 | if (!args[0]) { |
78 | 81 | args[0] = contextualApp; |
@@ -102,94 +105,100 @@ export const performance = usePerformance; |
102 | 105 | export const remoteConfig = useRemoteConfig; |
103 | 106 | export const storage = useStorage; |
104 | 107 |
|
105 | | -function preload( |
| 108 | +function preloadFactory( |
106 | 109 | componentName: 'auth' |
107 | 110 | ): ( |
108 | 111 | firebaseApp?: App, |
109 | | - settingsCallback?: (instanceFactory: App['auth']) => any |
| 112 | + settingsCallback?: (instanceFactory: App['auth']) => void | Promise<any> |
110 | 113 | ) => Promise<App['auth']>; |
111 | | -function preload( |
| 114 | +function preloadFactory( |
112 | 115 | componentName: 'analytics' |
113 | 116 | ): ( |
114 | 117 | firebaseApp?: App, |
115 | | - settingsCallback?: (instanceFactory: App['analytics']) => any |
| 118 | + settingsCallback?: (instanceFactory: App['analytics']) => void | Promise<any> |
116 | 119 | ) => Promise<App['analytics']>; |
117 | | -function preload( |
| 120 | +function preloadFactory( |
118 | 121 | componentName: 'database' |
119 | 122 | ): ( |
120 | 123 | firebaseApp?: App, |
121 | | - settingsCallback?: (instanceFactory: App['database']) => any |
| 124 | + settingsCallback?: (instanceFactory: App['database']) => void | Promise<any> |
122 | 125 | ) => Promise<App['database']>; |
123 | | -function preload( |
| 126 | +function preloadFactory( |
124 | 127 | componentName: 'firestore' |
125 | 128 | ): ( |
126 | 129 | firebaseApp?: App, |
127 | | - settingsCallback?: (instanceFactory: App['firestore']) => any |
| 130 | + settingsCallback?: (instanceFactory: App['firestore']) => void | Promise<any> |
128 | 131 | ) => Promise<App['firestore']>; |
129 | | -function preload( |
| 132 | +function preloadFactory( |
130 | 133 | componentName: 'functions' |
131 | 134 | ): ( |
132 | 135 | firebaseApp?: App, |
133 | | - settingsCallback?: (instanceFactory: App['functions']) => any |
| 136 | + settingsCallback?: (instanceFactory: App['functions']) => void | Promise<any> |
134 | 137 | ) => Promise<App['functions']>; |
135 | | -function preload( |
| 138 | +function preloadFactory( |
136 | 139 | componentName: 'messaging' |
137 | 140 | ): ( |
138 | 141 | firebaseApp?: App, |
139 | | - settingsCallback?: (instanceFactory: App['messaging']) => any |
| 142 | + settingsCallback?: (instanceFactory: App['messaging']) => void | Promise<any> |
140 | 143 | ) => Promise<App['messaging']>; |
141 | | -function preload( |
| 144 | +function preloadFactory( |
142 | 145 | componentName: 'performance' |
143 | 146 | ): ( |
144 | 147 | firebaseApp?: App, |
145 | | - settingsCallback?: (instanceFactory: App['performance']) => any |
| 148 | + settingsCallback?: (instanceFactory: App['performance']) => void | Promise<any> |
146 | 149 | ) => Promise<App['performance']>; |
147 | | -function preload( |
| 150 | +function preloadFactory( |
148 | 151 | componentName: 'remoteConfig' |
149 | 152 | ): ( |
150 | 153 | firebaseApp?: App, |
151 | | - settingsCallback?: (instanceFactory: App['remoteConfig']) => any |
| 154 | + settingsCallback?: (instanceFactory: App['remoteConfig']) => void | Promise<any> |
152 | 155 | ) => Promise<App['remoteConfig']>; |
153 | | -function preload( |
| 156 | +function preloadFactory( |
154 | 157 | componentName: 'storage' |
155 | 158 | ): ( |
156 | 159 | firebaseApp?: App, |
157 | | - settingsCallback?: (instanceFactory: App['storage']) => any |
| 160 | + settingsCallback?: (instanceFactory: App['storage']) => void | Promise<any> |
158 | 161 | ) => Promise<App['storage']>; |
159 | | -function preload(componentName: ComponentName) { |
160 | | - return async ( |
| 162 | +function preloadFactory(componentName: ComponentName) { |
| 163 | + return ( |
161 | 164 | firebaseApp?: App, |
162 | 165 | settingsCallback?: (instanceFactory: FirebaseInstanceFactory) => any |
163 | | - ) => { |
164 | | - const app = firebaseApp || useFirebaseApp(); |
165 | | - const initialized = !!app[componentName]; |
166 | | - if (!initialized) { |
167 | | - await importSDK(componentName); |
168 | | - } |
169 | | - const instanceFactory = app[componentName].bind( |
170 | | - app |
171 | | - ) as FirebaseInstanceFactory; |
172 | | - if (initialized) { |
173 | | - if (settingsCallback) { |
174 | | - console.warn( |
175 | | - `${componentName} was already initialized on ${ |
176 | | - app.name == DEFAULT_APP_NAME ? 'the default app' : app.name |
177 | | - }, ignoring settingsCallback` |
178 | | - ); |
179 | | - } |
180 | | - } else if (settingsCallback) { |
181 | | - await Promise.resolve(settingsCallback(instanceFactory)); |
182 | | - } |
183 | | - return instanceFactory; |
184 | | - }; |
| 166 | + ) => preload(componentName, firebaseApp, settingsCallback).toPromise(); |
| 167 | +} |
| 168 | + |
| 169 | +function preload( |
| 170 | + componentName: ComponentName, |
| 171 | + firebaseApp?: App, |
| 172 | + settingsCallback: (instanceFactory: FirebaseInstanceFactory) => any = () => {} |
| 173 | +) { |
| 174 | + const app = firebaseApp || useFirebaseApp(); |
| 175 | + return preloadObservable( |
| 176 | + new Observable(emitter => { |
| 177 | + importSDK(componentName) |
| 178 | + .then(() => { |
| 179 | + const instanceFactory = app[componentName].bind( |
| 180 | + app |
| 181 | + ) as FirebaseInstanceFactory; |
| 182 | + Promise.resolve(settingsCallback(instanceFactory)).then(() => { |
| 183 | + emitter.next(instanceFactory); |
| 184 | + emitter.complete(); |
| 185 | + }); |
| 186 | + }) |
| 187 | + .catch(e => { |
| 188 | + emitter.error(e); |
| 189 | + emitter.complete(); |
| 190 | + }); |
| 191 | + }), |
| 192 | + `firebase-sdk:${componentName}:${app.name}` |
| 193 | + ); |
185 | 194 | } |
186 | 195 |
|
187 | | -export const preloadAuth = preload('auth'); |
188 | | -export const preloadAnalytics = preload('analytics'); |
189 | | -export const preloadDatabase = preload('database'); |
190 | | -export const preloadFirestore = preload('firestore'); |
191 | | -export const preloadFunctions = preload('functions'); |
192 | | -export const preloadMessaging = preload('messaging'); |
193 | | -export const preloadPerformance = preload('performance'); |
194 | | -export const preloadRemoteConfig = preload('remoteConfig'); |
195 | | -export const preloadStorage = preload('storage'); |
| 196 | +export const preloadAuth = preloadFactory('auth'); |
| 197 | +export const preloadAnalytics = preloadFactory('analytics'); |
| 198 | +export const preloadDatabase = preloadFactory('database'); |
| 199 | +export const preloadFirestore = preloadFactory('firestore'); |
| 200 | +export const preloadFunctions = preloadFactory('functions'); |
| 201 | +export const preloadMessaging = preloadFactory('messaging'); |
| 202 | +export const preloadPerformance = preloadFactory('performance'); |
| 203 | +export const preloadRemoteConfig = preloadFactory('remoteConfig'); |
| 204 | +export const preloadStorage = preloadFactory('storage'); |
0 commit comments