Open ludwigbacklund opened 3 years ago
Hi @ludwigbacklund, thanks for the report. This iframe from Firebase Auth is used for third party login and eagerly loaded on mobile in certain situations. Currently, there’s no way to disable it. You may refer to this for your reference.
@looptheloop88 I see, thank you. However, I think you're a bit quick to close this. 263 kb of entirely unused code is a lot to download, parse and evaluate for nothing when our application has no use for it. I can imagine there are many other applications where this is true as well. For now we've had to use patch-package to manually disable the loading of this file which improved our Lighthouse score.
Hi @ludwigbacklund, thanks for the feedback. We are exploring for potential solutions, however we can't provide definite timelines or details. I have reopened this issue and added a feature request label for the meantime.
@ludwigbacklund Can you share the snippet of your solution?
@mark922 Open node_modules/@firebase/auth/dist/esm2017/index-somehash.js
. Find the _shouldInitProactively()
function. Change return _isMobileBrowser() || _isSafari() || _isIOS();
to return false
. Follow the patch-package README instructions to generate the patch and commit it.
Shouldn't this issue be given higher priority, since the benefit of firebase js package becoming smaller is nullified by this issue?
@ludwigbacklund there are multiple index-somehash.js files, which one should I take? Or all of them? Why are there multiple? (they all look the same)
@ludwigbacklund there are multiple index-somehash.js files, which one should I take? Or all of them? Why are there multiple? (they all look the same)
Search in the @firebase/auth node_modules directory for _shouldInitProactively
and you'll find it.
@looptheloop88 Could you please share if there's any update on this? If this issue is fixed, it will help us meet the core web vitals for an ecommerce site that we built for our client. As per pagespeed insights, if this is fixed, it will improve our LCP quite a bit (saw a very big improvement for desktop after moving to v9 but for mobile the score became worse).
Hi folks, the iframe code is in fact required if you're doing signInWithPassword
or signInWithRedirect
. If you're not using those methods (i.e. you're not using any of the OAuth providers), you can initialize Auth in a way that does not cause this code to load.
The default in getAuth()
pulls in all dependencies you might need, including browserPopupRedirectResolver
. You can tailor which dependencies are pulled in by using initializeAuth
instead of getAuth
.
The notes in the reference doc for initializeAuth
explain in more detail, but at a high level you can mimic the behavior of getAuth()
without pulling in the iframe code by using this code instead:
// initializeAuth throws an error if it's called more than once for the same app; save the reference.
const auth =initializeAuth(app, {
persistence: [indexedDBLocalPersistence, browserLocalPersistence]
});
You can verify this by looking at the code: https://github.com/firebase/firebase-js-sdk/blob/6564e99ec16612960c7ea49a368fc18197a5f2d1/packages-exp/auth-exp/index.ts#L137-L140
As you can see, the snippet I wrote earlier just omits the popupRedirectResolver
dependency. This will prevent the iframe code from loading. But remember, this will prevent you from using signInWithPopup
and signInWithRedirect
.
Hi @sam-gc, thank you for your response. Is it possible to delay the iframe code from loading until signInWithPopup
or signInWithRedirect
are called ?
In general it does delay. It only loads early in a few cases: https://github.com/firebase/firebase-js-sdk/blob/7028c1159b9153f14c22a81fdd09df68ffcfcfb6/packages-exp/auth-exp/src/platform_browser/popup_redirect.ts#L166-L169
@sam-gc Is there no way to fix this such that lighthouse doesn't penalize performance score for using firebase sdk?
Any updates on this? We'd definitely like to disable it on mobile until it's really needed.
Hi folks, it is indeed possible to delay loading that code until the sign in methods are called. The popup and redirect family of methods take an optional third parameter that is the popupRedirectResolver
. For example, the signature for signInWithPopup()
is as follows:
export declare function signInWithPopup(auth: Auth, provider: AuthProvider, resolver?: PopupRedirectResolver): Promise<UserCredential>;
So instead of using getAuth()
(or initializeAuth
with the popupRedirectResolver
set---these are the same), you can call initializeAuth()
without the popupRedirectResolver
option, then pass it in to the sign in functions as you need them. For example, this code below will always delay loading the iframe code until it is used:
import {initializeAuth, indexedDBLocalPersistence, browserLocalPersistence, browserSessionPersistence, browserPopupRedirectResolver, signInWithPopup, GoogleAuthProvider} from 'firebase/auth';
const auth = initializeAuth(app, {
persistence: [
indexedDBLocalPersistence,
browserLocalPersistence,
browserSessionPersistence
],
});
async function signIn() {
const result = await signInWithPopup(auth, new GoogleAuthProvider(), browserPopupRedirectResolver);
}
If anyone is looking for a patch. https://gist.github.com/mdathersajjad/628c53913c10f7e090d52871faf1c373. And add browserPopupRedirectResolver as given in above comment
Hi folks, it is indeed possible to delay loading that code until the sign in methods are called. The popup and redirect family of methods take an optional third parameter that is the
popupRedirectResolver
. For example, the signature forsignInWithPopup()
is as follows:export declare function signInWithPopup(auth: Auth, provider: AuthProvider, resolver?: PopupRedirectResolver): Promise<UserCredential>;
So instead of using
getAuth()
(orinitializeAuth
with thepopupRedirectResolver
set---these are the same), you can callinitializeAuth()
without thepopupRedirectResolver
option, then pass it in to the sign in functions as you need them. For example, this code below will always delay loading the iframe code until it is used:import {initializeAuth, indexedDBLocalPersistence, browserLocalPersistence, browserSessionPersistence, browserPopupRedirectResolver, signInWithPopup, GoogleAuthProvider} from 'firebase/auth'; const auth = initializeAuth(app, { persistence: [ indexedDBLocalPersistence, browserLocalPersistence, browserSessionPersistence ], }); async function signIn() { const result = await signInWithPopup(auth, new GoogleAuthProvider(), browserPopupRedirectResolver); }
The only problem is that you'll get a pop-up blocked error on the first try to login with a provider on Safari. If you try again it works because by than the iframe has loaded.
@abdo643-HULK yep, that's one of the reasons why the _shouldInitProactively
functionality exists
@abdo643-HULK yep, that's one of the reasons why the
_shouldInitProactively
functionality exists
Where can I find this function ? I am looking through the source code of the auth but can't seem to find it. And thnks for your help
It's this code here: https://github.com/firebase/firebase-js-sdk/blob/49b0406abb9b211c5b75325b0383539ac03358d1/packages/auth/src/platform_browser/popup_redirect.ts#L166-L169
By omitting the popupRedirectResolver
optional dependency in initializeAuth()
, that function is never called
Here goes my solution, i only dynamic import firebase auth, when I need it. So I don't call it in the entire application, only when am making request to firebase. If you have small to medium application, it should be to much work. Tip* to keep the state of current user, use cookies
Using the examples from the comments, I get an error "TypeError: class constructors must be invoked with 'new'"
provideAuth(() => {
const auth: Auth = initializeAuth(getApp(), {
persistence: [
indexedDBLocalPersistence,
browserLocalPersistence,
browserSessionPersistence
],
popupRedirectResolver: undefined
});
if (environment.emulator) {
connectAuthEmulator(auth, 'http://localhost:9099', {disableWarnings: true});
}
return auth;
}),
const credential: UserCredential = await signInWithPopup(this.auth, new GoogleAuthProvider(), browserPopupRedirectResolver);
Ah, the problem lies within AngularFire. Will open a ticket there (https://github.com/angular/angularfire/issues/3038)
Another reason why this can be problematic is if you try to put the whole Auth module into a web worker. It works at first, until you test it on mobile, when suddenly it breaks because the web worker has no access to window.
The use of initializeAuth instead of getAuth (as outlined by sam-gc) fixed the issue for me.
// initializeAuth throws an error if it's called more than once for the same app; save the reference. const auth =initializeAuth(app, { persistence: [indexedDBLocalPersistence, browserLocalPersistence] });
PS. Having auth in a web worker already means that you cannot use signInWithPopup or Redirect, so that is not a drawback. To make that work for me using Google, I basically use Google Auth scripts to get a token, then send that token to my web worker auth script where I use signInWithCredential instead. :-)
I suspect this is what causes firebase to stop in PWA in offline mode. #5720
https://github.com/firebase/firebase-js-sdk/issues/4946#issuecomment-927800881
Is there nothing we could do to load iframe when we need ?
like after initialization and beforesignInWithPopup
@sam-gc Your solution works great, except for on Safari. I have tried different hacks to get the script to load when I actually need it (on sign in/sign up pages) but couldn't get anything to work reliably. A method to initialize the loading of the script would be perfect, so we don't have to load it on every page.
Pagespeed Insights even says that it is not gzipped. This could shave off some loading time and could improve this issue while we wait for a proper solution.
+1
If there's any way to get rid of the js, that would be sweet.
In the meantime, it should really get gzipped, it's a pretty bad hit on perf. The file is 263 kb unzipped while it ~could~ should be ~83 kb (~69% smaller). according to Pagespeed.
Hi all, thanks for the work to fix this. Are there any updates on the timeline? This is likely hurting SEO and load times for many users out there and gzipping would fix 69% of the issue, so would be a high ROI change to make when you get around to it.
It's strange that Google's own tool (PageSpeed Insights) recommends a solution (set a lifetime cache) for Firebase which is extremely popular on mobile. Is there anyone internally that can pick this up and unblock?
There are various solutions above for lazy-loading Firebase Auth but it's not the recommended approach as per documentation since auth should ideally be initialised once and shared as much as possible. I suspect this may need to be a Google hosting fix and not something the community can PR for.
It's sincerely been fantastic how far Firebase SDK has come to tackle bloat in the last year so this feels like an oversight?
Since lazy loading iframe.js is not a viable option for now, can we at least get compressed files served?
In the current state, my SPA gets a ~1s performance hit from this issue.
Paging @sam-gc @looptheloop88.
Is there any way to get the iframe.js
compressed? Or would you recommend fixing the auth library itself? Has this been assigned to anyone internally?
Desperate for a update on this, its killing my performance/lighthouse score
Here are some comparisons to highlight:
Desktop:
Mobile:
I was so shocked when I saw my measurements. This really needs a fix, haha.
I've spun the compression issue into a separate ticket, see #6169. Now let's hope someone picks it up..
Man I hope this gets fix quickly. The impact on performance is pretty severe.
Hi all, thanks for the active discussion regarding this issue. We are unable to promise any timeline for this, adding a +1 on this issue can help us prioritize adding this to the roadmap.
Hey looks like the gzip compression is enabled? That's great!
Any updates on this? I am finalizing a project ready to be put on production but its impossible to make the mobile pagespeed go above 70 with this iframe loading. I am still loading a 263kb package loaded on mobile every time..
Any updates on this? I am finalizing a project ready to be put on production but its impossible to make the mobile pagespeed go above 70 with this iframe loading. I am still loading a 263kb package loaded on mobile every time..
You can do what I did and load all of firebase asynchronously into a web worker. So the initial load isn't affected at all by the size of firebase. Of course, you won't get any functionality until it is loaded but at least it is off the main thread and you can show whatever you need before the functionality is there.
Need an update on this.
Updates on this guy? Isn't this a very basic thing to do?
Firebase SDK Team, This issue is a blocking for me to improve PageSpeed Insight. This issue has been open for sooooooooo long. Please assign this as urgent priority to fix it.
Hi @dwyfrequency
Anyway you can help the firebase team prioritize this issue?
Thank you
Any update on this issue?
Im also still waiting for an update on this
I solved my issue with customize your v9 auth dependency from firebase .
What I did:
Replace
getAuth()
on the _app.tsx (I am using NextJS) with auth from the app configconst auth = initializeAuth(app, { persistence: [ indexedDBLocalPersistence, browserLocalPersistence, browserSessionPersistence, ], });
<AuthProvider sdk={auth}> // import above auth
<FirestoreProvider sdk={firestore}>
<StorageProvider sdk={storage}>{children}</StorageProvider>
</FirestoreProvider>
</AuthProvider>
Add third parameter to the place where I was using
signInWithPopup
for both Google and Facebook Provider. Now, the code is like this:
await signInWithPopup(
auth,
facebookProvider,
browserPopupRedirectResolver); // import this from firebase/auth
Boom! The pre-loading of auth/iframe
is now gone.
@SanjivG10
But that's not working well on Safari right ?
same as this https://github.com/firebase/firebase-js-sdk/issues/4946#issuecomment-927800881
[REQUIRED] Describe your environment
[REQUIRED] Describe the problem
After upgrading from v8 to v9 a request for an iframe (
https://[projectname].firebaseapp.com/__/auth/iframe.js
) has started appearing on every page load, but only on mobile (via Chrome's simulated Device mode at least, and when Lighthouse is auditing the website).An older Lighthouse report of our application, from before the upgrade to v9, did not mention this file at all so I can only assume it wasn't loaded back then.
This iframe file is big and seems unnecessary to our application since we never use any kind of iframing of Firebase functionality and the only auth login method we use is email login.
Is there a way to disable the loading of this iframe?