Next.js getServerSideProps 中的 'ReferenceError' 导入函数错误

Next.js imported function errors out with 'ReferenceError' in getServerSideProps

我在我的项目中使用 Firebase 进行身份验证。用户通过身份验证后,我在 cookie 中设置了 his/her id token,以便下次向仅授权页面发出任何请求时,我可以验证 SSR 的服务器端令牌。

但是,我为此编写的包装器函数在 getServerSideProps.

中使用时出错为 'ReferenceError'

lib/firebase-admin.ts

import { initializeApp, App, AppOptions } from 'firebase-admin/app'
import { getAuth, Auth } from 'firebase-admin/auth'
import { credential } from 'firebase-admin'
import serviceAccount from '../secrets/firebase-admin-sdk.json'

// Firebase Admin app configs
const firebaseAdminConfig: AppOptions = {
    credential: credential.cert(JSON.stringify(serviceAccount))
}
// Get app admin instance and export it
const app: App = initializeApp(firebaseAdminConfig)
export default app

// Get auth admin and export
export const auth: Auth = getAuth(app)

utils/auth-server.ts

import { auth } from '../lib/firebase-admin'
import { DecodedIdToken } from 'firebase-admin/auth'
import AuthErrorMessages from '../constants/auth'

// Export function to verify id token in server side
interface IVerifyIdToken {
    status: boolean
    message?: string
    token?: DecodedIdToken
}

export const verifyIdToken = async (idToken: string): Promise<IVerifyIdToken> => {
    try {
        const decodedIdtoken = await auth.verifyIdToken(idToken, true)
        console.log(decodedIdtoken)
        return { status: true, token: decodedIdtoken }
    } catch (e) {
        return { status: false, message: e }
    }
}

components/test.tsx

import { GetServerSideProps, GetServerSidePropsContext, InferGetServerSidePropsType } from 'next'
import nookies from 'nookies'
import { verifyIdToken } from '../utils/auth-server'

export const getServerSideProps: GetServerSideProps = async (ctx: GetServerSidePropsContext) => {
    const cookies = nookies.get(ctx)
    if (cookies.token) {
        const idToken = await verifyIdToken(cookies.token) // ERROR HERE
        console.log(idToken)
        return {
            props: {
                email: 'DUMMY'
            }
        }
    } else {
        return {
            props: {
                email: "NO EMAIL (not logged in)"
            }
        }
    }
}

export default function Test({ email }: InferGetServerSidePropsType<typeof getServerSideProps>) {
    return (
        <p>Your email: {email}</p>
    )
}

打开 /test 时出错

ReferenceError: Cannot access 'auth' before initialization
      at Module.auth (webpack-internal:///./lib/firebase-admin.ts:5:53)
      at verifyIdToken (webpack-internal:///./utils/auth-server.ts:12:87)
      at getServerSideProps (webpack-internal:///./pages/test.tsx:20:96)
      at Object.renderToHTML (/home/captain-woof/Desktop/charity-cms/node_modules/next/dist/server/render.js:479:26)
      at runMicrotasks (<anonymous>)
      at processTicksAndRejections (internal/process/task_queues.js:97:5)
      at async doRender (/home/captain-woof/Desktop/charity-cms/node_modules/next/dist/server/next-server.js:1392:38)
      at async /home/captain-woof/Desktop/charity-cms/node_modules/next/dist/server/next-server.js:1487:28
      at async /home/captain-woof/Desktop/charity-cms/node_modules/next/dist/server/response-cache.js:63:36

我解决了问题! (感谢@ArneHugo 的提示)

所以,发生的并不是真正的循环依赖,而是异步编译的文件,因此无法实际控制首先编译的内容。

我做了一个小改动解决了这个问题:

lib/firebase-admin.ts

.
.
.
const serviceAccount = require('../secrets/firebase-admin-sdk.json') // Earlier -> import serviceAccount from '../secrets/firebase-admin-sdk.json'
.
.
.
credential: credential.cert(serviceAccount) // Earlier -> credential: credential.cert(JSON.stringify(serviceAccount))
.
.
.
// REPLACE ENTIRE BELOW PORTION WITH THIS
// Get app admin instance and export it
if (getApps().length === 0) { // To make sure only one instance is created and referred to at a time
    initializeApp(firebaseAdminConfig)
}

// Get auth admin and export
export const auth: Auth = getAuth(getApp()) // To make sure auth from only the one app instance we have is exported