Open isokosan opened 3 years ago
It would be better to see how you define your pinia store but I guess can do something like that.
import { defineStore } from 'pinia'
const useAuthStore= defineStore('authStore', {
state: () => {
return {
user: typeof window !== 'undefined' ? localStorage.user : 'guest',
}
},
})
Or you can use https://vueuse.org/core/useStorage/
import { defineStore } from 'pinia'
import { useStorage } from '@vueuse/core'
const useAuthStore= defineStore('authStore', {
state: () => {
return {
// 'user' = localStorage.user
// 'guest' = default value
user: useStorage('user', 'guest'),
}
},
})
Thanks, that is the way I currently set it up, by checking for the window variable. I'll check out useStorage from @vueuse/core
as well, thank you!
My question regarding setting up global router hooks that use pinia stores remains though. I want to define some router.beforeEach
and router.afterEach
hooks that have access to pinia stores, but when I use useAuthStore
for example to look for a user in the beforeEach
hook, I get the following error upon build:
I think it would be great if we can show a router middleware implementation using stores, and ideally merge that into the vitesse templates. If you can direct me in the right way I'd be happy to write some examples and submit a pull request there.
Cheers
[Vue Router warn]: uncaught error during route navigation:
TypeError: Cannot read property '_s' of undefined
at useStore (/home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/pinia@2.0.0-rc.8_typescript@4.4.2+vue@3.2.11/node_modules/pinia/dist/pinia.cjs.js:1544:20)
at /home/deniz/dev/metalink/metalink-frontend/.vite-ssg-temp/main.js:267:18
at /home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:1920:35
at new Promise (<anonymous>)
at /home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:1894:18
at /home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:3368:65
TypeError: Cannot read property '_s' of undefined
at useStore (/home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/pinia@2.0.0-rc.8_typescript@4.4.2+vue@3.2.11/node_modules/pinia/dist/pinia.cjs.js:1544:20)
at /home/deniz/dev/metalink/metalink-frontend/.vite-ssg-temp/main.js:267:18
at /home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:1920:35
at new Promise (<anonymous>)
at /home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:1894:18
at /home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:3368:65
ELIFECYCLE Command failed with exit code 1.
The pinia module is so:
import { createPinia } from 'pinia'
import type { RouteParams } from 'vue-router'
import { ModuleInstall } from '~/types'
import { useAuthStore } from '~/stores/auth'
import { useLayoutStore } from '~/stores/layout'
// Setup Pinia
// https://pinia.esm.dev/
export const install: ModuleInstall = async ({ isClient, initialState, app, router }) => {
const pinia = createPinia()
app.use(pinia)
// Refer to
// https://github.com/antfu/vite-ssg/blob/main/README.md#state-serialization
// for other serialization strategies.
if (isClient) {
pinia.state.value = (initialState.pinia) || {}
} else {
initialState.pinia = pinia.state.value
}
router.beforeEach((to, from): boolean | string | RouteParams => {
const auth = useAuthStore()
if (to.meta.redirect) {
return to.meta.redirect
}
if (to.meta.middleware) {
if (to.meta.middleware === 'auth' && !auth.user) {
return { name: 'login' }
}
if (to.meta.middleware === 'guest' && auth.user) {
return { name: 'index' }
}
}
return true
})
router.afterEach((to, from): void => {
const layout = useLayoutStore()
layout.navigationDrawer = false
layout.sidebar = false
})
}
There is nothing wrong with your approach to access pinia store in router hook. Only thing you have to avoid calling browser APIs in your useAuthStore
store for build time.
It would be nice to see what is going on that useAuthStore
definition and at /home/deniz/dev/metalink/metalink-frontend/.vite-ssg-temp/main.js:267:18
based on this error message.
The line the error is thrown in .vite-ssh-temp/main.js
is the line where we call const auth = useAuthStore();
I removed everything to bare bones as to rule out any other errors so the auth store and the layout store I attempt to import are currently in this state:
~/stores/auth.ts
import type { Ref } from 'vue'
import { acceptHMRUpdate, defineStore } from 'pinia'
export const useAuthStore = defineStore('user', () => {
const user: Ref<User | null> = ref(null)
return {
user
}
})
if (import.meta.hot) { import.meta.hot.accept(acceptHMRUpdate(useAuthStore, import.meta.hot)) }
~/stores/layout.ts
import type { Ref } from 'vue'
import { acceptHMRUpdate, defineStore } from 'pinia'
export const useLayoutStore = defineStore('layout', () => {
const navigationDrawer: Ref<boolean> = ref(false)
const sidebar: Ref<boolean> = ref(false)
return {
navigationDrawer,
sidebar
}
})
if (import.meta.hot) { import.meta.hot.accept(acceptHMRUpdate(useLayoutStore, import.meta.hot)) }
Others are apparently also having this issue when attempting the build with vite-ssg, you can check this issue over at pinia's issues.
Thanks for looking into it!
Does it throw error when your stores like that? You shouldn't have any issue with this stores. I guess you removed the actual code that causes an issue.
No, it does throw the same error. You can try it yourself, all you have to do is call useSomeStore
in any module.
Yeah, I got same error.
I fixed this issue by adding await router.isReady()
right before router.beforeEach
call. Can you try it?
Interesting: Just tried it, and still get the same error. Plus from what I understand, the router.isReady
waits for the initial navigations to all complete, which wouldn't make sense to do right before a route middleware, or?
TypeError: Cannot read property '_s' of undefined
at useStore (/home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/pinia@2.0.0-rc.8_typescript@4.4.2+vue@3.2.11/node_modules/pinia/dist/pinia.cjs.js:1544:20)
at /home/deniz/dev/metalink/metalink-frontend/.vite-ssg-temp/main.js:165:20
at triggerAfterEach (/home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:3116:13)
at /home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:3019:13
at async /home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vite-ssg@0.14.7_a05020cb06f51988f10705a8ab55a652/node_modules/vite-ssg/dist/node/cli.js:187:7
at async Promise.all (index 0)
at async build (/home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vite-ssg@0.14.7_a05020cb06f51988f10705a8ab55a652/node_modules/vite-ssg/dist/node/cli.js:184:3)
at async Object.handler (/home/deniz/dev/metalink/metalink-frontend/node_modules/.pnpm/vite-ssg@0.14.7_a05020cb06f51988f10705a8ab55a652/node_modules/vite-ssg/dist/node/cli.js:267:3)
Can you show your main.ts?
@isokosan Please provide a minimal reproduction repo so we can better help.
Probably you are trying to access pinia store before it's getting installed or; registered another router hook on other modules.
Try putting await router.isReady()
on main.ts
like that:
export const createApp = ViteSSG(
App,
{ routes },
async(ctx) => {
await ctx.router.isReady()
// install all modules under `modules/`
Object.values(import.meta.globEager('./modules/*.ts')).map(i => i.install?.(ctx))
},
)
This would fix your issue if you are trying to access pinia store on other modules.
That was it @sibbng, the ngprogress
module from the vitesse starter template was also accessing the router. Thank you so much for your time and support. :) And maybe this is something to document, as it was quite a challenge to debug.
You're welcome.
If that router hooks defined in ngprogress module wrapped in if
statement as here, the issue is not there 👍
Yeah, then maybe the pwa
but that also waits for the router.isReady
. If I find some time tomorrow I'll fork the vitesse template and try to demonstrate the issue. Would be awesome to have you take a look, also at my approach at making middleware nuxt style with the globEager
imports.
Thanks again mate. :)
I'm re-opening this issue guys because router.isReady
waits for the initial navigation to complete, which is useless when trying to build router middleware, also when I await it the routes don't resolve at all.
Could you please demonstrate an example of how one could implement a router hook that uses a pinia store, which does not fail upon build with the error above? I made a fork from the vitesse template here, with a minimal example of adding a router.beforeEach
hook that accesses a pinia store.
Can you upgrade to latest version and try again without router.isReady
. Seems related to https://github.com/antfu/vite-ssg/pull/106
I have the latest version in the fork, and the build is still failing. The comment I made: "when I await router.isReady()
the routes don't resolve at all." seems to be the result of the merge #106, which is ok, but the build still throws the error without router.isReady
.
[Vue Router warn]: uncaught error during route navigation:
TypeError: Cannot read property '_s' of undefined
at useStore (/home/deniz/dev/examples/vitesse/node_modules/.pnpm/pinia@2.0.0-rc.9_typescript@4.4.3+vue@3.2.11/node_modules/pinia/dist/pinia.cjs:1564:20)
at /home/deniz/dev/examples/vitesse/.vite-ssg-temp/main.js:783:18
at /home/deniz/dev/examples/vitesse/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:1920:35
at new Promise (<anonymous>)
at /home/deniz/dev/examples/vitesse/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:1894:18
at /home/deniz/dev/examples/vitesse/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:3368:65
TypeError: Cannot read property '_s' of undefined
at useStore (/home/deniz/dev/examples/vitesse/node_modules/.pnpm/pinia@2.0.0-rc.9_typescript@4.4.3+vue@3.2.11/node_modules/pinia/dist/pinia.cjs:1564:20)
at /home/deniz/dev/examples/vitesse/.vite-ssg-temp/main.js:783:18
at /home/deniz/dev/examples/vitesse/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:1920:35
at new Promise (<anonymous>)
at /home/deniz/dev/examples/vitesse/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:1894:18
at /home/deniz/dev/examples/vitesse/node_modules/.pnpm/vue-router@4.0.11_vue@3.2.11/node_modules/vue-router/dist/vue-router.cjs.js:3368:65
ELIFECYCLE Command failed with exit code 1.
Try awaiting router only on server side with if (!ctx.isClient)
export const createApp = ViteSSG(
App,
{ routes },
async(ctx) => {
if (!ctx.isClient)
await ctx.router.isReady()
// install all modules under `modules/`
Object.values(import.meta.globEager('./modules/*.ts')).map(i => i.install?.(ctx))
},
)
That did the trick!
I noticed yesterday that the vite-ssg build command will not generate pages when the router.isReady
is awaited. So instead, I wrapped all store accessing logic in an isClient
if closure.
I think the issue should stay open for the time being, since pinia in vite-ssg should not really throw an error and still function even when generating the pages.
export const createApp = ViteSSG(
App,
{ routes },
async (ctx) => {
// Breaks generation
// if (!ctx.isClient) {
// await ctx.router.isReady()
// }
// install all modules under `modules/`
Object.values(import.meta.globEager('./modules/*.ts')).map(i => i.install?.(ctx))
if (ctx.isClient) {
// we can only use stores in client mode,
const auth = useAuthStore()
await auth.me()
const layout = useLayoutStore()
ctx.router.afterEach((to, from): void => {
layout.navigationDrawer = false
layout.sidebar = false
})
}
}
)
Hey, same issue here, tried every mentioned solution but noting is working. Could it be because I use a pina store in an other pinia store ?
I also encounter the same issue when I call the useStore() function from a composable (SPA)
Please check this issue here, its either pinia related or vite-ssg - but in any case I couldn't figure out the best way to install global middleware that uses the store, that doesn't throw this error on build.
Any suggestions on how to access the store in a
router.beforeEach
, which is initialized with the app?And in case the store uses localStorage initialization which won't be available during generation, any best practices there?
Would be great if one could direct me to an example repo with such middleware.