Skip to content

Support emulators #1270

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
TitusKirch opened this issue Dec 27, 2022 · 4 comments · Fixed by #1392
Closed

Support emulators #1270

TitusKirch opened this issue Dec 27, 2022 · 4 comments · Fixed by #1392
Assignees

Comments

@TitusKirch
Copy link

What problem is this solving

For local development, the Firebase emulators are very helpful. In my opinion, support for these would be a great added value for this extension.

Proposed solution

In my opinion, the nicest solution would be to be able to specify the hosts and ports for each emulator via the config and, if it is set and the host is localhost, use it, e.g. like this: https://firebase.google.com/docs/emulator-suite/connect_rtdb

Describe alternatives you've considered

No response

Copy link
Member

posva commented Dec 27, 2022

This is in the roadmap for Nuxt to be automatic. Otherwise one only need to call the different connectEmulator functions exposed by Firebase. Probably worth a mention in the docs

Copy link
Author

Ohw, my mistake, I had forgotten that it was specifically about the Nuxt plugin.

Yes, I have noticed that things are missing here and there in the docs. I am currently working myself into the extension here and will probably soon contribute something to the documentation.

@DevJoghurt
Copy link

Maybe it would be better to take the configuration of the emulator from the firebase.json. Then there would be only one place where you have to make the setting and there would be less error possibilities.

@Soviut
Copy link
Contributor

Soviut commented Feb 23, 2023

I've got a project where I got the emulators starting on Vite start. There is vite-plugin-firebase however, it is seemingly not actively maintained. Both issues I logged on that repo I was able to fix in by making a local copy of the code.

The following Vite plugin will start and stop the emulators cleanly as well as optionally import emulator data.

vite-plugin-firebase.ts

// based on https://github.com/divriots/vite-plugin-firebase
// and https://firebase.google.com/docs/emulator-suite/install_and_configure#export_and_import_emulator_data

import fs from 'fs'
import path from 'path'
import { ViteDevServer } from 'vite'
import { setupLoggers } from 'firebase-tools/lib/utils.js'
import { getProjectDefaultAccount } from 'firebase-tools/lib/auth.js'
import { Config } from 'firebase-tools/lib/config.js'
import { setActiveAccount } from 'firebase-tools/lib/auth.js'
import {
  materializeAll,
  ensureApi,
} from 'firebase-tools/lib/functionsConfig.js'
import { requireAuth } from 'firebase-tools/lib/requireAuth.js'
import {
  startAll,
  cleanShutdown,
} from 'firebase-tools/lib/emulator/controller.js'
// import { shutdownWhenKilled } from 'firebase-tools/lib/emulator/commandUtils.js'

export interface FirebasePluginOptions {
  projectId: string | ((server: ViteDevServer) => string)
  projectName: string | ((server: ViteDevServer) => string)
  root?: string
  materializeConfig?: boolean
  targets: string[]
  showUI: boolean
  importDir?: string
}

export default function firebasePlugin({
  projectId,
  projectName = projectId,
  root,
  materializeConfig,
  targets = ['hosting', 'functions'],
  showUI = false,
  importDir = '',
}: FirebasePluginOptions) {
  return {
    name: 'vite:firebase',
    async configureServer(server: ViteDevServer) {
      if (server.config.command !== 'serve') return

      const projectDir = root || server.config.root

      if (!process.env.IS_FIREBASE_CLI) {
        process.env.IS_FIREBASE_CLI = 'true'
        setupLoggers()

        // we are already doing this on sigterm
        // shutdownWhenKilled({})
      }

      if (typeof projectId !== 'string') projectId = projectId(server)
      if (typeof projectName !== 'string') projectName = projectName(server)

      const account = getProjectDefaultAccount(projectDir)

      const options = {
        projectId,
        project: projectName,
        projectDir,
        nonInteractive: true,
        account,
        only: targets.join(','),
        targets,
        import: importDir,
        config: {},
      }

      const config = Config.load(options)
      options.config = config

      if (account) {
        setActiveAccount(options, account)
      }

      if (materializeConfig) {
        await requireAuth(options)
        await ensureApi(options)
        const settings = await materializeAll(projectId)
        const functionsDir = config.data.functions.source
        await fs.promises.writeFile(
          path.join(functionsDir, '.runtimeconfig.json'),
          JSON.stringify(settings)
        )
      }

      await startAll(options, showUI)

      // patch server.close to close emulators as well
      // const { close: closeServer } = server
      // server.close = async () => {
      //   await Promise.all([closeServer(), cleanShutdown()])
      // }

      const shutdown = async () => {
        await cleanShutdown()
        // await server.close()

        // this prevents the process from hanging after server close
        process.exit(0)
      }

      process.on('SIGINT', shutdown)
      process.on('SIGTERM', shutdown)
    },
  }
}\

vite.config.ts

export default defineConfig({
  plugins: [
    vue(),
    firebasePlugin({
      projectName: 'xxx',
      projectId: 'xxx-123',
      targets: ['firestore', 'functions', 'storage'],
      showUI: true,
      importDir: 'data',
    }),
  ],

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants