Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Service auth is not available #8506

Open
jdgamble555 opened this issue Sep 18, 2024 · 16 comments
Open

Service auth is not available #8506

jdgamble555 opened this issue Sep 18, 2024 · 16 comments

Comments

@jdgamble555
Copy link

jdgamble555 commented Sep 18, 2024

Operating System

Windows 11

Environment (if applicable)

Vercel Edge with Qwik

Firebase SDK Version

10.13.1-canary.16d62d4fa (or lower)

Firebase SDK Product(s)

Auth

Project Tooling

Qwik (1.8.0)

Detailed Problem Description

When I use getAuth() on the server inside a Qwik app, I get the Service Auth is not available error. The local testing environment has no problems and works as expected.

It is literally something that gets errored out in Qwik with getAuth().

Possibly related to #8355

While I'm not sure why the error is thrown, it is coming from here:

throw Error(`Service ${this.name} is not available`);

J

Steps and code to reproduce issue

I made a Repo:

  1. Add your Firebase environment variables to .env and to Vercel Edge environment variables.
PUBLIC_FIREBASE_CONFIG={"apiKey":....,"authDomain"...}
  1. Deploy to Vercel Edge.

  2. # with Google.

  3. Click the about link in navigation.

  4. See error thrown.

See Deployed Demo with error.

If have isolated the error to getAuth(). This app doesn't use initializeApp or initializeServerApp, but the error is the same in either case.

Here is failing code.

J

@jdgamble555 jdgamble555 added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Sep 18, 2024
@google-oss-bot
Copy link
Contributor

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@jbalidiong jbalidiong added api: auth needs-attention and removed needs-triage new A new issue that hasn't be categoirzed as question, bug or feature request labels Sep 18, 2024
@DellaBitta
Copy link
Contributor

Hi @jdgamble555,

This reported error is generally realted to an Auth Instance being used without an initialized App Instance. This doesn't seem related to #8355 as that had to do with a lack of support for features in fetch, which would come much later in the usage of Auth.

Are you certain that there's a default instance of App initialized within the context of that Request Handler? It might be worth adding a call to initializeApp before the getAuth call to double check.

@jdgamble555
Copy link
Author

@DellaBitta - I just made the test repo so that you can see clearly what the problem is. This equally happens when the server is initialized. I already have a repo for that.

quik-firebase-todo

J

@hsubox76
Copy link
Contributor

I'm not familiar with Qwik or Vercel Edge or the architecture of your app but what I can do is tell you what causes that error in the Firebase SDK.

The error is usually caused when the entry point bundle that initializeApp comes from (firebase/app) doesn't match the version of the @firebase/auth bundle that getAuth was imported from. A couple of reasons this happens is (1) mismatched package versions - you have a newer @firebase/app but an older @firebase/auth - sometimes caused by incomplete npm upgrades - cleaning out node_modules and lockfiles and reinstalling usually fixes it, (2) your app does multiple builds - for example, one for server and one for client, with different module resolution configurations - for example, the server build process looks for CJS or the "main" or "exports.node" paths in the package.json, while the client build process looks for "browser" or "module" or "exports.browser/import". This would lead to each process importing a different bundle (CJS vs ESM) which aren't aware of each other, and if you try to share across them, the getAuth() from one won't recognize the app from another.

I took a quick glance and noticed your repo gets the "app" to use for getAuth() in 3 different places, by two different methods, you initializeApp/getApp in 2 places and initializeServerApp in the file that you say you're getting the error in. Do you not get the error from the other two files? Are they all compiled into one app? Or is the initializeServerApp only used in an isolated process on the server? If you use app instead of initializeServerApp there, do you have the same error?

https://github.com/search?q=repo%3Ajdgamble555%2Fqwik-firebase-todo%20getAuth&type=code

Also does this problem only occur when deployed to Vercel Edge? Does it happen locally? Is there any way to deploy it locally so we can reproduce and diagnose it? If not, the best I can suggest is to dig into Qwik or Vercel Edge and try to understand which environments your various bits of code are running in, what the module resolution config might be for each environment if there are multiple environments, and try to give us a breakdown of what's running where, and with what module resolution config. Unfortunately I'm not an expert in these tools and I'm afraid if this isn't reproducible locally, the error is likely to happen somewhere in this tooling pipeline, and can't be figured out without more understanding of the steps of this pipeline. If you can provide insight into it, that would be great.

@jdgamble555
Copy link
Author

Well I know a few things:

1.) I only have one package version, not even sure how you would have two package versions.

2.) Since I am running on the server, it clearly has a build for the server and for the client. I have deleted package-lock.json and node_modules and rebuilt. Same error.

3.) Everything works fine locally, in dev and in production builds.

4.) As far as I can tell, everything compiles with type: "module" everywhere, even in vercel edge plugin. There is unfortunately not a Vercel Serverless plugin, so no way to test this.

5.) The problem only persists when I call, not bundle, but call getAuth() on the server. It does not seem to matter what initialize method I use.

Given this information, any way to isolate the problem (at least get rid of what the causes aren't)?

Here is my test repository with a simpler version - https://github.com/jdgamble555/qwik-firebase-test

Thanks,

J

@hsubox76
Copy link
Contributor

2.) Since I am running on the server, it clearly has a build for the server and for the client.
5.) The problem only persists when I call, not bundle, but call getAuth() on the server.

It seems like you have two separate builds and two separate copies of the Firebase SDK code - not sure if I'm reading right, but one is in a bundle? for client? And the other is not bundled but called directly out of node_modules by the server?

