Skip to content
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

The requested module 'firebase/app' is expected to be of type CommonJS, which does not support named exports #47

Closed
nielsvandermolen opened this issue May 7, 2021 · 12 comments

Comments

@nielsvandermolen
Copy link
Contributor

Describe the bug
I decided to use v9 of the Firebase API.

The biggest change to v8 is that you no longer need to load all the Firebase JS but just the functions that you are going to use.

Instead of

import firebase from "firebase/app"

it is called by

import { initializeApp } from 'firebase/app';

In development this works fine however when running the build with the Svelte adapter I get the following error:

> Using svelte-adapter-firebase
> The requested module 'firebase/app' is expected to be of type CommonJS, which does not support named exports. CommonJS modules can be imported by importing the default export.
For example:
import pkg from 'firebase/app';
const {getApp, initializeApp} = pkg;
file:///var/www/svelte/.svelte-kit/output/server/app.js:6
import {getApp, initializeApp} from "firebase/app";

To Reproduce
Steps to reproduce the behavior:

  1. Initiate an App with v9 logic
  2. Run a build with svelte adapter 0.6.3

Expected behavior
Being able to build without having to add something like import firebase from "firebase/app"

Additional context
I do not know where this error is triggered but it seems related to the adapter. The initial svelte build does seem to work. With the support of ESMBuild in #39 you would expect that it should work but maybe there is a hardcoded check on firebase/app that it is CommonJS somewhere?

@nielsvandermolen
Copy link
Contributor Author

Might be related to this similar issue in another adapter sveltejs/kit#1379

@babichjacob
Copy link

This isn't a bug with this adapter, by the way, because it'll happen with any. I'd also suggest upgrading to Node 14.16.1 if not 16.1.0 to solve this (because I've seen that be the reason for issues with a similar error message).

@nielsvandermolen
Copy link
Contributor Author

Thanks! Confirmed that updating to Node 14.16.1 solved this issue.

@jthegedus
Copy link
Owner

Cloud Functions latest Node.js support is 14.x.x so I highly recommend using that. I don't think there is a way for me to enforce this with the adapter unfortunately.

@sebmade
Copy link
Contributor

sebmade commented Jul 14, 2021

problem persists
if I import firebase/firestore I have the same problem
if I upgrade to node v16.5.0, the problem is now on firebase/auth !!!
is there a problem from firebase v9 packaging ?

@sebmade
Copy link
Contributor

sebmade commented Jul 14, 2021

finally it works by doing "npm i firebase@9.0.0-beta.6" under functions directory

@jthegedus
Copy link
Owner

@sebmade You shouldn't need to or be expected to add firebase client SDK to the Functions directory. Are you able to provide more information on your setup, how and where you're using the SDK in your app so we can better understand the exact scenario. Depending on the use case I feel the resolution is not strictly correct and do not want to lead others astray.

@sebmade
Copy link
Contributor

sebmade commented Jul 15, 2021

@jthegedus my config is a just new installation of a svelte-kit app by using npm init svelte@next my-app, so I use @sveltejs/kit 1.0.0-next.127. I've import firebase-admin@9.10.0 for server side calls and firebase@9.0.0-beta.6 for client side calls. I use svelte-adapter-firebase@0.9.2 and svelte@3.34.0.
I've imported firebase-admin also in functions directory because I have a specific google function that used it.
I think there is a conflict declaration between firebase-admin and firebase.

@sebmade
Copy link
Contributor

sebmade commented Jul 15, 2021

Finally it reproduce again, you're true : install firebase in functions dir don't work
I don't understand how it happens to work once time
Now I try to manage putting firebase and firebase-admin in dependencies vs devDependencies in root packages.json
In devDependencies I have the commonJS error describe above in dependencies I have "IDBIndex is not defined" error
I remove my node_modules dir and "npm i" but nothing changed

Don't understand what happens, I'm open to ideas :)

@jthegedus
Copy link
Owner

