-
Notifications
You must be signed in to change notification settings - Fork 923
Firebase v9 loads a large iframe.js file but only on mobile #4946
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
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 |
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) |
Search in the @firebase/auth node_modules directory for |
@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 The default in The notes in the reference doc for // 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: firebase-js-sdk/packages-exp/auth-exp/index.ts Lines 137 to 140 in 6564e99
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 |
In general it does delay. It only loads early in a few cases: firebase-js-sdk/packages-exp/auth-exp/src/platform_browser/popup_redirect.ts Lines 166 to 169 in 7028c11
|
@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 export declare function signInWithPopup(auth: Auth, provider: AuthProvider, resolver?: PopupRedirectResolver): Promise<UserCredential>; So instead of using 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 |
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 |
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: firebase-js-sdk/packages/auth/src/platform_browser/popup_redirect.ts Lines 166 to 169 in 49b0406
By omitting the |
Here goes my solution, i only dynamic import firebase auth, when I need it. |
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 (angular/angularfire#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.
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. :-) |
Just wanted to say I am also dealing with this issue. Hoping for the best and will subscribe to this thread for updates! |
@SanjivG10 as @kodai3 mentioned, that will have several popup blocked issues, forcing the user to first, unblock the popup, second, re-try the authentication, which will probably generate a lot of support tickets in anyone's app support team. The only difference between those two screenshots is deferring the load of the popup. |
What I did was to isolate all firebase libraries in a Worker thread, that also loads the libraries lazily. Sure, now everything is asynchronous and like you said, the only way to check for user auth status is to load the library. So, everything that require user information is lazily loaded. I do, however, store some user information (very basic, like, are they logged in at all and what kind of access rights do I expect them to have) on local disk so that I can guess what menu options they will have. All that gets corrected once I get the real information, but this limits the redrawing since 99% of the time, the locally stored information is correct. The worker thread also has the added benefit of keeping the main thread more open, and it forced me to create an API between the threads. Does mean it will be easy to swap out Firebase if I ever need to! :-) |
@Parakoos' solution is basically what I do. I only load auth + auth-ui in the main thread if the user is not logged in. Slightly offtopic, but Comlink (by dasurma) will save you a lot of work when moving firebase into a worker |
@Parakoos, running all the firebase related operations in a worker has been in my mind for some years now. Not only because the size of le libraries (which is huge, specially in the pre-v9 era) but because all of my projects are focused on being low cost but still need to compute statistics in slightly big datasets, so having all the async communication + big computations into a dedicated non blocking thread always looked very attractive to me. What was putting me away from it was that I was not sure about the investment (was it doable, or will I hit a roadblock after invested dozens of hours?) and because the complexity of the project which was already mature and big (not to mention the redux docs tell you to do all the calculations on the reducer but redux can not work in a worker... I should not have listen to them 😄 ). Now with your testimonial that is possible and starting a new and small project I feel more inclined to give t a go, and the existence of Comlink as pointed out by @rejhgadellaa really makes me want to try it out. However, how do you manage the popup login scenario? I think I can maybe put all the auth logic into a lazy loaded component that, once the login is either verified or succeeded populates the app global store (or whatever you use) with the credentials and login information, and meanwhile just used whatever is cached in local storage? How are you sharing the credentials with the worker thread though? Do you send them from the main thread and re-initialize the firebase app there or how? I'm very interested in the topic |
You can find a small Comlink / firebase example in an issue I filed a while ago (since been resolved): Regarding auth in the main thread; I currently do it in a Preact app, and have one route (/login) where I send the user when the auth in the worker signals the user isn't logged in, then I load everything I need in that route: import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
// Init firebase app & auth
const app = initializeApp({/* config */ );
const auth = getAuth(app);
// Import firebase ui dynamically so we can do SSR
const firebaseUi = await import('firebaseui');
// Init & start Firebase Auth UI
const ui = new firebaseUi.auth.AuthUI( auth );
ui.start('#firebaseui-auth-container', /* config */); The above is just some parts of code I use, thrown together in a snippet, hope it helps :) Update: Forgot the auth module :) |
@danielo515 , I never load any firebase code in the main thread, so I don't use the AuthUI of course. Instead I use handmade login forms for email, google, facebook, twitter and github, get hold of the credentials, send them to the worker thread that uses them to log in to firebase. Basically, I use the 'Manual Flow' under all the Firebase Auth documentation. You can see this live at https://sharedgametimer.com/login I did this because I didn't think I could do it any other way. I figured that logging the user in using AuthUI on the main thread wouldn't log the user in on the worker threat. But, seems @rejhgadellaa has gotten that to work (which would simplify the auth code A LOT). I do wonder if this means that the firebase core, app and auth modules are loaded twice? Once on the main thread, and again on the worker thread? I guess the download of the modules get cached (I'd hope) but parsing the JS has to happen twice, no? Is this a significant hit or a minor one? Perhaps this conversation is getting a bit off-topic. I'd love to continue the discussion off-thread, @rejhgadellaa and @danielo515 . Email in my bio. |
Are there any updates on this issue? Would be really great to have faster performance for firebase on mobile. |
Hi folks, the comment in #4946 (comment) is the "correct" solution. See also this commonet: #4946 (comment). Unfortunately, as you've noticed, this does not work in some cases like Safari. That is why this comment still applies: #4946 (comment). It is not easy to fix this at all, because the iframe and popup code is necessary for the proper functioning of social sign in. We're still aware of this issue, but there are no immediate plans/designs in place to avoid proactive initialization in general. |
FWIW, the I do wonder why I'm seeing 3 requests to |
Adding AngularFireAnalytics > UserTrackingService in angular app > providers list loads the iframe immediately. |
…pendencies' and 'firebase/firebase-js-sdk#4946' I am now deferring the loading of 'signInWithPopup' iFrame ... which pagespeed insights complains about. This is done by swapping getAuth(app) for initializeAuth(app,..) and then contextually loading the 'browserPopupRedirectResolver' method and passing as a third parameter to 'signInWithPopup' in both google and twitter login functions
Hey, Is there any update on how to remove the load of iframe in next js? |
Hi @raghavmri , the iframe.js file is necessary if you use signInWithPopup or signInWithRedirect. Proactive loading of this file can be disabled by following the code snippet in #4946 (comment), i see a next JS specific snippet in #4946 (comment) |
It's been more than 1.5 years. Will this ever be fixed? |
This is exactly why Big tech companies shouldn't be able to legally buy startups... 2 years later, and such an massive performance hit still unresolved! |
Some more information I'd like to put forward if it helps:
I hope some of this will help in some way. |
It is really bad that there is no simple solution to this problem. Why not simply give developers the option to dynamically import the module on demand? As a temporary workaround in Angular, I conditionally provide the provideAuth(() => {
if (typeof document !== 'undefined') {
const isAuth = document.location.href.includes('auth');
return initializeAuth(getApp(), {
persistence: [
indexedDBLocalPersistence,
browserLocalPersistence,
browserSessionPersistence,
],
popupRedirectResolver: isAuth ? browserPopupRedirectResolver : undefined,
});
}
return getAuth(getApp());
}); I also use the This workaround improved the Lighthouse speed score, but it is super ugly. |
Shouldn't this issue be fixed already? |
Hi everyone, The solutions above only work if you don't have Google auth. Here is hack to make it work even with Google auth. It just overrides the function that decides whether to preload html or not. Object.defineProperty((browserPopupRedirectResolver as any).prototype, '_shouldInitProactively', {
get: function () {
return false;
},
}); |
I think we may be able to code our own workaround to separately call the Specifically we would do something like the following--I'll report back what I find tomorrow: References:
|
Summary of investigation & solution: Use the The key trick to delayed initialization:
Step by Step Details:
Here is the key part wrapped up in a nice function that you could call unconditionally from some login component render method, but note that you must have already invoked Dimitry's method on startup prior to ever initializing auth (see step by step section above).
|
Its funny that its been almost 3 years, and still no fix, I am moving away to mongoDB just because of this issue. |
For others coming from search, the post above does fix the problem. Granted, it wasn't fixed in Firebase Auth by Google directly, but the problem of unconditionally loading the |
the following hack worked for me, I used replace-in-file npm package to patch the built bundle js using the following script:
I made it run automatically postbuild, it works with minified an unminified builds. I hope it helps someone. |
Experiencing the same issue here, in particular within my next.js app. The initial loading time is way too slow, and it seems mainly attributed to this. |
[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?
The text was updated successfully, but these errors were encountered: