| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- import { computed, createSSRApp, defineComponent, h, reactive, ref } from 'vue'
- import { renderToString } from '../src/renderToString'
- // #5208 reported memory leak of keeping computed alive during SSR
- // so we made computed properties created during SSR non-reactive in
- // https://github.com/vuejs/core/commit/f4f0966b33863ac0fca6a20cf9e8ddfbb311ae87
- // However, the default caching leads to #5300 which is tested below.
- // In Vue 2, computed properties are simple getters during SSR - this can be
- // inefficient if an expensive computed is accessed multiple times during render,
- // but because of potential mutations, we cannot cache it until we enter the
- // render phase (where no mutations can happen anymore)
- test('computed reactivity during SSR', async () => {
- const store = {
- // initial state could be hydrated
- state: reactive({ items: null }) as any,
- // pretend to fetch some data from an api
- async fetchData() {
- this.state.items = ['hello', 'world']
- },
- }
- const getterSpy = vi.fn()
- const App = defineComponent(async () => {
- const msg = computed(() => {
- getterSpy()
- return store.state.items?.join(' ')
- })
- // If msg value is falsy then we are either in ssr context or on the client
- // and the initial state was not modified/hydrated.
- // In both cases we need to fetch data.
- if (!msg.value) await store.fetchData()
- return () => h('div', null, msg.value + msg.value + msg.value)
- })
- const app = createSSRApp(App)
- const html = await renderToString(app)
- expect(html).toMatch('hello world')
- // should only be called twice since access should be cached
- // during the render phase
- expect(getterSpy).toHaveBeenCalledTimes(2)
- })
- // although we technically shouldn't allow state mutation during render,
- // it does sometimes happen
- test('computed mutation during render', async () => {
- const App = defineComponent(async () => {
- const n = ref(0)
- const m = computed(() => n.value + 1)
- m.value // force non-dirty
- return () => {
- n.value++
- return h('div', null, `value: ${m.value}`)
- }
- })
- const app = createSSRApp(App)
- const html = await renderToString(app)
- expect(html).toMatch('value: 2')
- })
|