Skip to content

Commit 7d94183

Browse files
committed
fix(auth): allow treeshaking with explicit initialization
Fix #1459
1 parent a013306 commit 7d94183

File tree

4 files changed

+112
-19
lines changed

4 files changed

+112
-19
lines changed

playground/src/main.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ import { createFirebaseApp } from './firebase'
1313
import { createWebHistory, createRouter } from 'vue-router/auto'
1414
import { createStore } from 'vuex'
1515
import { ReCaptchaV3Provider } from 'firebase/app-check'
16+
import { VueFireAuthWithDependencies } from '../../src/auth'
17+
import {
18+
browserLocalPersistence,
19+
browserPopupRedirectResolver,
20+
indexedDBLocalPersistence,
21+
} from 'firebase/auth'
1622

1723
const router = createRouter({
1824
history: createWebHistory(),
@@ -43,7 +49,16 @@ app
4349
.use(VueFire, {
4450
firebaseApp: createFirebaseApp(),
4551
modules: [
46-
VueFireAuth(),
52+
VueFireAuthWithDependencies({
53+
dependencies: {
54+
popupRedirectResolver: browserPopupRedirectResolver,
55+
persistence: [
56+
indexedDBLocalPersistence,
57+
browserLocalPersistence,
58+
// browserSessionPersistence,
59+
],
60+
},
61+
}),
4762
VueFireAppCheck({
4863
debug: process.env.NODE_ENV !== 'production',
4964
isTokenAutoRefreshEnabled: true,

src/auth/index.ts

Lines changed: 92 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
import type { FirebaseApp } from 'firebase/app'
2-
import { getAuth, type User } from 'firebase/auth'
3-
import { App, ref } from 'vue-demi'
2+
import {
3+
type Dependencies as AuthDependencies,
4+
initializeAuth,
5+
type User,
6+
browserPopupRedirectResolver,
7+
browserLocalPersistence,
8+
browserSessionPersistence,
9+
indexedDBLocalPersistence,
10+
Auth,
11+
} from 'firebase/auth'
12+
import { type App, ref, inject } from 'vue-demi'
413
import { useFirebaseApp } from '../app'
514
import { getGlobalScope } from '../globals'
615
import { isClient, _Nullable } from '../shared'
716
import { authUserMap, setupOnAuthStateChanged } from './user'
17+
import { type VueFireModule } from '..'
818

919
export {
1020
useCurrentUser,
@@ -15,28 +25,80 @@ export {
1525
} from './user'
1626

1727
/**
18-
* VueFire Auth Module to be added to the `VueFire` Vue plugin options.
28+
* Options for VueFire Auth module.
29+
*/
30+
export interface VueFireAuthOptions {
31+
/**
32+
* Initial value of the user. Used during SSR.
33+
*/
34+
initialUser?: _Nullable<User>
35+
36+
/**
37+
* Options to pass to `initializeAuth()`.
38+
*/
39+
dependencies: AuthDependencies
40+
}
41+
42+
/**
43+
* VueFire Auth Module to be added to the `VueFire` Vue plugin options. This calls the `VueFireAuthWithDependencies()`
44+
* with **all** the dependencies, increasing bundle size. Consider using `VueFireAuthWithDependencies()` instead to
45+
* better control the bundle size.
46+
*
47+
* @see https://firebase.google.com/docs/auth/web/custom-dependencies
1948
*
2049
* @example
2150
*
22-
* ```ts
23-
* import { createApp } from 'vue'
24-
* import { VueFire, VueFireAuth } from 'vuefire'
51+
*```ts
52+
*import { createApp } from 'vue'
53+
*import { VueFire, VueFireAuth } from 'vuefire'
54+
*
55+
*const app = createApp(App)
56+
*app.use(VueFire, {
57+
* modules: [VueFireAuth()],
58+
*})
59+
*```
60+
*
61+
* @param initialUser - initial value of the user. used for SSR
62+
*/
63+
export function VueFireAuth(initialUser?: _Nullable<User>): VueFireModule {
64+
return VueFireAuthWithDependencies({
65+
initialUser,
66+
dependencies: {
67+
popupRedirectResolver: browserPopupRedirectResolver,
68+
persistence: [
69+
indexedDBLocalPersistence,
70+
browserLocalPersistence,
71+
browserSessionPersistence,
72+
],
73+
},
74+
})
75+
}
76+
77+
/**
78+
* Key to be used to inject the auth instance into components. It allows avoiding to call `getAuth()`, which isn't tree
79+
* shakable.
80+
*/
81+
export const _VueFireAuthKey = Symbol('VueFireAuth')
82+
83+
/**
84+
* VueFire Auth Module to be added to the `VueFire` Vue plugin options. It accepts dependencies to pass to
85+
* `initializeAuth()` to better control the bundle size.
2586
*
26-
* const app = createApp(App)
27-
* app.use(VueFire, {
28-
* modules: [VueFireAuth()],
29-
* })
30-
* ```
87+
* @param options - user and options to pass to `initializeAuth()`.
3188
*/
32-
export function VueFireAuth(initialUser?: _Nullable<User>) {
89+
export function VueFireAuthWithDependencies({
90+
dependencies,
91+
initialUser,
92+
}: VueFireAuthOptions): VueFireModule {
3393
return (firebaseApp: FirebaseApp, app: App) => {
3494
const user = getGlobalScope(firebaseApp, app).run(() =>
3595
ref<_Nullable<User>>(initialUser)
3696
)!
3797
// this should only be on client
3898
authUserMap.set(firebaseApp, user)
39-
setupOnAuthStateChanged(user, firebaseApp)
99+
const auth = initializeAuth(firebaseApp, dependencies)
100+
app.provide(_VueFireAuthKey, auth)
101+
setupOnAuthStateChanged(user, auth)
40102
}
41103
}
42104

@@ -47,6 +109,22 @@ export function VueFireAuth(initialUser?: _Nullable<User>) {
47109
* @param name - name of the application
48110
* @returns the Auth instance
49111
*/
112+
export function useFirebaseAuth(): Auth | null
113+
/**
114+
* Retrieves the Firebase Auth instance. **Returns `null` on the server**. When using this function on the client in
115+
* TypeScript, you can force the type with `useFirebaseAuth()!`.
116+
*
117+
* @deprecated - the name parameter is removed to enable tree shaking. If you have multiple applications, you **must**
118+
* use "getAuth(firebaseApp)" or "getAuth(useFirebaseApp(name))" instead.`
119+
*
120+
* @param name - name of the application
121+
* @returns the Auth instance
122+
*/
50123
export function useFirebaseAuth(name?: string) {
51-
return isClient ? getAuth(useFirebaseApp(name)) : null
124+
if (__DEV__ && name != null) {
125+
console.warn(
126+
`[VueFire] useFirebaseAuth() no longer accepts a name parameter to enable tree shaking. If you have multiple applications, you must use "getAuth(firebaseApp)" or "getAuth(useFirebaseApp(name))" instead.`
127+
)
128+
}
129+
return isClient ? inject(_VueFireAuthKey) : null
52130
}

src/auth/user.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import type { FirebaseApp } from 'firebase/app'
22
import {
3-
getAuth,
43
onIdTokenChanged,
54
type User,
65
updateEmail,
76
updateProfile,
87
reauthenticateWithCredential,
98
type AuthCredential,
9+
type Auth,
1010
} from 'firebase/auth'
1111
import { computed, Ref } from 'vue-demi'
1212
import { useFirebaseApp } from '../app'
@@ -168,10 +168,8 @@ export function getCurrentUser(name?: string): Promise<_Nullable<User>> {
168168

169169
export function setupOnAuthStateChanged(
170170
user: Ref<_Nullable<User>>,
171-
app?: FirebaseApp
171+
auth: Auth
172172
) {
173-
const auth = getAuth(app)
174-
175173
// onAuthStateChanged doesn't trigger in all scenarios like when the user goes links an existing account and their
176174
// data is updated
177175
// https://github.com/firebase/firebase-js-sdk/issues/4227

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ export { useFirebaseApp } from './app'
8787
export {
8888
useCurrentUser,
8989
useIsCurrentUserLoaded,
90+
type VueFireAuthOptions,
9091
VueFireAuth,
92+
VueFireAuthWithDependencies,
9193
useFirebaseAuth,
9294
getCurrentUser,
9395
updateCurrentUserProfile,

0 commit comments

Comments
 (0)