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
我在我的项目中使用 Firebase 进行身份验证。用户通过身份验证后,我在 cookie 中设置了 his/her id token,以便下次向仅授权页面发出任何请求时,我可以验证 SSR 的服务器端令牌。
但是,我为此编写的包装器函数在 getServerSideProps
.
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