nuxt / framework

Old repo of Nuxt 3 framework, now on nuxt/nuxt
https://nuxt.com
10.64k stars 1.05k forks source link

NuxtLink doesn't support hook onServerPrefetch #5133

Closed prstwo closed 2 years ago

prstwo commented 2 years ago

Environment

Operating System: Windows_NT Node Version: v16.13.0 Nuxt Version: 3.0.0-rc.3 Package Manager: npm@8.1.0 Builder: vite User Config: typescript Runtime Modules: - Build Modules: -

Reproduction

export default { setup() { const route = useRoute(); const catInfo = useCategoryInfo(); /this method is available in index.js/ onServerPrefetch(async () => { await catInfo.getCatInfo(route.params.id); }); return { route , catInfo }; } }

Describe the bug

I'm struggling with this problem since I've been using Nuxt. I'm coding an E-commerce website using nuxt3 and vue3 and data is got from an api using Pinia, therefore SEO is so important to me and codes should be shown on Page Source. I found a way to render HTML codes on page source:

  1. executing the function which gets data from api inside onServerPrefetch hook .
  2. Wrapping the html code which gets its data from api in .

Functions inside vue onServerPrefetch will be executed well when the page is refreshed and but the problem appears when switching between routes using NuxtLink. I found that when the routes are switched using nuxtlink, the functions inside onServerPrefetch are not executed. Possible solutions you may give me:

  1. using onMounted: This will eliminate this problem but wouldn't render data during server side rendering, so those data and html codes which are reliable to api. wouldn't be rendered in page source.
  2. using useAsyncData or useFetch: This will eliminate the problem. But I need pinia state manager to fetch data and store them

Additional context

No response

Logs

No response

HomWang commented 2 years ago

import { watch, toRaw } from 'vue' import * as Cookies from 'js-cookie';

export function createPersistStorage(state: any, key = 'default'): T { const STORAGE_KEY = '--Fbit-Saas--'

Object.entries(getItem(key)).forEach(([key, value]) => { state[key] = value })

function setItem(state: any) { const stateRow = getItem() stateRow[key] = state const stateStr = JSON.stringify(stateRow) // localStorage.setItem(STORAGE_KEY, stateStr) // Cookies.set(STORAGE_KEY, stateStr, { expires: 365, secure: false }) }

function getItem(key?: string) { // const stateStr = localStorage.getItem(STORAGE_KEY) || '{}' const stateStr = Cookies.get(STORAGE_KEY) || '{}' const stateRow = JSON.parse(stateStr) || {} return key ? stateRow[key] || {} : stateRow }

watch(state, () => { const stateRow = toRaw(state) setItem(stateRow) })

return readonly(state) }

HomWang commented 2 years ago

import { reactive, readonly } from 'vue' import { createAction } from '../stores/action' import { createPersistStorage } from '../stores/persistStorage' import { createState, IState } from '../stores/state'

// 创建State const state = createState() // 根据state创建Action const action = createAction(state)

export const useStore = () => { const store = { state: process.client ? createPersistStorage(state) : readonly(state), action: readonly(action) } return store }

HomWang commented 2 years ago

This supports cookies