-
Notifications
You must be signed in to change notification settings - Fork 897
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
Importing getFunctions() throws "self is not defined" during SSR/Static (v9-beta) #4846
Comments
I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight. |
After more testing, even lazy-loading // $lib/functions.ts
const { cloudFunction } = await import("$lib/glacier/core/functions"); is being transformed into // .svelte/output/app.js
const {cloudFunction: cloudFunction2} = await Promise.resolve().then(function() {
return functions;
}); This may be for performance reasons (lazy-loads are unnecessary during SSR) or for tree-shaking bundling purposes (Rollup). I can try opening up an issue on the SvelteKit repository, but this side-effect behaviour may cause issues with other SSR/SSG frameworks in the future. SvelteKit's advice is to run any |
Just want to clarify that the issue happens during static site generation which does happen in Nodejs? so the error makes sense. And you're right that it's caused by the side effect of the module, so it happens even if you don't call As a workaround for now, is it possible to configure svelte (rollup) to pick up the node build instead of the browser build of |
You are correct, the issue does indeed happen during static site generation in a Node.js environment. I understand that firebase expects a browser environment, but SSR requires running some code on the server, before being sent to the browser. I would argue that this behaviour does not make sense and is therefore undesirable. No function from the firebase module is ever used. Import-time initialisation is a bit of a hack from the CommonJS days, introduces start-up delays and makes it impossible to intercept errors. In my mind, there is no technical barrier that would keep initialisation from happening upon the first invocation of a function. I'm not sure how other SSR frameworks (Next.js, Nuxt, ...) have mitigated this issue so far, perhaps Webpack's module system has some form of lazy execute-once-required policy. While it's true that SvelteKit and Vite are relatively "new kids on the block" that do things differently to battle-tested CommonJS-based frameworks, I commend them on their bravery to try and give the JS community that push into the ESM world that brings it more in line with traditional programming languages. I would like to add that I'm not sure if such a workaround would work, my understanding is that Vite will attempt to transform CJS into ESM, likely resulting in the same issue. Having said that, I have just discovered a SvelteKit-specific workaround. Moving the
Heads up, I'm not sure how browsers handle this case, but if ESM hits more mainstream frameworks, it may become a problem. For now, my workaround is adequate, although I would like the new firebase SDK to embrace true ESM modularity. |
If I'm looking at the right package source (I'm on my phone and may not be), then I see the following:
This seems like it may not be setup correctly. |
@benmccann Interesting! We have been using the module field for browser builds all the time. I just checked rollup documentation again, but didn't see any text that says whether it should be used for nodejs build or browser build. so my understanding is that there is no consensus on that, and it's up to the lib authors. Do you have any link that says module field should point to nodejs build? |
|
Node only knows about |
It looks like the codesandbox example is using an outdated version of SvelteKit and Vite. If I update it (updated code on Github), then Vite's behavior does match that described in the docs and it does use the CJS version on the server-side. However, that code path shouldn't be executed in Vite and there's another bug causing it to go down that path: vitejs/vite#4425 We should still leave this open though as I still think it's wrong to put a browser-only build in |
I've re-created the sandbox using a new Sveltekit skeleton project (so removed the explicit vite dependency), updated all the dependencies to their respective latest versions (beta/next) and locked in the versions to maintain reproducibility. The bug is still there, you just need to download as a ZIP and run it locally, I think it's a caching issue with codesandbox, Ctrl+F5 usually helps to trigger the error. I have managed to get this to work on my own project through extensive dynamic Terminal error
|
@MarcusCemes I'm hitting this error and I'd love to work around it as you have. Would you be able to share some code to show how to protect against the self is not defined error, please? |
Found something that works, for anyone else that runs into this:
|
WorkaroundUpdated on 2021-08-12 After a little experimentation, the only problematic firebase module I can find is Simply make sure that you never import anything from Your implementation should work fine, here's my solution that makes it a little easier and avoids promises and imports everywhere. The downside of the dynamic import is that the // $lib/functions.ts
import type { HttpsCallable } from "firebase/functions"; // type imports are fine, they are removed during transpilation
export function cloudFunction<P, R>(name: string): HttpsCallable<P, R> {
return async function (params) {
const { getFunctions, httpsCallable } = await import("firebase/functions");
const service = getFunctions(firebase(), "europe-west3");
return httpsCallable<P, R>(service, name)(params);
};
} <!-- index.svelte -->
<script lang="ts">
import { cloudFunction } from "$lib/functions";
const fn = cloudFunction("someFunction");
async function onClick() {
await fn({ time: Date.now() });
}
</script>
<button on:click={onClick}>Execute function</button> |
I have the same problem:
I'm looking forward to an easier workaround / fix. |
@MarcusCemes IIUC, Vite translates |
@Feiyang1 I am not too familiar with the inner workings of the Vite/Rollup/Sveltekit trio, but inspecting the generated const name = "@firebase/functions-exp";
const version = "0.0.900-exp.8b4d7550f";
registerFunctions(fetch.bind(self)); // offending line
registerVersion(name, version);
const Test = create_ssr_component(($$result, $$props, $$bindings, slots) => { As stated in my above comment, moving The {
"name": "firebase-exp/functions",
"main": "dist/index.cjs",
"browser": "dist/index.esm.js",
"module": "dist/index.esm.js",
"typings": "dist/functions/index.d.ts",
"type": "module"
} My guess is that Vite is inlining the |
@Feiyang1 if you'd like to continue using the |
FWIW I encounter this (and this sveltejs/kit#612) issue when switching from |
To follow up on the discussion, here's my experience with SvelteKit/Vite/Firebase, for anyone else who might find this insightful. There's a lot going on with the Firebase SDK that Vite and Node.js can't deal with (without resorting to the Admin SDK). I've encountered all sorts of errors after accidentally including a Firebase import somewhere in the dependency chain, whether on purpose or by accident with VSCode's Intellisense. I have a spaghetti of browser checks and lazy I tried moving SSR-related Firestore code into a Cloud Function that I can query during SSR without the SDK, before realising that That, and also this (5-10 seconds for me...), and this, has led me to start the move away from Firebase. I was very excited at first, but it's quite difficult to integrate these stacks together at the moment, without too many unnecessary abstractions. I've no doubt that for some it may be a fantastic solution. The client SDK is used by a lot more than just SvelteKit/Vite users, it was designed with CommonJS and Webpack in mind, I'm guessing that messing with the |
So I made a prerelease with exports support for all firebase packages including functions, but it doesn't seem to solve the problem using @MarcusCemes's repro. @benmccann Do you mind giving it a try, using The
I expect Vite to use
|
Hi @Feiyang1, thank you for taking a look at this. Your change did allow me to get past that error! I did get a two other errors, but I would say to go ahead and ship your change. If you send a PR I'd be happy to lend it a set of eyes. One suggestion I would make is to also export The most serious remaining issue is a Vite bug. I will work with the Vite team to fix it, but in the meantime it looks like it can be worked around by setting However, there was one more error originating from Firebase. Vite was complaining vociferously about this Firebase sourcemap, which appears to be empty:
As a result, I get the error message:
It would be nice if that could be fixed as well, but it could possibly be tracked in a new issue. |
The reason why it happens is more related to how node loads modules. If the package is of So a fix for this is to make sure ESM files always end with |
It should be noted though that I'm not getting that error. I think that @MarcusCemes test repo was outdated. Here's a working version: https://github.com/benmccann/sveltekit-firebase. (Note that it won't give the other errors I mentioned because I added the |
There is a |
Ah I see. My bad, that's really strange then. |
@benmccann Nice! Glad it works. The sourcemap is generated by rollup and I think it's working as intended. The source code only contains one line
, so it makes sense that the sourcemap is empty? Maybe it's something vite can also look into? Good point of adding Here is the PR - #5646 |
Describe your environment
Describe the problem
Unable to render a statically built site using Sveltekit. This seems to be a result of Sveltekit's new bundling technique of "using Vite to dump everything into one file before running it through Rollup for tree-shaking and optimisation".
The following line gets included in the bundle when a user's code has
import { getFunctions } from "firebase/functions";
, even ifgetFunctions()
is not called. During SSR,window
, here referenced asself
, is not available. This is a import side-effect.fetch()
is pollyfilled during SSR by Sveltekit. From what I can tell, it's the ESM build that's being imported.The static build adapter for Sveltekit fails with:
This is not an attempt to use Firebase during SSR or from Node.js. I would like to include firebase in the browser bundle. A solution is lazily importing
getFunctions()
from the browser, however, this comes with a latency penalty and an extra network request.Steps to reproduce:
[email protected]
to a Sveltekit applicationnpm run dev
ornpm run build
(dev will only fail once, as dev-time SSR is not retried a second time)The sandbox is a little weird, it occasionally works, occasionally doesn't. Downloading the sandbox as a ZIP on Windows and Ubuntu still causes the build error.
Relevant Code:
Offending line
firebase-js-sdk/packages-exp/functions-exp/src/index.ts
Line 30 in 9df03c9
Failure case
The text was updated successfully, but these errors were encountered: