vuejs / pinia

🍍 Intuitive, type safe, light and flexible Store for Vue using the composition api with DevTools support
https://pinia.vuejs.org
MIT License
13.19k stars 1.06k forks source link

Implement nuxtServerInit Action to load data from server-side on the initial load #1080

Open MarceloLuis1997 opened 2 years ago

MarceloLuis1997 commented 2 years ago

What problem is this solving

Implement something like NuxtServerInit Action, so we can load data from the server-side and give it directly to the client-side on the initial load/render.

Proposed solution

Include an index.js file inside /stores with a nuxtServerInit action which will be called from the server-side on the initial load.

Describe alternatives you've considered

The only way I found to do this is using Pinia with Vuex, using the nuxtServerInit from Vuex:

// store/index.js
import { useSessionStore } from '~/stores/session'

export const actions = {
  async nuxtServerInit ({ dispatch }, { req, redirect, $pinia }) {
    if (!req.url.includes('/auth/')) {
      const store = useSessionStore($pinia)

      try {
        await store.me() // load user information from the server-side before rendering on client-side
      } catch (e) {
        redirect('/auth/login') // redirects to login if user is not logged in
      }
    }
  }
}
MarceloLuis1997 commented 2 years ago

947

posva commented 2 years ago

There should be a way to add this for both setup and option stores. Maybe a specific name for an action is enough.

One important thing to note is that given the nature of stores in pinia, you need explicitly say somewhere in your server code which stores must run this action as they need to be instantiated on the server. By default, if no store is ever user, no store is ever instantiated and therefore no server init function can run.

AustinMusiku commented 2 years ago

What problem is this solving

Implement something like NuxtServerInit Action, so we can load data from the server-side and give it directly to the client-side on the initial load/render.

Proposed solution

Include an index.js file inside /stores with a nuxtServerInit action which will be called from the server-side on the initial load.

Describe alternatives you've considered

The only way I found to do this is using Pinia with Vuex, using the nuxtServerInit from Vuex:

// store/index.js
import { useSessionStore } from '~/stores/session'

export const actions = {
  async nuxtServerInit ({ dispatch }, { req, redirect, $pinia }) {
    if (!req.url.includes('/auth/')) {
      const store = useSessionStore($pinia)

      try {
        await store.me() // load user information from the server-side before rendering on client-side
      } catch (e) {
        redirect('/auth/login') // redirects to login if user is not logged in
      }
    }
  }
}

Thanks for this workaround, I would also love to see the feature implemented

matifanger commented 2 years ago

What problem is this solving

Implement something like NuxtServerInit Action, so we can load data from the server-side and give it directly to the client-side on the initial load/render.

Proposed solution

Include an index.js file inside /stores with a nuxtServerInit action which will be called from the server-side on the initial load.

Describe alternatives you've considered

The only way I found to do this is using Pinia with Vuex, using the nuxtServerInit from Vuex:

// store/index.js
import { useSessionStore } from '~/stores/session'

export const actions = {
  async nuxtServerInit ({ dispatch }, { req, redirect, $pinia }) {
    if (!req.url.includes('/auth/')) {
      const store = useSessionStore($pinia)

      try {
        await store.me() // load user information from the server-side before rendering on client-side
      } catch (e) {
        redirect('/auth/login') // redirects to login if user is not logged in
      }
    }
  }
}

Thanks for this workaround, I would also love to see the feature implemented

Did the stores are shared?

nestle49 commented 2 years ago

This solution is workaround for me:

nuxt.config.ts

plugins: [
   { src: '~/plugins/init.server.ts' }, // must be the first server plugin
 ]

plugins/init.server.ts

import { useGlobalStateStore } from '~/store/globalState';

const initServer: () => void = async () => {
    // example code
    const host = req.hostname;
    const globalStateStore = useGlobalStateStore();
    globalStateStore.SET_HOST({ host });
};

export default initServer;
MuhammadM1998 commented 1 year ago

@nestle49 Can this be placed as a nitro plugin in a nuxt project instead?

mrleblanc101 commented 1 year ago

Any update on this ?

yshrsmz commented 11 months ago

It looks like currently, we can't use a store with inject() call inside, from the nuxt plugin.

inject() call simply throws the following error.

[Vue warn]: inject() can only be used inside setup() or functional components.

Tested with Nuxt/Bridge btw.