3

Hey y'all really struggling here.

I am trying use firebase in my Next.js app, specifically for the api. It works fine when I build production locally, and on local development. But once I deploy to production on the vercel platform I get a 500 - Internal Server Error. I have been able to narrow down the error to it being being caused by using await getDocs(q) but not sure how to fix it.

Essentially I am trying to do dynamic api routing with data from firestore.

firebase.js:

// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";

// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries

// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
  apiKey: "<REDACTED_FOR_STACKOVERFLOW>",
  authDomain: "<REDACTED_FOR_STACKOVERFLOW>",
  databaseURL: "<REDACTED_FOR_STACKOVERFLOW>",
  projectId: "<REDACTED_FOR_STACKOVERFLOW>",
  storageBucket: "<REDACTED_FOR_STACKOVERFLOW>",
  messagingSenderId: "<REDACTED_FOR_STACKOVERFLOW>",
  appId: "<REDACTED_FOR_STACKOVERFLOW>",
  measurementId: "<REDACTED_FOR_STACKOVERFLOW>"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Database
const db = getFirestore();
// Storage
const storage = getStorage(app)

export {
  app,
  storage,
  db
}

/api/users/[name].js:

import { db } from './firebase.js'

export default async function handler(req, res) {
  try {
    const { name } = req.query
    let users = []
    const q = query(collection(db, "users"), where("name", "==", name))
    const querySnapshot = await getDocs(q)
    if (querySnapshot.empty) {
      res.status(404).json({error: "Document does not exist."})
    } else {
      querySnapshot.forEach((doc) => {
        users.push(doc.data())
      })
      res.status(200).json(users)
    }
  } catch(err) {
    res.status(404).json({error: err})
  }
}

package.json:

{
  "name": "app-frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@headlessui/react": "^1.4.2",
    "@heroicons/react": "^1.0.5",
    "bootstrap": "^4.6.0",
    "classnames": "^2.2.6",
    "next": "11.0.1",
    "firebase": "^9.5.0",
    "postcss-custom-properties": "^8.0.11",
    "postcss-flexbugs-fixes": "^5.0.2",
    "postcss-import": "^14.0.2",
    "postcss-nested": "^5.0.5",
    "postcss-nesting": "^8.0.1",
    "postcss-preset-env": "^6.7.0",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-icons": "^4.2.0",
    "react-markdown": "^6.0.2",
    "react-pro-sidebar": "^0.6.0",
    "react-remark": "^2.0.3",
    "rehype-raw": "^5.1.0",
    "rehype-react": "^6.2.1",
    "remark-html": "^13.0.1",
    "remark-react": "^8.0.0",
    "remark-rehype": "^8.1.0",
    "sass": "^1.35.1",
    "xhr2": "^0.2.1"
  },
  "devDependencies": {
    "autoprefixer": "^10.2.6",
    "eslint": "7.29.0",
    "eslint-config-next": "11.0.1",
    "postcss": "^8.3.5",
    "tailwindcss": "^2.2.4"
  }
}

The error on the server side starts off like this: @firebase/firestore: Firestore (9.5.0): INTERNAL UNHANDLED ERROR: Error: ENOENT: no such file or directory, open '/var/task/node_modules/@firebase/firestore/dist/src/protos/google/firestore/v1/firestore.proto'

Mario Lopez
  • 67
  • 1
  • 10

4 Answers4

1

Downgrading firebase to 9.4.0 solves the exact issue for me. I'm not sure if it's a good fix, but it works.

0

The issue is that somehow the dependencies was installed in local package node_modules but not defined on package.json.

You need to define it on package.json so it will be installed on the building stage

on project folder, open terminal and install it so it will be added in the package :

npm install --save firebase
Chemi Adel
  • 1,964
  • 1
  • 10
  • 18
0

For this, if you are using handler function in getServerSideProps or other functions in index.js, try using the code below:

const q = query(collection(getFirestore(app), "users"), where("name", "==", name))

This worked for me. Thanks

-1

I faced the same issue for a while. The problem is that you are using the approach to initializeApp in the client.

for a nodejs, or server based initailization do this:

  • go to firebase console, and in Project Settings > service account, export a new key (that export a json file, that you should sit in the root of the project)

  • then create utils/db.js and inside import that json file and initialize the app:

import serviceAccount from "./file.json";

if (!admin.apps.length) {
  try {
    admin.initializeApp({
      credential: admin.credential.cert(serviceAccount),
    });
  } catch (error) {
    console.log("Firebase admin initialization error", error.stack);
  }
}
export default admin.firestore();

wala. If you use both, SSR and CSR, keep both approaches for client side and server side firebase connnection.

then in your pages/api/whetever.js

import db from "/utils/db.js";

export default async function handler(req, res) {
  try {
    const entries = await db.collection("collection").get();
    const entriesData = entries.docs.map((entry) => ({
      id: entry.id,
      ...entry.data(),
    }));
    res.status(200).json({ entriesData });
  } catch (e) {
    res.status(400).end();
  }
}

test by calling localhost:3000/api/whatever

Luchux
  • 803
  • 1
  • 7
  • 17