Alexander Barker
Alexander Barker

Reputation: 321

Rendering Observables Server Side using Nuxt SSR and Vue-rx

My goal is to use only observables to render initial content on the server and continue subscriptions on the client. As an observable may not complete over time, ideally the server should wait until all observables are complete before rendering the component.

In a server environment it would be safe to simply take the first value emitted using:

takeWhile(() => process.client)

However I have tried various scenarios in the example below that don't seem to work as I expected.

<template>
  <div class="box m-6">
    <p class="subtitle">Value A: {{ valueA$ }}</p>
    <p class="subtitle">Value B: {{ valueB$ }}</p>
  </div>
</template>

<script>
import { of, from } from 'rxjs';

export default {
  subscriptions() {
    const valueA$ = of('observables that complete immediately work on the server')
    const valueB$ = from(new Promise(resolve => setTimeout(() => resolve('not rendered'), 1000)))

    return {
      valueA$,
      valueB$,
    }
  },
}
</script>

valueA$ completes immediately and Nuxt will render this using SSR. valueB$ completes after 1s however Nuxt will not render this using SSR.

It's seems Nuxt is simply unsubscribing to the Observable before it gets the chance to complete. If I try this with fromFetch() then it will attempt to abort the request.

Taking a look at the code and example below I tried to solve this with fetch() and asyncData() with varying success.

In the case of valueC$ fetch is used and it sets a data variable called this.fetchValue that is used to create an Observable that completes immediately when on the server-side:

const valueC$ = process.server ? of(this.fetchValue || 'not ready') : interval(1000)
// result: valueC$ === 'not ready' as `fetch` is executed after component is created.

The other attempt using valueD$ was using asyncData()... this time it worked as asyncData() is executed before create in the nuxt lifecycle.

 const valueD$ = process.server ? of(this.asyncDataValue || 'not ready') : interval(1000)
// result: valueC$ === 'https://api.github.com/orgs/nuxt'

This would work ok for pages using asyncData() but ideally I need to use fetch().

The hack is not nice and I would like to find a better, more elegant way of doing this. Any ideas?

Is there a way to tell nuxt to wait until a certain event is fired or Observable completes?

Upvotes: 1

Views: 707

Answers (0)

Related Questions