Skip to content

Built-in SSR support #10

Open
Open

Description

@MartinMalinda

There's several approaches how to handle SSR with Tasks but none are optimal: https://vue-concurrency.netlify.app/ssr-support/

The approach of saving data to VueX / Pinia or other client side store has proven to work well but probably shouldn't be done just to make SSR with hydration work.
(https://vue-concurrency.netlify.app/examples/store/)

There could be a way to make tasks work with SSR out of the box

  1. right before sending HTML response, serialize task state to JSON and place it on SSR context. All that's needed to serialize is probably _instances as all other state derives from that.
  2. When task is run on the client side, it should pick up the serialized _instances from the ssr context.

Activity

  1. MartinMalinda commented on Jul 3, 2020

    @MartinMalinda
    OwnerAuthor

    Experimental support here:
    https://vue-concurrency.netlify.app/ssr-support/#with-vue-concurrency-ssr-utils

    It's been tested briefly, but I expect to revisit this in a month or two when I'll be dealing with this at work.

  2. kpdemetriou commented on Jan 25, 2021

    @kpdemetriou

    I'm interested in this feature. @MartinMalinda how can I help you build this out?

    Edit:

    import { useTask } from 'vue-concurrency';
    import { getCurrentInstance, onServerPrefetch, onBeforeMount } from '@nuxtjs/composition-api';
    export { useTask } from 'vue-concurrency';
    import wrap from 'REDACTED';
    
    const nuxtState = process.client && window['__NUXT__'];
    
    export function useServerTask (generator) {
      const vm = getCurrentInstance();
      const task = useTask(generator);
    
      onServerPrefetch(async () => {
        await wrap(task.perform); // Muffle errors
    
        if (!vm.$ssrContext.nuxt.task)
          vm.$ssrContext.nuxt.task = [];
    
        vm._taskKey = vm.$ssrContext.nuxt.task.length;
    
        if (!vm.$vnode.data) vm.$vnode.data = {}
        const attrs = (vm.$vnode.data.attrs = vm.$vnode.data.attrs || {})
        attrs['data-task-key'] = vm._taskKey;
    
        vm.$ssrContext.nuxt.task.push(task._instances);
      });
    
      onBeforeMount(async () => !vm._hydrated && await task.perform());
    
      // Hydrate component
      if (process.client) {
        vm._hydrated = true
        vm._taskKey = vm.$vnode.elm.dataset.taskKey;
        task._instances = nuxtState.task[vm._taskKey];
        console.log(task.isError)
      }
    
      return task;
    }
    
  3. MartinMalinda commented on Jan 25, 2021

    @MartinMalinda
    OwnerAuthor

    @kpdemetriou

    thanks for reaching out about this

    There's some WIP on this: https://github.com/MartinMalinda/vue-concurrency/blob/master/src/utils/ssr-utils.ts

    Maybe it's not the latest WIP.. I think I have some tweaked (better) version that I tested directly in a Nuxt app... I'll try to recover it (tomorrow hopefully 🙏 ). There was some trick with reactive that made sure that even some later changes to the task state were propagated, I don't remember exactly.

    I have no use for this feature currently. I have changed my SSR server -> client strategy. I fully rely on Pinia (pinia is used inside the task). But even with Pinia I had to do some hack to make it work:

    export function usePiniaPrefetch(cb: () => Promise<any>) {
      const root = useRoot() as any;
      onServerPrefetch(async () => {
        await cb();
        const ssrContext = root.context.ssrContext;
        ssrContext.nuxt.pinia = getRootState(root.context.req);
      });
    }

    I won't have much time to implement this any time soon - but if you play with these things I can definitely do code reviews in a PR and help out a bit 🙏

  4. MartinMalinda commented on Jan 25, 2021

    @MartinMalinda
    OwnerAuthor

    The latest WIP solution worked for me actually. But I remember it broke with Nuxt upgrade. It was quite fragile in a way that it somehow used some Nuxt internal things. Nuxt itself isn't actually doing great job with all the nuxtState etc IMO, it changes often and it the structure is different in different places (nuxt plugin, context etc)

    vuejs/pinia#332
    nuxt/nuxt#8620

  5. kpdemetriou commented on Jan 25, 2021

    @kpdemetriou

    Thanks for the quick turnaround @MartinMalinda. I've modified your implementation in ssr-utils.ts (which indeed doesn't work in Nuxt latest for me) and I believe it should be sustainable now. Would you mind digging up that latest WIP so I can merge any useful additions before I create a PR?

  6. MartinMalinda commented on Jan 27, 2021

    @MartinMalinda
    OwnerAuthor

    @kpdemetriou I tried to look it up but couldn't find it, welp. It's in some old branch that I can't identify right now 😬 but I rechecked the implementation and what was important was the usage of computed for the saving of task instances and that's present in the current master also... so maybe It's fine.

    PR for the fix for latest Nuxt is welcome 🙏

  7. kpdemetriou commented on Jan 27, 2021

    @kpdemetriou

    I thought that might be what you meant; relevant PR in #34.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions