vuefire icon indicating copy to clipboard operation
vuefire copied to clipboard

How to use Nuxt with VueFire and SSR

Open ReeVicente opened this issue 5 years ago • 22 comments

I dont understand how that works, please add to dock or give me a example

ReeVicente avatar Aug 18 '18 13:08 ReeVicente

It is indeed missing the docs. The whole idea goes around $bind returning a promise that resolves once the data is ready. So you can wait for it in asyncData:

data: () => ({ items: [] }), // initialise items
async asyncData () {
  await this.$bind('items', db.collection('items'))
  // no need to return the data as it is bound in data  
  return {}
}

posva avatar Nov 19 '18 18:11 posva

@posva you don't have access to this from asyncData https://nuxtjs.org/api/

dac3971 avatar Nov 22 '18 01:11 dac3971

Forgot about that! With vuexfire you can still access the store from the context passed to asyncdata but with vuefire it's a bit different. It should be possible to call $bind through the Vue constructor with something like Vue.prototype.$bind.call({}) and await that promise in one asyncdata property but I need to check a bit more since the whole point of using bind was to make it work both on client and on server

posva avatar Nov 22 '18 08:11 posva

Hi All,

I could not find this.$bind in Nuxt's asyncData(), but I could find this.$nuxt.$bind in Nuxt's asyncData.

I tried something below and no success

data: () => ({ text: '' }), // initialise items
async asyncData () {
  const ref = db.collection('test').doc('test')
  const snap = await ref.get()
  await this.$nuxt.$bind('text', snap.data().text)
  // await this.$nuxt.$bind('text', 'Today is a good day.') // also not working by giving a value directly.
  return
}

I use Nuxt plugin to add vue-fire

max8hine avatar Jan 21 '19 06:01 max8hine

This is not yet supported on vuefire package. It's only supported by vuexfire since you can await an action in fetch or asyncdata. I need to find a way to fix hydration and will expose a nuxt plugin or module in the future to enable ssr wot vuefire.

posva avatar Jan 21 '19 11:01 posva

This is not yet supported on vuefire package. It's only supported by vuexfire since you can await an action in fetch or asyncdata. I need to find a way to fix hydration and will expose a nuxt plugin or module in the future to enable ssr wot vuefire.

Is there any update on this? Would be really awesome

agcty avatar May 11 '19 11:05 agcty

No updates no. For the moment use vuexfire, it's more adapted to bigger apps anyway :). When you are doing SSR, your app isn't that simple anymore.

posva avatar May 11 '19 12:05 posva

@posva I understand the vuexfire repo has now been archived, but is there any chance you could take another look at https://github.com/posva/vuexfire/issues/124#issuecomment-469146657 and address it here?

I linked to a (not working) demo repo in that thread. Someone just commented on the demo, also looking for help with Nuxt and vuexfire, but I still haven't figured it out.

Thanks so much for your hard work!

chasebank avatar Jun 08 '19 06:06 chasebank

vuexfire is now here, that's why it got archived. I'll paste the example I put there about how to use Vuexfire with Nuxt:

// firebase/index.js
import { firebase } from '@firebase/app'
import 'firebase/firestore'
import 'firebase/auth'

const config = {
  apiKey: '...',
  authDomain: '...',
  projectId: '...',
}

export const db = firebase.initializeApp(config).firestore()


// Export utility functions
export const { Timestamp } = firebase.firestore
// firebase/collections.js
import { db } from './index'

export const users = db.collection('users')
export const matches = db.collection('matches')
// store/index.js
import { vuexfireMutations as mutations } from 'vuexfire'

export const state = () => ({})

export { mutations }
// store/matches.js
import { firestoreAction } from 'vuexfire'
import { matches, users } from '../firebase/collections'

// omitting state, mutations, getters

const actions = {
  subscribeToAllMatches: firestoreAction(({ bindFirestoreRef }) => {
    return bindFirestoreRef('matches', matches)
  }),
  // async version
  subscribeToMatch: firebasestore(async ({ bindFirestoreRef }, { matchRef ) => {
    await bindFirestoreRef('match', matchRef)
  }),
}

pages/matches.vue

<template>
  <div>
    <ul>
      <li v-for="match in matches">{{ match }}</li>
    </ul>
  </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
  computed: mapState('matches', ['matches']),

  // return a promise
  fetch({ store }) {
    return store.dispatch('matches/subscribeToAllMatches')
  },
}
</script>

posva avatar Jun 08 '19 06:06 posva

@posva That's not working for me! I got 'this. subscribetoAllMatches is not a function' error at the fetch hook. But in the create hook it works.

krisztianodor avatar Jun 11 '19 01:06 krisztianodor

@posva is the nuxt plugin going to be another package?

trickstival avatar Jun 17 '19 23:06 trickstival

a plugin would be part of the package, but not sure yet of the features to add yet

posva avatar Jun 18 '19 23:06 posva

I played around with vuexfire and nuxt when testing if vuexfire works with nuxt-fire (see this issue), and I got it to work just fine.

Without using fetch() but using the created() hook.

I created this example repository for vuexfire with nuxt-fire, I hope it helps someone: https://github.com/lupas/nuxt-fire-vuexfire-example

I'm using nuxt-fire here but this is basically the same as initiating firebase yourself, so it should work the same way for projects who are not using nuxt-fire.

The examples uses universal mode (resp. nuxt generate) and not SPA mode.

Update: As @posva noted below, this example does not fetch the data on server-side and therefore is not truly a working SSR example.

lupas avatar Jun 21 '19 05:06 lupas

but using the created hook instead of fetch doesn't wait for it before rendering on SSR, waiting for the action is the whole point. @krisztianodor let me update the comment, I'm using a method but they are not accessible in fetch

