|
| 1 | +import { createSSRApp, defineComponent, h, computed, reactive } from 'vue' |
| 2 | +import { renderToString } from '../src/renderToString' |
| 3 | + |
| 4 | +// #5208 reported memory leak of keeping computed alive during SSR |
| 5 | +// so we made computed properties created during SSR non-reactive in |
| 6 | +// https://github.com/vuejs/core/commit/f4f0966b33863ac0fca6a20cf9e8ddfbb311ae87 |
| 7 | +// However, the default caching leads to #5300 which is tested below. |
| 8 | +// In Vue 2, computed properties are simple getters during SSR - this can be |
| 9 | +// inefficient if an expensive computed is accessed multiple times during render, |
| 10 | +// but because of potential mutations, we cannot cache it until we enter the |
| 11 | +// render phase (where no mutations can happen anymore) |
| 12 | +test('computed reactivity during SSR', async () => { |
| 13 | + const store = { |
| 14 | + // initial state could be hydrated |
| 15 | + state: reactive({ items: null }) as any, |
| 16 | + |
| 17 | + // pretend to fetch some data from an api |
| 18 | + async fetchData() { |
| 19 | + this.state.items = ['hello', 'world'] |
| 20 | + } |
| 21 | + } |
| 22 | + |
| 23 | + const getterSpy = jest.fn() |
| 24 | + |
| 25 | + const App = defineComponent(async () => { |
| 26 | + const msg = computed(() => { |
| 27 | + getterSpy() |
| 28 | + return store.state.items?.join(' ') |
| 29 | + }) |
| 30 | + |
| 31 | + // If msg value is falsy then we are either in ssr context or on the client |
| 32 | + // and the initial state was not modified/hydrated. |
| 33 | + // In both cases we need to fetch data. |
| 34 | + if (!msg.value) await store.fetchData() |
| 35 | + |
| 36 | + expect(msg.value).toBe('hello world') |
| 37 | + return () => h('div', null, msg.value + msg.value + msg.value) |
| 38 | + }) |
| 39 | + |
| 40 | + const app = createSSRApp(App) |
| 41 | + |
| 42 | + const html = await renderToString(app) |
| 43 | + expect(html).toMatch('hello world') |
| 44 | + |
| 45 | + // should only be called twice since access should be cached |
| 46 | + // during the render phase |
| 47 | + expect(getterSpy).toHaveBeenCalledTimes(2) |
| 48 | +}) |
0 commit comments