From eb23ecb33e473226111238344d3930fe92ac1288 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Thu, 26 Sep 2024 13:58:51 +0200 Subject: [PATCH 1/3] feat(nuxt): not serializing skipHydrate properties --- packages/nuxt/playground/app.vue | 20 +----------------- packages/nuxt/playground/nuxt.config.ts | 4 ++++ packages/nuxt/playground/pages/index.vue | 21 +++++++++++++++++++ .../nuxt/playground/pages/skip-hydrate.vue | 8 +++++++ .../playground/stores/with-skip-hydrate.ts | 16 ++++++++++++++ packages/nuxt/src/module.ts | 18 +++++++++------- packages/nuxt/src/runtime/payload-plugin.ts | 19 +++++++++++++++++ packages/nuxt/src/runtime/plugin.vue3.ts | 3 ++- packages/pinia/src/index.ts | 2 +- packages/pinia/src/store.ts | 2 +- 10 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 packages/nuxt/playground/pages/index.vue create mode 100644 packages/nuxt/playground/pages/skip-hydrate.vue create mode 100644 packages/nuxt/playground/stores/with-skip-hydrate.ts create mode 100644 packages/nuxt/src/runtime/payload-plugin.ts diff --git a/packages/nuxt/playground/app.vue b/packages/nuxt/playground/app.vue index 450e65a2d3..8f62b8bf92 100644 --- a/packages/nuxt/playground/app.vue +++ b/packages/nuxt/playground/app.vue @@ -1,21 +1,3 @@ - - diff --git a/packages/nuxt/playground/nuxt.config.ts b/packages/nuxt/playground/nuxt.config.ts index 973b5d95a3..1431c79015 100644 --- a/packages/nuxt/playground/nuxt.config.ts +++ b/packages/nuxt/playground/nuxt.config.ts @@ -3,9 +3,11 @@ import { defineNuxtConfig } from 'nuxt/config' import piniaModule from '../src/module' export default defineNuxtConfig({ + devtools: { enabled: true }, alias: { pinia: fileURLToPath(new URL('../../pinia/src/index.ts', import.meta.url)), }, + modules: [piniaModule], pinia: { @@ -19,4 +21,6 @@ export default defineNuxtConfig({ __TEST__: false, }, }, + + compatibilityDate: '2024-09-26', }) diff --git a/packages/nuxt/playground/pages/index.vue b/packages/nuxt/playground/pages/index.vue new file mode 100644 index 0000000000..450e65a2d3 --- /dev/null +++ b/packages/nuxt/playground/pages/index.vue @@ -0,0 +1,21 @@ + + + diff --git a/packages/nuxt/playground/pages/skip-hydrate.vue b/packages/nuxt/playground/pages/skip-hydrate.vue new file mode 100644 index 0000000000..2ad72bb296 --- /dev/null +++ b/packages/nuxt/playground/pages/skip-hydrate.vue @@ -0,0 +1,8 @@ + + + diff --git a/packages/nuxt/playground/stores/with-skip-hydrate.ts b/packages/nuxt/playground/stores/with-skip-hydrate.ts new file mode 100644 index 0000000000..3cbbc31bc2 --- /dev/null +++ b/packages/nuxt/playground/stores/with-skip-hydrate.ts @@ -0,0 +1,16 @@ +import { skipHydrate } from 'pinia' + +export const useWithSkipHydrateStore = defineStore('with-skip-hydrate', () => { + const skipped = skipHydrate( + ref({ + text: 'I should not be serialized or hydrated', + }) + ) + return { skipped } +}) + +if (import.meta.hot) { + import.meta.hot.accept( + acceptHMRUpdate(useWithSkipHydrateStore, import.meta.hot) + ) +} diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts index b528bad4f6..08148ad940 100644 --- a/packages/nuxt/src/module.ts +++ b/packages/nuxt/src/module.ts @@ -11,6 +11,7 @@ import { addImportsDir, } from '@nuxt/kit' import type { NuxtModule } from '@nuxt/schema' +import { fileURLToPath } from 'node:url' export interface ModuleOptions { /** @@ -44,7 +45,9 @@ const module: NuxtModule = defineNuxtModule({ disableVuex: true, }, setup(options, nuxt) { - const resolver = createResolver(import.meta.url) + // configure transpilation + const { resolve } = createResolver(import.meta.url) + const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url)) // Disable default Vuex store (Nuxt v2.10+ only) if ( @@ -58,7 +61,7 @@ const module: NuxtModule = defineNuxtModule({ } // Transpile runtime - nuxt.options.build.transpile.push(resolver.resolve('./runtime')) + nuxt.options.build.transpile.push(resolve(runtimeDir)) // Make sure we use the mjs build for pinia nuxt.options.alias.pinia = @@ -76,14 +79,15 @@ const module: NuxtModule = defineNuxtModule({ // https://github.com/nuxt/framework/issues/9130 nuxt.hook('modules:done', () => { if (isNuxt2()) { - addPlugin(resolver.resolve('./runtime/plugin.vue2')) + addPlugin(resolve(runtimeDir, 'plugin.vue2')) } else { - addPlugin(resolver.resolve('./runtime/plugin.vue3')) + addPlugin(resolve(runtimeDir, 'plugin.vue3')) + addPlugin(resolve(runtimeDir, 'payload-plugin')) } }) // Add auto imports - const composables = resolver.resolve('./runtime/composables') + const composables = resolve(runtimeDir, 'composables') addImports([ { from: composables, name: 'defineStore' }, { from: composables, name: 'acceptHMRUpdate' }, @@ -93,12 +97,12 @@ const module: NuxtModule = defineNuxtModule({ if (!options.storesDirs) { // resolve it against the src dir which is the root by default - options.storesDirs = [resolver.resolve(nuxt.options.srcDir, 'stores')] + options.storesDirs = [resolve(nuxt.options.srcDir, 'stores')] } if (options.storesDirs) { for (const storeDir of options.storesDirs) { - addImportsDir(resolver.resolve(nuxt.options.rootDir, storeDir)) + addImportsDir(resolve(nuxt.options.rootDir, storeDir)) } } }, diff --git a/packages/nuxt/src/runtime/payload-plugin.ts b/packages/nuxt/src/runtime/payload-plugin.ts new file mode 100644 index 0000000000..2479225613 --- /dev/null +++ b/packages/nuxt/src/runtime/payload-plugin.ts @@ -0,0 +1,19 @@ +import { + definePayloadPlugin, + definePayloadReducer, + definePayloadReviver, +} from '#imports' +import { shouldHydrate } from 'pinia' + +/** + * Removes properties marked with `skipHydrate()` to avoid sending unused data to the client. + */ +const payloadPlugin = definePayloadPlugin(() => { + definePayloadReducer( + 'skipHydrate', + (data: unknown) => !shouldHydrate(data) && undefined + ) + definePayloadReviver('skipHydrate', (data: undefined) => data) +}) + +export default payloadPlugin diff --git a/packages/nuxt/src/runtime/plugin.vue3.ts b/packages/nuxt/src/runtime/plugin.vue3.ts index f15db36457..1e101d066a 100644 --- a/packages/nuxt/src/runtime/plugin.vue3.ts +++ b/packages/nuxt/src/runtime/plugin.vue3.ts @@ -1,6 +1,7 @@ import { createPinia, setActivePinia } from 'pinia' import type { Pinia } from 'pinia' import { defineNuxtPlugin, type Plugin } from '#app' +import { toRaw } from 'vue' const plugin: Plugin<{ pinia: Pinia }> = defineNuxtPlugin({ name: 'pinia', @@ -10,7 +11,7 @@ const plugin: Plugin<{ pinia: Pinia }> = defineNuxtPlugin({ setActivePinia(pinia) if (import.meta.server) { - nuxtApp.payload.pinia = pinia.state.value + nuxtApp.payload.pinia = toRaw(pinia.state.value) } else if (nuxtApp.payload && nuxtApp.payload.pinia) { pinia.state.value = nuxtApp.payload.pinia as any } diff --git a/packages/pinia/src/index.ts b/packages/pinia/src/index.ts index d06aedc4fa..be7b83475b 100644 --- a/packages/pinia/src/index.ts +++ b/packages/pinia/src/index.ts @@ -11,7 +11,7 @@ export type { PiniaPluginContext, } from './rootStore' -export { defineStore, skipHydrate } from './store' +export { defineStore, skipHydrate, shouldHydrate } from './store' export type { StoreActions, StoreGetters, diff --git a/packages/pinia/src/store.ts b/packages/pinia/src/store.ts index 923c4b120b..e6749fd797 100644 --- a/packages/pinia/src/store.ts +++ b/packages/pinia/src/store.ts @@ -137,7 +137,7 @@ export function skipHydrate(obj: T): T { * @param obj - target variable * @returns true if `obj` should be hydrated */ -function shouldHydrate(obj: any) { +export function shouldHydrate(obj: any) { return isVue2 ? /* istanbul ignore next */ !skipHydrateMap.has(obj) : !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol) From 49281095e7fc860c9c410f72ad382665242ff181 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Thu, 26 Sep 2024 14:00:16 +0200 Subject: [PATCH 2/3] test: toto test --- packages/nuxt/__tests__/nuxt.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/nuxt/__tests__/nuxt.spec.ts b/packages/nuxt/__tests__/nuxt.spec.ts index 51f7cf5a83..30a74f3a77 100644 --- a/packages/nuxt/__tests__/nuxt.spec.ts +++ b/packages/nuxt/__tests__/nuxt.spec.ts @@ -33,4 +33,9 @@ describe('works with nuxt', async () => { const html = await $fetch('/') expect(html).toContain('Count: 101') }) + + it.todo('drop state that is marked with skipHydrate', async () => { + const html = await $fetch('/skip-hydrate') + // TODO: + }) }) From 4746ff2812e2c916cc95b908a7361c2b5c38873d Mon Sep 17 00:00:00 2001 From: Balazs Kaufmann Date: Sun, 13 Oct 2024 12:34:55 +0200 Subject: [PATCH 3/3] fix(nuxt): fix skipHydrate payload plugin and add test --- packages/nuxt/__tests__/nuxt.spec.ts | 5 +++-- packages/nuxt/playground/pages/skip-hydrate.vue | 7 ++++++- packages/nuxt/playground/tsconfig.json | 3 +++ packages/nuxt/src/runtime/payload-plugin.ts | 5 +++-- 4 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 packages/nuxt/playground/tsconfig.json diff --git a/packages/nuxt/__tests__/nuxt.spec.ts b/packages/nuxt/__tests__/nuxt.spec.ts index 30a74f3a77..563e94b432 100644 --- a/packages/nuxt/__tests__/nuxt.spec.ts +++ b/packages/nuxt/__tests__/nuxt.spec.ts @@ -34,8 +34,9 @@ describe('works with nuxt', async () => { expect(html).toContain('Count: 101') }) - it.todo('drop state that is marked with skipHydrate', async () => { + it('drops state that is marked with skipHydrate', async () => { const html = await $fetch('/skip-hydrate') - // TODO: + expect(html).not.toContain('I should not be serialized or hydrated') + expect(html).toContain('skipHydrate-wrapped state is correct') }) }) diff --git a/packages/nuxt/playground/pages/skip-hydrate.vue b/packages/nuxt/playground/pages/skip-hydrate.vue index 2ad72bb296..c3ad2aaf5d 100644 --- a/packages/nuxt/playground/pages/skip-hydrate.vue +++ b/packages/nuxt/playground/pages/skip-hydrate.vue @@ -1,8 +1,13 @@ diff --git a/packages/nuxt/playground/tsconfig.json b/packages/nuxt/playground/tsconfig.json new file mode 100644 index 0000000000..4b34df1571 --- /dev/null +++ b/packages/nuxt/playground/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./.nuxt/tsconfig.json" +} diff --git a/packages/nuxt/src/runtime/payload-plugin.ts b/packages/nuxt/src/runtime/payload-plugin.ts index 2479225613..8563543257 100644 --- a/packages/nuxt/src/runtime/payload-plugin.ts +++ b/packages/nuxt/src/runtime/payload-plugin.ts @@ -11,9 +11,10 @@ import { shouldHydrate } from 'pinia' const payloadPlugin = definePayloadPlugin(() => { definePayloadReducer( 'skipHydrate', - (data: unknown) => !shouldHydrate(data) && undefined + // We need to return something truthy to be treated as a match + (data: unknown) => !shouldHydrate(data) && 1 ) - definePayloadReviver('skipHydrate', (data: undefined) => data) + definePayloadReviver('skipHydrate', (_data: 1) => undefined) }) export default payloadPlugin