nuxt-community / firebase-module

🔥 Easily integrate Firebase into your Nuxt project. 🔥
https://firebase.nuxtjs.org
MIT License
642 stars 98 forks source link

Nuxt Generate + RealtimeDatabase / Firestore results in "Nuxt Generate finished but did not exit" #93

Closed lupas closed 3 years ago

lupas commented 4 years ago

When using nuxt generate, the following warning appears at the end (after a successful generate)

Problem

Screenshot 2020-11-08 at 15 19 20
⚠ Nuxt Warning 

The command 'nuxt generate' finished but did not exit after 5s
This is most likely not caused by a bug in Nuxt.js
Make sure to cleanup all timers and listeners you or your plugins/modules start.
Nuxt.js will now force exit

DeprecationWarning: Starting with Nuxt version 3 this will be a fatal error  

Possible Solution

It can theoretically be fixed by calling goOffline() for RealtimeDb or terminate() for Firestore after the generate:done hook.

export default {
  hooks: {
    generate: {
      done(builder) {
        $fireDb.goOffline()
        $fireStore.goOffline()
      }
    }
  },

Might be a big issue when Nuxt v3 arrives.

(Originated from https://github.com/lupas/nuxt-fire/issues/90#issuecomment-590052067)

simeon9696 commented 4 years ago

When using nuxt generate, the following warning appears at the end (after a successful generate)

Problem

⚠ Nuxt Warning 

The command 'nuxt generate' finished but did not exit after 5s
This is most likely not caused by a bug in Nuxt.js
Make sure to cleanup all timers and listeners you or your plugins/modules start.
Nuxt.js will now force exit

DeprecationWarning: Starting with Nuxt version 3 this will be a fatal error  

Possible Solution

It can theoretically be fixed by calling goOffline() for RealtimeDb or terminate() for Firestore after the generate:done hook.

export default {
  hooks: {
    generate: {
      done(builder) {
        $fireDb.goOffline()
        $fireStore.goOffline()
      }
    }
  },
  • [ ] Problem now is: How do we access $fireDb or $fireStore in this hook and how do we implement this in nuxt-firebase?

Might be a big issue when Nuxt v3 arrives.

(Originated from #90 (comment))

Any update on this?

mctweb commented 4 years ago

I'd like to add that this is still relevant on the new target: static Nuxt functions; nuxt build & nuxt export

lupas commented 4 years ago

@simeon9696 Not yet, haven't found the time unfortunately. @fmctaggart Thanks for the heads up.

If someone has an idea on how to best approach this, let me know :)

tpiros commented 4 years ago

@lupas I hope you can figure this out, it's been a while since I wished for this "bug" to go away :) I will try to look at the code as well and see if I can figure something out.

simeon9696 commented 4 years ago

@lupas This thread https://github.com/nuxt-community/firebase-module/issues/90 seems to have a solution. However, as you can see by the last comment, when using it with firestore instead of the realtime db it just crashes.

lupas commented 4 years ago

@simeon9696 Thanks. Problem is that we cannot access the nuxt context in the generate-done hook...

@tpiros I know, I wish I had more time for this these days. Let me know if you find a solution. https://github.com/nuxt-community/firebase-module/pull/258 might give us an option to fix this, will have to check when I get time to finally close that PR.

EvanLomas commented 4 years ago

So a short-term solution I've determined from these two posts is:

  1. Move your firebase config to a shared file such as {project_root}/firebase.config.js:
module.exports = {
  apiKey: "...",
  authDomain: "...",
  databaseURL: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "...",
  appId: "...",
  measurementId: "..."
}
  1. Create a plugins/firebaseInit.js file:
import firebase from 'firebase/app'
import 'firebase/database'
import 'firebase/firestore'

if (!firebase.apps.length) {
  firebase.initializeApp(require('../firebase.config.js'))
}

export const fireDb = firebase.database()
export const fireStore = firebase.firestore()
  1. Change your nuxt.config.js to import the config file and add a generate.done() hook around the plugin:
import { fireDb, fireStore } from './plugins/firebaseInit.js'

export default {
  // ...
  modules: [
    // ...
    [
      '@nuxtjs/firebase',
      {
        config: require('./firebase.config.js'),
        services: {
          auth: true,
          realtimeDb: true,
          firestore: true,
          // ...
        }
      }
    ]
  ],
  // ...
  hooks: {
    generate: {
      done(builder) {
        try { fireDb.goOffline() } catch (e) { }
        try { fireStore.terminate() } catch (e) { }
      }
    }
  }
}
tpiros commented 4 years ago

@zeus3rd - works like a charm, thanks for this!

lupas commented 3 years ago

Thanks guys for the discussion and the workarounds.

I don't get the issue anymore with the following versions:

"nuxt": "^2.14.6",
"@nuxtjs/firebase": "^7.0.0",
"firebase": "^8.0.1"

If you guys still get the issue let me know and I'll reopen this.

Update: Turns out the issue still exists

lupas commented 3 years ago

Reopened because issue still exists, also see (https://github.com/nuxt-community/firebase-module/issues/373).

Will try to find a solution that does not require a workaround.

lupas commented 3 years ago

Alright guys, so I found a way to make this work without having to create any additional files. Just do the following in your nuxt.config.js:

hooks: {
  generate: {
    async done(builder) {
      const appModule = await import('./.nuxt/firebase/app.js')
      const { session } = await appModule.default(
        builder.options.firebase.config,
        {
          res: null,
        }
      )
      try {
        session.database().goOffline()
      } catch (e) { }
      try {
        session.firestore().terminate()
      } catch (e) { }
    },
  },
},

What I am doing is:

  1. Take the Firebase config out of builder.options.firebase.config
  2. Get the Firebase instance from ./.nuxt/firebase/app.js
  3. Call goOffline() / terminate() on RealtimeDatabase and Firestore through that instance

I assume that with Nuxt 3 the API and possibly the hooks will change quite a bit so that this has to be reevaluated anyway (maybe we can access the context in the hooks then?). Until Nuxt 3 is released (possibly around Q1 2021) this should be a good workaround.

ToDo's

sugoidesune commented 3 years ago

Fantastic! Works like a charm, this cost me 2 days of hunting and trying. definitely need to learn some more of the indepth nuxt workings. Didnt really know what to do with hooks. (☞゚ヮ゚)☞

sugoidesune commented 3 years ago

Some further development: Adding the firebase session to the generator object like so:

hooks: {
      generate: {
        async before(generator, generateOptions){
          const appModule = await import('./.nuxt/firebase/app.js')
          const {session} = await appModule.default(
            generator.options.firebase.config,
            {
              res: null,
            }
          )
          generator.firebase = session
}}

from that moment on firebase is accessible in all generate hooks.

    hooks: {
      generate: {
   async done(generator) {
          try {
            generator.firebase.database().goOffline()
          } catch (e) { }
          try {
            generator.firebase.firestore().terminate()
          } catch (e) { }
}

I think this would be a nice addition to the module. adding the firebase instance to the generate property and making it accessible

As I am currently extending routes and providing payloads through the generate hooks, I am using it in multiple hooks. Without the need of seperate imports etc.

Thank you for showing me how to work with hooks!

mandalornl commented 3 years ago

I had to import firebase/app instead of ./.nuxt/firebase/app, because the latter could not be found by our docker build server. The following nuxt.config.js example seems to work though.

// nuxt.config.js
export default {
  ssr: true,
  target: 'static',
  modules: [
    '@nuxtjs/firebase'
  ],
  firebase: {
    config: {
      // ...
    },
    services: {
      firestore: true
    }
  },
  hooks: {
    generate: {
      async before(generator) {
        const { default:firebase } = await import('firebase/app');

        await import('firebase/firestore');

        if (!firebase.apps.length) {
          firebase.initializeApp(generator.options.firebase.config);
        }

        generator.firebase = firebase.apps[0];
      },
      done(generator) {
        generator.firebase.firestore().terminate()
          .then(() => console.log('Firestore terminated'))
          .catch(console.error);
      }
    }
  }
}
sugoidesune commented 3 years ago

Yes i posted it as a feature request. nuxt generate doesn't create the .nuxt folder. Therefore for production i run "nuxt build && nuxt generate" nuxt build creates the .nuxt folder and nuxt generate is smart enough not to re-build again, so no time is lost. https://github.com/nuxt/nuxt.js/issues/8365

polymer-coder commented 3 years ago

@mandalornl thanks for posting! Yours is the only one that worked out-of-the-box for me

dolbex commented 3 years ago

Is this already in the docs? If not can I add it through a pr?

lupas commented 3 years ago

@dolbex Yep it's documented here. If you talk about the docker issue/solution mentioned by @mandalornl, this could still be added, feel free to do a PR for it :)

lupas commented 3 years ago

Added an option terminateDatabasesAfterGenerate: true that automatically terminates databases when using nuxt generate with commit https://github.com/nuxt-community/firebase-module/commit/4df37a7add07caa711d556fc00c331ffe66e164e

Will be live with the next version. Might switch it to true by default at some point.

lupas commented 3 years ago

Added option to automatically terminate databases with v7.5.0, hope that works for everyone!

See documentation: https://firebase.nuxtjs.org/guide/options#terminateDatabasesAfterGenerate

mandalornl commented 3 years ago

@lupas Unfortunately now I'm getting a SIGSEGV error during the nuxt generate hook.

error Command failed with signal "SIGSEGV"

Not a lot to work with, but after some fiddling and trial and error, I got it to work by changing just one line in terminateDatabasesInGenerateHooks.

Before:

const { default: firebase } = await import(firebaseDir + 'app')

After:

const firebase = require(firebaseDir + 'app')

Maybe also include the firestore and database modules, just to be safe?

require(firebaseDir + 'firestore')
require(firebaseDir + 'database')
lupas commented 3 years ago

@mandalornl Not a big fan of adding code "just to be safe".. The import of Firestore & Database should not be needed since we already import them when instantiating them.

Thanks for letting me know about the SIGSEGV error, interesting. It's working just fine for me. Can you share some details about your environment? Does that error only appear within docker? Which node.js version are you using? Have you tried using a more current version?

It does work for me as well when using require(), so I might change the code to that, but first would like to know what the issue could be.

Thanks for your support!

mandalornl commented 3 years ago

@lupas Your welcome!

Not a big fan of adding code "just to be safe".. The import of Firestore & Database should not be needed since we already import them when instantiating them.

Yeah, maybe not the best analogy, but I came across this issue in another totally unrelated instance. It does seems to work just fine without the extra require lines, so just forget about it.

Can you share some details about your environment? Does that error only appear within docker? Which node.js version are you using? Have you tried using a more current version?

Tested it locally on macOS High Sierra and Node 14.15.5 (LTS) and remotely on a Docker 14.15.1-alpine image. I haven't tried a more current version, because I like to stick to LTS versions by default.

lupas commented 3 years ago

@mandalornl Thanks! Tested it with Node 14 and even earlier versions and it worked for me, also on macOS, so I wonder what that could be that it works for me.

Re-opened the issue until this is fixed.

ToDo

mandalornl commented 3 years ago

@lupas Ok, so I decided to give terminateDatabasesInGenerateHooks from v7.5.0 a try again today and somehow the SIGSEGV error, I was having before, seems to have vanished.

I've tested it in two different projects, just to be sure, and no errors whatsoever, only a gentle Firestore manually terminated. message. Still using the same environment as before. So feel free to close this issue again.

lupas commented 3 years ago

@mandalornl Alright, thanks for the update! Will close it for now in that case!