client side routing works except parameters

This commit is contained in:
Ulf Gebhardt 2023-11-23 16:27:41 +01:00
parent aac1b93cc8
commit fedeacad19
Signed by: ulfgebhardt
GPG Key ID: DA6B843E748679C9
8 changed files with 103 additions and 59 deletions

View File

@ -1,17 +1,36 @@
import { createApp } from './app'
import type { PageContextClient } from '#types/PageContext'
import type { PageContext, VikePageContext } from '#types/PageContext'
// This render() hook only supports SSR, see https://vike.dev/render-modes for how to modify render() to support SPA
async function render(pageContext: PageContextClient) {
const { Page, pageProps } = pageContext
if (!Page) throw new Error('Client-side render() hook expects pageContext.Page to be defined')
const app = createApp(Page, pageProps, pageContext)
app.mount('#app')
let app: ReturnType<typeof createApp>
async function render(pageContext: VikePageContext & PageContext) {
if (!app) {
app = createApp(pageContext)
app.mount('#app')
} else {
// console.log(pageContext)
app.changePage(pageContext)
}
}
/* To enable Client-side Routing:
export const clientRouting = true
// !! WARNING !! Before doing so, read https://vike.dev/clientRouting */
function onHydrationEnd() {
// eslint-disable-next-line no-console
console.log('Hydration finished; page is now interactive.')
}
function onPageTransitionStart() {
// eslint-disable-next-line no-console
console.log('Page transition start')
// document.querySelector('.content')!.classList.add('page-transition')
}
function onPageTransitionEnd() {
// eslint-disable-next-line no-console
console.log('Page transition end')
// document.querySelector('.content')!.classList.remove('page-transition')
}
export const clientRouting = true
export const prefetchStaticAssets = 'viewport'
export { render }
export { onHydrationEnd }
export { onPageTransitionStart }
export { onPageTransitionEnd }

View File

@ -6,20 +6,14 @@ import { META } from '#src/env'
import { createApp } from './app'
import type { PageContextServer } from '#types/PageContext'
import type { PageContextServer, PageContext } from '#types/PageContext'
import type { App } from 'vue'
// See https://vike.dev/data-fetching
export const passToClient = ['pageProps', 'urlPathname', 'routeParams']
export const passToClient = ['pageProps', /* 'urlPathname', */ 'routeParams']
async function render(pageContext: PageContextServer) {
const { Page, pageProps } = pageContext
// This render() hook only supports SSR, see https://vike.dev/render-modes for how to modify render() to support SPA
if (!Page) {
throw new Error('My render() hook expects pageContext.Page to be defined')
}
const app = createApp(Page, pageProps, pageContext, false)
async function render(pageContext: PageContextServer & PageContext) {
const app = createApp(pageContext, false)
const appHtml = await renderToString(app)

View File

@ -1,32 +1,36 @@
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import { createSSRApp, defineComponent, h } from 'vue'
import { createSSRApp, defineComponent, h, markRaw, reactive } from 'vue'
import PageShell from '#components/PageShell.vue'
import { setPageContext } from '#context/usePageContext'
import i18n from '#plugins/i18n'
import pinia from '#plugins/pinia'
import CreateVuetify from '#plugins/vuetify'
import { Page } from '#types/Page'
import { PageProps } from '#types/PageProps'
import type { PageContext } from '#types/PageContext'
import type { Component } from '#types/Component'
import type { PageContext, VikePageContext } from '#types/PageContext'
const vuetify = CreateVuetify(i18n)
function createApp(
Page: Page,
pageProps: PageProps | undefined,
pageContext: PageContext,
isClient = true,
) {
const PageWithLayout = defineComponent({
function createApp(pageContext: VikePageContext & PageContext, isClient = true) {
let rootComponent: Component
const PageWithWrapper = defineComponent({
data: () => ({
Page: markRaw(pageContext.Page),
pageProps: markRaw(pageContext.pageProps || {}),
isClient,
}),
created() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
rootComponent = this
},
render() {
return h(
PageShell,
{},
{
default() {
return h(Page, pageProps || {})
default: () => {
return h(this.Page, this.pageProps)
},
},
)
@ -37,15 +41,35 @@ function createApp(
pinia.use(piniaPluginPersistedstate)
}
const app = createSSRApp(PageWithLayout)
const app = createSSRApp(PageWithWrapper)
app.use(pinia)
app.use(i18n)
app.use(vuetify)
objectAssign(app, {
changePage: (pageContext: VikePageContext & PageContext) => {
Object.assign(pageContextReactive, reactive(pageContext))
rootComponent.Page = markRaw(pageContext.Page)
rootComponent.pageProps = markRaw(pageContext.pageProps || {})
},
})
// When doing Client Routing, we mutate pageContext (see usage of `app.changePage()` in `_default.page.client.js`).
// We therefore use a reactive pageContext.
const pageContextReactive = reactive(pageContext)
// Make pageContext available from any Vue component
setPageContext(app, pageContext)
setPageContext(app, pageContextReactive)
return app
}
// Same as `Object.assign()` but with type inference
function objectAssign<Obj extends object, ObjAddendum>(
obj: Obj,
objAddendum: ObjAddendum,
): asserts obj is Obj & ObjAddendum {
Object.assign(obj, objAddendum)
}
export { createApp }

View File

@ -3,11 +3,11 @@
import { inject } from 'vue'
import { PageContext } from '#types/PageContext'
import { PageContext, VikePageContext } from '#types/PageContext'
import type { App, InjectionKey } from 'vue'
const key: InjectionKey<PageContext> = Symbol(undefined)
const key: InjectionKey<VikePageContext & PageContext> = Symbol(undefined)
function usePageContext() {
const pageContext = inject(key)
@ -15,7 +15,7 @@ function usePageContext() {
return pageContext
}
function setPageContext(app: App, pageContext: PageContext) {
function setPageContext(app: App, pageContext: VikePageContext & PageContext) {
app.provide(key, pageContext)
}

View File

@ -1,5 +1,5 @@
<template>
<v-btn :variant="isRoutSelected($attrs.href as string) ? 'tonal' : 'flat'">
<v-btn :variant="isRouteSelected($attrs.href as string) ? 'tonal' : 'flat'">
<slot />
</v-btn>
</template>
@ -8,7 +8,7 @@ import { usePageContext } from '#context/usePageContext'
const pageContext = usePageContext()
const isRoutSelected = (href: string) => {
const isRouteSelected = (href: string) => {
if (href === '/app') {
return pageContext.urlPathname.indexOf(href) === 0
}

View File

@ -37,7 +37,12 @@ import { useCounterStore } from '#stores/counter'
const counter = useCounterStore()
/*
const {
routeParams: { id: page },
} = usePageContext()
*/
const { routeParams } = usePageContext()
const page = routeParams?.id
// console.log(page)
</script>

2
types/Component.ts Normal file
View File

@ -0,0 +1,2 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Component = any

View File

@ -3,31 +3,31 @@ import { PageProps } from '#types/PageProps'
export type {
PageContextServer,
/*
// When using Client Routing https://vike.dev/clientRouting
PageContextClient,
PageContext,
/ */
// When using Client Routing https://vike.dev/clientRouting
PageContextClient,
PageContext as VikePageContext,
PageContextBuiltInClientWithClientRouting as PageContextBuiltInClient,
// When using Server Routing
/*
PageContextClientWithServerRouting as PageContextClient,
PageContextWithServerRouting as PageContext,
*/
//* /
} from 'vike/types'
// https://vike.dev/pageContext#typescript
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Vike {
interface PageContext {
Page: Page
pageProps?: PageProps
urlPathname: string
exports: {
documentProps?: {
title?: string
description?: string
}
}
export type PageContext = {
Page: Page
pageProps?: PageProps
urlPathname: string
exports: {
documentProps?: {
title?: string
description?: string
}
}
documentProps?: {
title: string
description?: string
}
}