Skip to content
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

How to use Nuxt with VueFire and SSR #203

Closed
ReeVicente opened this issue Aug 18, 2018 · 25 comments
Closed

How to use Nuxt with VueFire and SSR #203

ReeVicente opened this issue Aug 18, 2018 · 25 comments

Comments

@ReeVicente
Copy link

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

@posva
Copy link
Member

posva commented Nov 19, 2018

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 posva added the docs label Nov 19, 2018
@dac3971
Copy link

dac3971 commented Nov 22, 2018

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

@posva
Copy link
Member

posva commented Nov 22, 2018

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

@max8hine
Copy link

max8hine commented Jan 21, 2019

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

@posva
Copy link
Member

posva commented Jan 21, 2019

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.

@agcty
Copy link

agcty commented May 11, 2019

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

@posva
Copy link
Member

posva commented May 11, 2019

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.

@chasebank
Copy link

@posva I understand the vuexfire repo has now been archived, but is there any chance you could take another look at posva/vuexfire#124 (comment) 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!

@posva
Copy link
Member

posva commented Jun 8, 2019

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>

@krisztianodor
Copy link

@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.

@trickstival
Copy link
Collaborator

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

@posva
Copy link
Member

posva commented Jun 18, 2019

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

@lupas
Copy link
Contributor

lupas commented Jun 21, 2019

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.

@posva
Copy link
Member

posva commented Jun 22, 2019

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

@krisztianodor
Copy link

krisztianodor commented Jul 11, 2019

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

@posva
Copy link
Member

posva commented Jul 12, 2019

@krisztianodor that is something being tracked at #83

@lupas
Copy link
Contributor

lupas commented Dec 2, 2019

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: lupas/nuxt-fire-vuexfire-example#1 (comment)
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?

@fergusmeiklejohn
Copy link

@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?

@lupas
Copy link
Contributor

lupas commented Jul 3, 2020

@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.

@dosstx
Copy link

dosstx commented Sep 10, 2020

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
Copy link

dosstx commented Sep 24, 2020

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

@kraeki
Copy link

kraeki commented Feb 15, 2022

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.

@posva
Copy link
Member

posva commented Dec 21, 2022

This is currently being tracked at #1241

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

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 posva closed this as completed Dec 21, 2022
@chrisspiegl
Copy link

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?

Copy link
Member

posva commented Jul 18, 2023

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

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

No branches or pull requests