My NextJS bundle size seems to be huge (200-300 kB first load per page). I ran the bundle analyzer, and the culprit seems to be Firebase, which I use for user auth, storing data in Firestore, and calling Firebase functions. I have seen strategies to reduce bundle sizes like using dynamic imports, but I think the issue has more to do with how I am instantiating Firebase. This is what I am doing:
clientApp.ts :
import firebase from "firebase/compat/app";
import "firebase/compat/auth";
import "firebase/compat/firestore";
import "firebase/compat/functions";
const clientCredentials = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
if (!firebase.apps.length) {
firebase.initializeApp(clientCredentials);
}
const firebaseFunctions = firebase.functions();
firebaseFunctions.useEmulator("localhost", 5001);
export const auth = firebase.auth();
export const db = firebase.firestore();
export const functions = firebaseFunctions;
AuthContext.tsx :
import React from "react";
import firebase from "firebase/compat/app";
export const AuthContext = React.createContext<firebase.User | null>(null);
_app.tsx :
import "../styles/globals.css";
import type { AppProps } from "next/app";
import { AuthProvider } from "../provider/AuthProvider";
function MyApp({ Component, pageProps }: AppProps) {
return (
<AuthProvider>
<div className="h-screen w-screen overflow-y-hidden">
<Component {...pageProps} />
</div>
</AuthProvider>
);
}
export default MyApp;
Then, I call const user = useContext(AuthContext); in my pages to get the user session data. To use Firestore or functions, I import db or functions from clientApp.ts. Does this make sense or is it ineficiente and contributing to the large bundle size?
I have tried dynamic imports, but either I did not implement them correctly or they are not helpful in this situation.
You're using the compatibility layer of Firebase's modular SDKs, so that you can run code that uses the older namespaced syntax. Unfortunately using this compatibility layer and syntax prevents your build tool from tree-shaking any unused code.
The solution is to use the newer modular syntax of the SDKs, as shown in the upgrade guide and in all samples in the documentation. I also recommend checking out Deep dive into the new Firebase JS SDK design and The new Firebase JS SDK is now GA on the Firebase blog.
Related
When I use imports enabling type:module in the package json file I can use without problems the imports such as import { ref, set,child ,getDatabase,onValue,get,push, update} from "firebase/database"; and access the data, but I want to interact with that information with inputs or text areas but I cannot access those it throws document is not defined.!
I have read many pages but as I am new I cannot get it. I cannot apply the answer to my project.
import { ref, set,child ,getDatabase,onValue,get,push, update} from "firebase/database";
import { getAuth, onAuthStateChanged } from "firebase/auth";
//to get info from firebase
var headbox = document.getElementById('a'); // from Html to manage info send and show it here
var bodybox = document.getElementById('b'); // error when I want to read this
Although if I take those imports out and erase type:module in the package json file, I can use document.getById but I cannot use imports please help me! I am new
type: module in package.json is for use in Nodejs environments, hence the error. Backend has no document or even window object.
What you are doing is frontend, so setting up a frontend environment using vite/webpack (preferably vite), would do you some justice.
vite is really easy to setup for what you are doing. Vite Getting Started Guide.
You just place your index.html at the root of your working folder and run it's commands. It loads very quickly.
The Firebase Web SDK ideally requires module bundlers (Webpack/Rollup) or JavaScript framework tooling like Vue, React, Angular, etc because the Web SDK (or at least version 9) is optimized to work with module bundlers to eliminate unused code (tree-shaking) and decrease SDK size.
Sounds like you would be better off using CDN (content delivery network).
JavaScript
import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.15.0/firebase-app.js';
import { ref, set, child, getDatabase, onValue, get, push, update } from 'https://www.gstatic.com/firebasejs/9.15.0/firebase-database.js';
import { getAuth, onAuthStateChanged } from 'https://www.gstatic.com/firebasejs/9.15.0/firebase-auth.js';
const firebaseConfig = {
apiKey: 'xxx',
authDomain: 'xxx',
projectId: 'xxx',
storageBucket: 'xxx',
messagingSenderId: 'xxx',
appId: 'xxx',
measurementId: 'xxx'
};
const firebaseApp = initializeApp(firebaseConfig);
const auth = getAuth();
window.addEventListener('DOMContentLoaded', (event) => {
const headbox = document.getElementById('a');
const bodybox = document.getElementById('b');
onAuthStateChanged(auth, (user) => {
if (user) {
// user.uid
}
});
});
HTML
<html>
<head>
...
</head>
<body>
<div id="a">Head Box</div>
<div id="b">Body Box</div>
<script type="module" src="your-javascript-file.js"></script>
</body>
</html>
I ran
npm i firebase
and have
import firebase from 'firebase/compat/app'
but when i run
console.log(firebase.auth())
I get an error message of
app.js:280 Uncaught FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app-compat/no-app).
at app (firebaseNamespaceCore.ts?1484:102:1)
at Object.serviceNamespace [as auth] (firebaseNamespaceCore.ts?1484:152:1)
at eval (HelloWorld.vue?e90b:24:1)
at Module../node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/HelloWorld.vue?vue&type=script&lang=js (app.js:30:1)
at __webpack_require__ (app.js:277:33)
at fn (app.js:517:21)
at eval (HelloWorld.vue?vue&type=script&lang=js:5:213)
at Module../src/components/HelloWorld.vue?vue&type=script&lang=js (app.js:140:1)
at __webpack_require__ (app.js:277:33)
at fn (app.js:517:21)
However, when I just run console.log(firebase) I get correct data output in console. I have also setup firebase correctly as documented here but firebause.auth() is still not working. I am working in Vue3 but I don't think that part matters, still trying to find a solution.
I am currently trying to get firebaseUI to work and this is the step I am getting stuck in. Once I'm able to get firebause.auth() to work, I'll be able to initialize the firebaseUI widget by running:
var ui = new firebaseui.auth.AuthUI(firebase.auth());
my ./src/firebaseConfig.js code:
import { initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: "code",
authDomain: "code",
projectId: "code",
storageBucket: "code",
messagingSenderId: "code",
appId: "code",
measurementId: "code"
};
const firebaseApp = initializeApp(firebaseConfig);
export default firebaseApp
My component file using firebaseConfig.js in ./src/components/HellowWorld.vue :
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<div id="sign-in-status"></div>
<div id="sign-in"></div>
<pre id="account-details"></pre>
</div>
</template>
<script>
import firebaseConfig from '../firebaseConfig';
import firebase from 'firebase/compat/app';
import * as firebaseui from 'firebaseui'
import 'firebaseui/dist/firebaseui.css'
console.log(firebaseConfig);
console.log(firebase);
// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
ui
export default {
name: 'HelloWorld',
props: {
msg: String
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
both
console.log(firebaseConfig);
console.log(firebase);
works but
// Initialize the FirebaseUI Widget using Firebase.
var ui = new firebaseui.auth.AuthUI(firebase.auth());
ui
produces an error as copy and pasted above.
I had same problem, then I found points. And I understood why somebody was OK, others was bug.
Initialization needs to App based, of course before call firebaseUI. We have some ways to do that
main.js, import configuration.js, before auth timing...etc.
Initialized firebaseApp (your firebaseConfig.js) is different from import firebase from 'firebase/compat/app'
If new firebaseUI is called before Initialization or no initialized, we get error. Then take care Lifecycle of Vue.
Probably you need,
Import firebaseApp, Not firebaseConfig to HellowWorld.vue for getting Initialized.
In my case, my 'new firebaseUI' is in mounted() of ChildView. I initialize firebaseApp at main.ts, so childView doesn't need initialization any more, only import firebase from 'firebase/compat/app'.
If you need code, I can show you my case.
So I started taking a look into firebase and just after defining the intialization as
import firebase from "firebase/compat"
const firebaseConfig = {
apiKey: process.env.REACT_APP_API_KEY,
authDomain: process.env.REACT_APP_AUTH_DOMAIN,
projectId: process.env.REACT_APP_PROJECT_ID,
storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_APP_ID,
measurementId: process.env.REACT_APP_MEASUREMENT_ID
};
const chatSupportApp = firebase.initializeApp(firebaseConfig, "my-app");
A wild warning was display!
/*It looks like you're using the development build of the Firebase JS SDK.
When deploying Firebase apps to production, it is advisable to only import
the individual SDK components you intend to use.
For the module builds, these are available in the following manner
(replace <PACKAGE> with the name of a component - i.e. auth, database, etc):
CommonJS Modules:
const firebase = require('firebase/app');
require('firebase/<PACKAGE>');
ES Modules:
import firebase from 'firebase/app';
import 'firebase/<PACKAGE>';
Typescript:
import firebase from 'firebase/app';
import 'firebase/<PACKAGE>';*/
I search in many posts, including documentation and didn't really get how to initialize my app first before using any of the other imports
I found out lately that is was a bit hidden under "firebase/firebase-app"
so it get solved, as
import {initializeApp} from "firebase/firebase-app";
const firebaseConfig = {
apiKey: ...............
};
const chatSupportApp = initializeApp(firebaseConfig, "my-app");
export default chatSupportApp;
This started as a question that I search in most stack overflow posts, but since I solve it for now somehow I wanted also to share with the community in here, but also consider any other suggestion, the question will be then.
Is this approach correct? why all the documentation suggest to do it with
import { initializeApp } from 'firebase/app'; as:
import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged, getRedirectResult } from 'firebase/auth';
This really didn't work for me at all and I was not able to use it.
Thanks and enjoy your code!
import {initializeApp} from "firebase/firebase-app";
const firebaseConfig = {
apiKey: ...............
};
const chatSupportApp = initializeApp(firebaseConfig, "my-app");
export default chatSupportApp;
I'm trying to use firebase-ui in a VueJS project.
My api credentials is defined in a file called config.js
export default {
apiKey: "*****",
authDomain: "*****.firebaseapp.com",
databaseURL: "https://my-project.firebaseio.com",
projectId: "*****",
storageBucket: "*****",
messagingSenderId: "73482979",
appId: "1:685818581200:web:1f5ebjnfsdjnj",
measurementId: "G-BHJK6N67PZ"
};
I am the importing the config.js file in my init.js where the whole firebase setup is done:
import config from "./config";
import firebase from "firebase";
import firebaseui from "firebaseui";
import "firebase/auth";
import "firebase/firestore";
const app = firebase.initializeApp(config);
const auth = firebase.auth();
const firestore = app.firestore();
const authUi = new firebaseui.auth.AuthUI(auth); //Error is thrown at this point
export default app;
export { auth, authUi, firestore };
However the error -> Cannot read property 'auth' of undefined' is thrown and I've been unable to move past here for a few days now. I've checked the documentation (https://firebase.google.com/docs/auth/web/firebaseui#before_you_begin), everything is done correctly and even using the latest firebaseui version "firebaseui": "4.7.0" located in package.json
Any help with how I can solve this problem?
As of Firebase 9.0.0 (August 25, 2021) it should now be
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
to use the backwards compatible interface.
See https://firebase.google.com/docs/web/modular-upgrade for the full upgrade path
I got the same problem. After few hours of trying, I solve it by edit my config like :
import firebase from 'firebase/app';
import * as firebaseui from 'firebaseui';
import 'firebaseui/dist/firebaseui.css';
If your firebase version if greater than 7, you got to import from 'firebase/app' instead of 'firebase'.
And you have to import * from 'firebaseui', instead of import only firebaseui.
and my packages.json like:
"dependencies": {
"firebase": "^8.8.0-202162022140",
"firebaseui": "^4.8.1",
},
By the way, my project is using Vue3.js.
You're importing the Firebase client JS library incorrectly. The documentation for module bundlers shows:
// Firebase App (the core Firebase SDK) is always required and must be listed first
import firebase from "firebase/app";
// If you are using v7 or any earlier version of the JS SDK, you should import firebase using namespace import
// import * as firebase from "firebase/app"
Don't import from "firebase". Import from "firebase/app", and be sure to observe the conventions for the version of the SDK you're using.
The documentation for firebaseui might be out of date. Consider submitting your feedback using the "send feedback" button at the top of the doc page.
I'm developing an App using React Native and Firebase. So, I created a separate js file to store config of firebase database and then I imported that config file into my screen files when I need to connect with firebase database.
So, I have to import that config file into each and every screen file which I need connect with my firebase database.
I want to know that, is it possible to import that config file globally?
I mean, I create a separate config file, then import it only once into a particular js file (Just for an example, let's think, import it only once into the App.js file) and then, use it in my screen files whenever I need to connect with my firebase database. But in this case, is it possible to use that config file without importing it into each and every screen file?
Hope you will understand what I want to do.
Yes, you just import the file in your main screen/ app entry point.
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/database';
import 'firebase/storage';
const config = {
apiKey: "API_KEY",
authDomain: "DOMAIN",
databaseURL: "DB_URL",
projectId: "PROJECT_ID",
storageBucket: "BUCKET",
messagingSenderId: "MSG_ID",
appId: "APP_ID"
};
app.initializeApp(config);
module.Store = {
Firebase() {
return app;
},
}
if (global) {
global.Store = module.Store;
}
In your main screen
import './Global';
all the functions in Global will be available to all screens.
Demo