diff --git a/examples/full/pages/star-wars/index/+Page.vue b/examples/full/pages/star-wars/index/+Page.vue
index 109d2368..0a8730fd 100644
--- a/examples/full/pages/star-wars/index/+Page.vue
+++ b/examples/full/pages/star-wars/index/+Page.vue
@@ -12,5 +12,5 @@
diff --git a/examples/full/pages/star-wars/index/+data.ts b/examples/full/pages/star-wars/index/+data.ts
index 7aa9cb4d..07c030cc 100644
--- a/examples/full/pages/star-wars/index/+data.ts
+++ b/examples/full/pages/star-wars/index/+data.ts
@@ -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[] {
diff --git a/examples/full/pages/star-wars/index/+title.ts b/examples/full/pages/star-wars/index/+title.ts
index 6357ab89..299afc25 100644
--- a/examples/full/pages/star-wars/index/+title.ts
+++ b/examples/full/pages/star-wars/index/+title.ts
@@ -4,6 +4,6 @@ import type { Data } from './+data'
import type { PageContext } from 'vike/types'
function title(pageContext: PageContext) {
- const movies = pageContext.data
+ const { movies } = pageContext.data
return `${movies.length} Star Wars Movies`
}
diff --git a/packages/vike-vue/src/hooks/useData.ts b/packages/vike-vue/src/hooks/useData.ts
index 2368e12a..0c385f7e 100644
--- a/packages/vike-vue/src/hooks/useData.ts
+++ b/packages/vike-vue/src/hooks/useData.ts
@@ -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 {
- const data = inject(key)
+function useData(): ShallowReactive {
+ const data = inject>(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): void {
app.provide(key, data)
}
diff --git a/packages/vike-vue/src/hooks/usePageContext.ts b/packages/vike-vue/src/hooks/usePageContext.ts
index 9ce66602..8b8348b7 100644
--- a/packages/vike-vue/src/hooks/usePageContext.ts
+++ b/packages/vike-vue/src/hooks/usePageContext.ts
@@ -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 {
+ const pageContext = inject>(key)
+ if (!pageContext) throw new Error('setPageContext() not called')
+ return pageContext
}
-function setPageContext(app: App, pageContext: PageContext) {
+function setPageContext(app: App, pageContext: ShallowReactive) {
app.provide(key, pageContext)
}
diff --git a/packages/vike-vue/src/renderer/createVueApp.ts b/packages/vike-vue/src/renderer/createVueApp.ts
index 59a33ed0..f0841f12 100644
--- a/packages/vike-vue/src/renderer/createVueApp.ts
+++ b/packages/vike-vue/src/renderer/createVueApp.ts
@@ -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
@@ -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()
@@ -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
@@ -73,5 +73,11 @@ async function createVueApp(pageContext: PageContext, ssr: boolean, rootComponen
}
function assertDataIsObject(data: unknown): asserts data is Record {
- 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)
}
diff --git a/packages/vike-vue/src/utils/isObject.ts b/packages/vike-vue/src/utils/isObject.ts
deleted file mode 100644
index b5fd3133..00000000
--- a/packages/vike-vue/src/utils/isObject.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export function isObject(value: unknown): value is Record {
- return typeof value === 'object' && value !== null
-}
diff --git a/packages/vike-vue/src/utils/isPlainObject.ts b/packages/vike-vue/src/utils/isPlainObject.ts
new file mode 100644
index 00000000..afe0dfe7
--- /dev/null
+++ b/packages/vike-vue/src/utils/isPlainObject.ts
@@ -0,0 +1,19 @@
+export function isPlainObject(value: unknown): value is Record {
+ // 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'
+ )
+}