jthegedus commented Jul 16, 2021

IDBIndex is not defined

This error occurs because the Firebase (client) SDK relies on IDBIndex which is only available in Web environment, not server.

Server libs:

firebase-admin
firebase-functions

Client (web) libs:

firebase

SvelteKit is an SSR framework, so understanding which parts of SvelteKit will execute on the server is crucial. Be careful where you use firebase in SvelteKit because sometimes it will try and run during the SSR context.

The adapter works by compiling your SvelteKit SSR dependencies so you shouldn't need to modify your functions/package.json dependencies to support the SvelteKit code that executes on the Cloud Function. All code that SvelteKit needs for Cloud Function will be built when the SvelteKit build happens.

With that cleared up. Here is the breakdown across SvelteKit rendering scenarios:

SSR libs:

firebase-admin

Web libs:

firebase

In your SvelteKit app if you want to use Firebase in SSR you need to use firebase-admin only in the SSR parts of SvelteKit. Similarly, if you want to use Firebase on client side (web) you need to use firebase but only in non-SSR parts of SvelteKit. The two libraries differ slightly in their API and in how they Authenticate to your Firebase project.

SvelteKit is less clear than other libs (like Next.js) on what executes where, which makes the usage more difficult. But the IDBIndex error is the firebase lib trying to execute in a SvelteKit SSR context, and changing Cloud Function function/package.json dependencies won't do anything.

firebase - needs to be imported when in browser, and onMount:

import { browser } from '$app/env';
import { onMount } from 'svelte';

onMount(async () => {
	if (browser) {
		// it is safe to import firebase client sdk
	}
});

firebase-admin - needs to execute in a server environment, since our SSR runs in Cloud Functions that fits:

<script context="module"> & <script> blocks are sometimes SSR, sometimes CSR. You could guard the import using !browser as suggested for client. An easier way is to just use firebase-admin in SvelteKit Endpoints, which always execute in SSR. So any *.json.js file in routes it is safe to use firebase-admin.

Recap:

  • firebase-admin: use in SvelteKit Endpoints.
  • firebase: onMount & browser then you can safely import.

@sebmade
Copy link
Contributor

sebmade commented Jul 16, 2021

thanks @jthegedus for this clear explanation
it works now 👍
in fact I forgot "if (browser)" in an onMount() function, I was thinking it was only call on client side, but it's not, it's also use server side on prerendering : where the previous problem happened

IDBIndex error still there if I put firebase in dependencies rather than devDependencies, I had the same problem with sapper
using only devDependencies let it works

@jthegedus
Copy link
Owner

jthegedus commented Jul 16, 2021

IDBIndex error still there if I put firebase in dependencies rather than devDependencies, I had the same problem with sapper using only devDependencies let it works

I've not had this issue. I have firebase in dependencies & firebase-admin in devDependencies (because it gets compiled into the SSR on build). The IDBIndex will happen when you try and even import the library at the top level.

Here is a snippet from an app:

// $lib/firebase/client.js
import { initializeApp, getApps } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';

const app = getApps().length === 0 ? initializeApp({...}) : getApps()[0];
function firestore() {
	return getFirestore(app);
}
async function performance() {
	const perf = await import('firebase/performance');
	return perf.getPerformance(app);
}
export { firestore, performance };
<!-- __layout.svelte -->
<script>
	import { performance } from '$lib/firebase/client';

	let perf;
	onMount(async () => {
		if (browser) {
			perf = await performance();
		}
	});
</script>

Importing firebase/firestore is fine at the top level, because that lib does not rely on Web deps.

firebase/performace is a different scenario, it relies on IDBIndex which is only available on the web.

The error happens when we import. When we import the file '$lib/firebase/client' the top-level import like firebase/firestore are evaluated. So we defer the imports that require web using the dynamic import. That way firebase/performance is only actually evaluated on function execution.

At least this is my current understanding.

From memory performance and auth are the two libs I have needed to do this. Though there could be more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants