Skip to content

Fix imports after Nuxt 3.17.6 in dev mode #1628

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions packages/nuxt/src/runtime/admin/plugin.server.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { type App as AdminApp } from 'firebase-admin/app'
import type { App as AdminApp } from 'firebase-admin/app'
import { ensureAdminApp } from 'vuefire/server'
import { defineNuxtPlugin, useRequestEvent, useRuntimeConfig } from '#imports'

export default defineNuxtPlugin(() => {
export default defineNuxtPlugin(async () => {
const event = useRequestEvent()
const { vuefire } = useRuntimeConfig()

const firebaseAdminApp = ensureAdminApp(vuefire?.admin?.options)
const firebaseAdminApp = await ensureAdminApp(vuefire?.admin?.options)

// TODO: Is this accessible within middlewares and api routes? or should we use a middleware to add it
event.context.firebaseApp = firebaseAdminApp
if (event) {
event.context.firebaseApp = firebaseAdminApp
}

return {
provide: {
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/src/runtime/auth/api.session-verification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default defineEventHandler(async (event) => {
const { token } = await readBody<{ token?: string }>(event)
const runtimeConfig = useRuntimeConfig()

const adminApp = ensureAdminApp(
const adminApp = await ensureAdminApp(
{
// NOTE: ensured by the module
projectId: runtimeConfig.public.vuefire!.config!.projectId,
Expand Down
42 changes: 33 additions & 9 deletions src/server/admin.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import {
initializeApp as initializeAdminApp,
cert,
getApps as getAdminApps,
applicationDefault,
// renamed because there seems to be a global Credential type in vscode
// Dynamic imports to handle Nuxt 3.17.6+ Vite environment changes
import type {
Credential as FirebaseAdminCredential,
AppOptions,
} from 'firebase-admin/app'

let adminAppModule: any

// Use dynamic import in development, static import in production
async function getFirebaseAdminApp() {
if (!adminAppModule) {
// Check if we're in development mode
const isDev = process.env.NODE_ENV !== 'production'

if (isDev) {
// Use require in development mode to work around Vite environment changes
adminAppModule = require('firebase-admin/app')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks but this doesn't look like the right fix...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback. It works, but if you got another idea let me know so I can test / try it out. What was in your mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Nuxt/vite are not resolving correctly something. Sometimes some unintuitive workarounds are needed in Nuxt modules to avoid duplication or resolving the wrong version. You can see it here and in pinia modules. Good luck!

} else {
// Use dynamic import in production
adminAppModule = await import('firebase-admin/app')
}
}
return adminAppModule
}

import { logger } from './logging'

const FIREBASE_ADMIN_APP_NAME = 'vuefire-admin'
Expand All @@ -18,14 +34,22 @@ const FIREBASE_ADMIN_APP_NAME = 'vuefire-admin'
* @param name - name of the app
* @experimental this is experimental and may change in the future
*/
export function ensureAdminApp(
export async function ensureAdminApp(
firebaseAdminOptions?: Omit<AppOptions, 'credential'>,
name = FIREBASE_ADMIN_APP_NAME
) {
// Get Firebase Admin SDK functions dynamically
const {
initializeApp: initializeAdminApp,
cert,
getApps: getAdminApps,
applicationDefault,
} = await getFirebaseAdminApp()

// only initialize the admin sdk once
logger.debug(`Checking if admin app "${name}" exists...`)

if (!getAdminApps().find((app) => app.name === name)) {
if (!getAdminApps().find((app: any) => app.name === name)) {
const {
// these can be set by the user on other platforms
FIREBASE_PROJECT_ID,
Expand Down Expand Up @@ -120,5 +144,5 @@ export function ensureAdminApp(
}

// we know have a valid admin app
return getAdminApps().find((app) => app.name === name)!
return getAdminApps().find((app: any) => app.name === name)!
}