diff --git a/packages/nuxt/playground/pages/null-object-store.vue b/packages/nuxt/playground/pages/null-object-store.vue new file mode 100644 index 0000000000..576c03db06 --- /dev/null +++ b/packages/nuxt/playground/pages/null-object-store.vue @@ -0,0 +1,8 @@ + + + diff --git "a/packages/nuxt/playground/stores/with-null-\316\277bject.ts" "b/packages/nuxt/playground/stores/with-null-\316\277bject.ts" new file mode 100644 index 0000000000..42db0adb85 --- /dev/null +++ "b/packages/nuxt/playground/stores/with-null-\316\277bject.ts" @@ -0,0 +1,12 @@ +export const useWithNullObjectStore = defineStore('with-null-object', () => { + return { + text: ref(Object.create(null)), + foo: ref('bar'), + } +}) + +if (import.meta.hot) { + import.meta.hot.accept( + acceptHMRUpdate(useWithNullObjectStore, import.meta.hot) + ) +} diff --git a/packages/nuxt/test/nuxt.spec.ts b/packages/nuxt/test/nuxt.spec.ts index 8bcbfccc05..76a9041e81 100644 --- a/packages/nuxt/test/nuxt.spec.ts +++ b/packages/nuxt/test/nuxt.spec.ts @@ -1,6 +1,7 @@ import { fileURLToPath } from 'node:url' import { describe, it, expect } from 'vitest' import { setup, $fetch } from '@nuxt/test-utils/e2e' +import exp from 'node:constants' describe('works with nuxt', async () => { await setup({ @@ -28,6 +29,14 @@ describe('works with nuxt', async () => { expect(html).toContain('Count: 101') }) + it('works with null objects', async () => { + expect(async () => { + const html = await $fetch('/null-object-store') + expect(html).toContain('null object') + expect(html).toContain('bar') + }).not.toThrow() + }) + it('drops state that is marked with skipHydrate', async () => { const html = await $fetch('/skip-hydrate') expect(html).not.toContain('I should not be serialized or hydrated') diff --git a/packages/pinia/__tests__/ssr.spec.ts b/packages/pinia/__tests__/ssr.spec.ts index 5f5a364d81..10fc66793d 100644 --- a/packages/pinia/__tests__/ssr.spec.ts +++ b/packages/pinia/__tests__/ssr.spec.ts @@ -152,6 +152,13 @@ describe('SSR', () => { expect(store.$state).toEqual({ start: 'start' }) }) + it('accepts a store with no null state', () => { + const pinia = createPinia() + pinia.state.value.a = Object.create(null) + const store = defineStore('a', {})(pinia) + expect(store.$state).toEqual({}) + }) + describe('Setup Store', () => { const useStore = defineStore('main', () => { const count = ref(0) diff --git a/packages/pinia/src/store.ts b/packages/pinia/src/store.ts index a09196a4e5..c5410e5977 100644 --- a/packages/pinia/src/store.ts +++ b/packages/pinia/src/store.ts @@ -136,7 +136,10 @@ export function skipHydrate(obj: T): T { * @returns true if `obj` should be hydrated */ export function shouldHydrate(obj: any) { - return !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol) + return ( + !isPlainObject(obj) || + !Object.prototype.hasOwnProperty.call(obj, skipHydrateSymbol) + ) } const { assign } = Object