Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/full/pages/star-wars/index/+Page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
<script lang="ts" setup>
import type { Data } from './+data'
import { useData } from 'vike-vue/useData'
const movies = useData<Data>()
const { movies } = useData<Data>()
</script>
2 changes: 1 addition & 1 deletion examples/full/pages/star-wars/index/+data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const data = async () => {
// We remove data we don't need because the data is passed to the client; we should
// minimize what is sent over the network.
const movies = minimize(moviesData)
return movies
return { movies }
}

function minimize(movies: MovieDetails[]): Movie[] {
Expand Down
2 changes: 1 addition & 1 deletion examples/full/pages/star-wars/index/+title.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import type { Data } from './+data'
import type { PageContext } from 'vike/types'

function title(pageContext: PageContext<Data>) {
const movies = pageContext.data
const { movies } = pageContext.data
return `${movies.length} Star Wars Movies`
}
10 changes: 5 additions & 5 deletions packages/vike-vue/src/hooks/useData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ export { useData }
export { setData }

import { inject } from 'vue'
import type { App } from 'vue'
import type { App, ShallowReactive } from 'vue'

const key = 'vike-vue:useData'

/** https://vike.dev/useData */
function useData<Data>(): Data {
const data = inject(key)
function useData<Data>(): ShallowReactive<Data> {
const data = inject<ShallowReactive<Data>>(key)
if (!data) throw new Error('setData() not called')
return data as any
return data
}

function setData(app: App, data: unknown): void {
function setData(app: App, data: ShallowReactive<unknown>): void {
app.provide(key, data)
}
12 changes: 7 additions & 5 deletions packages/vike-vue/src/hooks/usePageContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ export { usePageContext }
export { setPageContext }

import { inject } from 'vue'
import type { App } from 'vue'
import type { App, ShallowReactive } from 'vue'
import type { PageContext } from 'vike/types'

const key = 'vike-vue:usePageContext'

function usePageContext() {
const pageContext = inject(key)
return pageContext as PageContext
/** https://vike.dev/usePageContext */
function usePageContext(): ShallowReactive<PageContext> {
const pageContext = inject<ShallowReactive<PageContext>>(key)
if (!pageContext) throw new Error('setPageContext() not called')
return pageContext
}

function setPageContext(app: App, pageContext: PageContext) {
function setPageContext(app: App, pageContext: ShallowReactive<PageContext>) {
app.provide(key, pageContext)
}
22 changes: 14 additions & 8 deletions packages/vike-vue/src/renderer/createVueApp.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export { createVueApp }
export type { ChangePage }

import { type App, createApp, createSSRApp, h, markRaw, nextTick, reactive, ref } from 'vue'
import { type App, createApp, createSSRApp, h, markRaw, nextTick, ref, shallowReactive } from 'vue'
import type { PageContext } from 'vike/types'
import { setPageContext } from '../hooks/usePageContext'
import { objectAssign } from '../utils/objectAssign'
import { callCumulativeHooks } from '../utils/callCumulativeHooks'
import { isObject } from '../utils/isObject'
import { isPlainObject } from '../utils/isPlainObject'
import { setData } from '../hooks/useData'

type ChangePage = (pageContext: PageContext) => Promise<void>
Expand Down Expand Up @@ -41,8 +41,8 @@ async function createVueApp(pageContext: PageContext, ssr: boolean, rootComponen
}
const data = pageContext.data ?? {}
assertDataIsObject(data)
Object.assign(dataReactive, data)
Object.assign(pageContextReactive, pageContext)
objectReplace(dataReactive, data)
objectReplace(pageContextReactive, pageContext)
rootComponentRef.value = markRaw(pageContext.config[rootComponentName])
layoutRef.value = markRaw(pageContext.config.Layout)
await nextTick()
Expand All @@ -52,9 +52,9 @@ async function createVueApp(pageContext: PageContext, ssr: boolean, rootComponen

const data = pageContext.data ?? {}
assertDataIsObject(data)
const dataReactive = reactive(data)
const pageContextReactive = reactive(pageContext)
setPageContext(app, pageContextReactive as typeof pageContext)
const dataReactive = shallowReactive(data)
const pageContextReactive = shallowReactive(pageContext)
setPageContext(app, pageContextReactive)
setData(app, dataReactive)

const { onCreateApp } = pageContext.config
Expand All @@ -73,5 +73,11 @@ async function createVueApp(pageContext: PageContext, ssr: boolean, rootComponen
}

function assertDataIsObject(data: unknown): asserts data is Record<string, unknown> {
if (!isObject(data)) throw new Error('Return value of data() should be an object, undefined, or null')
if (!isPlainObject(data)) throw new Error('Return value of data() should be a plain object, undefined, or null')
}

export function objectReplace(obj: object, objAddendum: object) {
// @ts-ignore
Object.keys(obj).forEach((key) => delete obj[key])
Object.assign(obj, objAddendum)
}
3 changes: 0 additions & 3 deletions packages/vike-vue/src/utils/isObject.ts

This file was deleted.

19 changes: 19 additions & 0 deletions packages/vike-vue/src/utils/isPlainObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export function isPlainObject(value: unknown): value is Record<string, unknown> {
// Is object?
if (typeof value !== 'object' || value === null) {
return false
}

// Support `Object.create(null)`
if (Object.getPrototypeOf(value) === null) {
return true
}

// Is plain object?
return (
/* Doesn't work in Cloudflare Pages workers
value.constructor === Object
*/
value.constructor.name === 'Object'
)
}