The way that the Firebase SDK manages different services is a component registry. When you import from firebase/app or firebase/auth, there's some code that runs immediately on load (before you call any methods like initializeApp or getAuth) that registers that service to a component registry in local memory. If you have different runtimes (as you seem to with server and client), then you'll create two different registries in two different namespaces that don't know about each other.

I don't know Qwik so I'm not very sure what's going on, but it seems like the setup when you run it locally must have some kind of shared context vs when you deploy it, where some of the build is shared but some of the code is run in a separate runtime?

My only guess would be to either further separate or further share the code to prevent this from happening. For further separating it, if there's any way to isolate the runtimes of server and client and prevent them from sharing anything after the build? For further sharing it, if there's any way to ensure they are using the same context? Perhaps make firebase external for the client build instead of bundling it, so that both builds are calling code in node_modules?

If none of this helps, we can try to get up to speed on Qwik and Vercel Edge deployment to debug it ourselves but this may take some time, as we have to prioritize this among our tasks.

@jdgamble555
Copy link
Author

The way that the Firebase SDK manages different services is a component registry. When you import from firebase/app or firebase/auth, there's some code that runs immediately on load (before you call any methods like initializeApp or getAuth) that registers that service to a component registry in local memory.

So, even if not one function gets called on the server, just by running "import," there is immediate code that gets ran?

If that is the case, what makes it a new copy of Firebase? Is there a way to delete whatever copy of Firebase is in memory? Why wouldn't it just detect the existing version and not run again? This is confusing to me.

I have modified my code again so that it is impossible to run any firebase imported function on the server:

https://github.com/jdgamble555/qwik-firebase-test

I still get the error. I am technically importing on the server, but not running any functions unless it is in the browser.

A few things:

  1. This problem does not exists locally (dev or prod)
  2. This problem does not exists on other frameworks when I import something on the server
  3. This problem seems to only exist on Vercel Edge or Cloudflare with Firebase

J

@jdgamble555
Copy link
Author

@hsubox76 - This is not an import problem. I just refactored my entire code base to use dynamic imports everywhere, and the problem still exists. It is impossible to run any firebase code on the server, except in the server route. This is the only place there has ever been a problem, and it doesn't seem to be related to any client bundling problems.

https://github.com/jdgamble555/qwik-firebase-test

J

@DellaBitta
Copy link
Contributor

Hi @jdgamble555,

I was able to reproduce the problem. It appears that something in the build pipeline is aggressively tree shaking portions of the Firebase JS SDK when it packages it for the edge runtime. The "service" mentioned in the log file is that fact that Auth cannot properly register itself with the instance of FirebaseApp (or FirebaseServerApp). This is due to the hooks it would use to register itself with the instance of App are inexplicitly missing from the SDK implementation.

I'm not that familiar with Qwik and I'm not sure how to tune the build pipeline, or even if there are ways to tune it. Do you have any thoughts on how that might be done?

In the meantime it might be worth using the Firebase REST API to get around this problem.

@jdgamble555
Copy link
Author

jdgamble555 commented Nov 13, 2024

QwikDev/qwik#7052 (comment)

To solve the problem, the firebase import needs to happen in a different file. This file should export helpers that expose the desired firebase functionality. Then when you use these helpers in your Qwik code, they won't be tree shaken and the firebase side effects can run on first import.

@DellaBitta - Is this something that is possible?

Thanks!

J

@DellaBitta
Copy link
Contributor

Hi @jdgamble555,

Unless I'm mistaken, I think this change has to be done in the app and not the SDK. The engineer refers to the "firebase import" which is at the app level. I left a comment asking for clarification in the Qwik issue a few days ago, but I haven't had a response. I think the intention is to have your app import in only one location and funnel all firebase requests through that file.

@jdgamble555
Copy link
Author

Hopefully they will respond soon. However, I'm dynamically importing all firebase imports in my project on the server and client, and on the server it is already in one file.

J

@jdgamble555
Copy link
Author

@DellaBitta - I'm getting a little clarity from Qwik team (not a lot), but I'm still convinced this is a Firebase issue because it seems to work fine on the local machine (dev and preview --- which apparently uses treeshaking) with dynamic imports.

It just doesn't work in non-Node environments from what I can see.

J

@DellaBitta
Copy link
Contributor

Yes, I've been mointoring their thread as well, and that fact that it works locally is expected. The tooling for their hosted worker environments seems to be causing the problem, whereas building locally executes less agressive packaging tools designed for your more roboust local environment, and those tools don't cause a problem.

@wmertens
Copy link

The only tree shaking done by the qwik optimizer plugin is for client builds 🤔

Can you give an example of necessary code that is tree shaken away?

@DellaBitta
Copy link
Contributor

DellaBitta commented Dec 23, 2024

The Firebase JS SDK leans on side effects to stand-up and/or register Components, cross SDK communication mechanisms, at the time of import of the various different Firebase packages. That is when App, or Auth, or Firestore, are imported, etc.

It seems that these side effects aren't being executed, and/or are being lost, or maybe isolated from each other when one SDK is imported in one file and another SDK is imported from a different file (at least that's what it sounds like given the response in the Qwik repo).

Going back to the specific error above, the App component should have been created via a side effect upon Firebase App import, but when a subsequent instance of Auth is created, and it attempts to register itself with the App Component, an error is thrown because the App component doesn't exist. It was either never stood up to begin with, or perhaps it exists within a different scope than the Auth import (just speculating).

If you really want to get into the weeds then you can see that _registerComponent is invoked inline upon import if you look into the dist sources of the various Firebase SDKs.

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

6 participants