posva avatar Jun 22 '19 19:06 posva

How to make it reactive while ssr? After the first load i have content, but it's not reactive, only after i bind again on client side. But when i bind, it automatically unbinds the previously bound property, which means that the property is reseted (null / [] / ...) and it causes a flash on the site before the client subscribe ending.

https://vuefire.vuejs.org/api/vuefire.html#bind

krisztianodor avatar Jul 11 '19 22:07 krisztianodor

@krisztianodor that is something being tracked at https://github.com/vuejs/vuefire/issues/83

posva avatar Jul 12 '19 09:07 posva

If anyone is still stumbling on this, I made vuexfire work in a Nuxt SSR app with using async/await and the new wait: true option by binding once in fetch (for server-side) and once in mounted (for client-side):

See comment: https://github.com/lupas/nuxt-fire-vuexfire-example/issues/1#issuecomment-560206034 Entire example: lupas/nuxt-fire-vuexfire-example

Example is with nuxt-fire, but that shouldn't make a difference.

Only thing that I would like to improve now is find a way to only need to call the binding action once and have it automatically be bound on server and client side, anyone an idea?

lupas avatar Dec 02 '19 03:12 lupas

@lupas Would we want to bind on the server? Maybe the server is just a simple query, get the data we need to render html, then we bind on the client?

fergusmeiklejohn avatar Jul 03 '20 08:07 fergusmeiklejohn

@fergusmeiklejohn Binding on a server does per se not make sense, you are right. Doing a single call on the server and then only binding on the client is for sure the safest way to do it.

But if we want to keep our code simple and make use of vuefire (-> not having to write all the mutations and all that ourselves), this could be an option to save us some lines of code.

My thinking here is that on the server the process could be like so:

  1. Do the binding
  2. Initial data gets loaded
  3. Unbind again
  4. Data gets rendered to client

-> probably a bit less performant

Unbinding (e.g. in the destroyed() hook) might be important though to avoid memory leaks. Not sure, would need to be tested properly before used in production for sure.

lupas avatar Jul 03 '20 09:07 lupas

Hi guys, vuefire is failing on page refresh when using the new fetch() api and NuxtJS:

Screenshot of console error: https://i.stack.imgur.com/lISRW.png

Here is my stackoverflow question with details: https://stackoverflow.com/questions/63827895/vuefire-and-async-fetch-in-nuxtjs-fails-on-page-refresh

Anyone know how to fix?

dosstx avatar Sep 10 '20 10:09 dosstx

Anyone have thoughts on the above question? Updated documentation for Nuxt would be greatly appreciated!

dosstx avatar Sep 24 '20 09:09 dosstx

Hi all, nuxt 2.12 introduced a new fetch() hook that triggers on the server-side and on the client-side and has access to component/page data. Specs

IMHO fetch() is the best place to bind vuexfire . Would you agree? However I encounter this issue:

vue.runtime.esm.js?2b0e:619 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render

Here how I use trainings (computed property) to print list of trainings inside <template>

   23       <v-list-item
   24         v-for="(t, idx) in trainings"
   25         v-else
   26         :key="idx"
   27         :to="'dashboard/' + t.id + '/' + todayStr"
   28         class="mb-3"
   29       >

Here how I bind in my page inside <script>

  65 export default Vue.extend({
   66   name: 'YourComponent',
   67   layout: 'DashboardLayout',
   68   data() {
   69     return {
   73       date: moment(),
   74     }
   75   },
   76   async fetch() {
-- 77     // Fetch has access to this. I need that to pass this.weekday to the bind action
   78     await administraStore.initTrainingByWeekday(this.weekday)
   79   },
   80   computed: {
~  81     trainings(): Training[] {
   82       return administraStore.trainingsByWeekday
   83     },

Here how initTrainingByWeekday(this.weekday) looks like in store.

  178   @Action({ rawError: true })
  179   initTrainingByWeekday(weekday: string) {
  180     const action = firestoreAction(({ bindFirestoreRef }) => {  
  181       return Promise.all([
  182         bindFirestoreRef(    
  183           'trainingsByWeekday',
--184           firebase
  185             .firestore()
  186             .collection('trainings')
  187             .where('weekday', '==', weekday),
  188           { wait: true }
  189         ),
  190       ])
  191     }) as Function
  192     return action(this.context)                                                                                                
  193   }                                                                                                                            

Does anyone know why I get the hydration mismatch when loading the page? Help would be appreciated.

kraeki avatar Feb 15 '22 11:02 kraeki

This is currently being tracked at https://github.com/vuejs/vuefire/issues/1241

For those adventurous enough to try the current nuxt module (Nuxt 3 only although it should work with Bridge too):

  • WIP docs: https://vuefire.vuejs.org/nuxt/getting-started.html#nuxt-js
  • Working playground:
    • https://github.com/vuejs/vuefire/blob/main/packages/nuxt/playground/nuxt.config.ts#L38-L53
    • https://github.com/posva/nuxt-vuefire-example

Some notes: AppCheck is still a work in progress for SSR. I recommend only prerendering routes and not doing SSR yet when the app is deployed. Refer to Firebase docs for information about AppCheck. The docs will also be updated I added this to the roadmap

posva avatar Dec 21 '22 14:12 posva

An interesting repository I just ran across in terms of appcheck: https://github.com/lahirumaramba/edge_token_verifier

The person is trying to get auth verification done in edge runtimes.

Maybe this is helpful to further bring appcheck support to nuxt in more environments?

chrisspiegl avatar Mar 23 '23 16:03 chrisspiegl

Thanks, that's interesting! It seems that the firebase sdk is not ready yet to run on the edge though. AppCheck and SSR are working better now, still need to update the docs and create some extra playgrounds

posva avatar Jul 18 '23 05:07 posva