Skip to content

Commit 0e09761

Browse files
authored
fix(ssr/watch) flush: sync watchers should work in ssr (#6139)
fix #6013
1 parent 32b5124 commit 0e09761

File tree

5 files changed

+64
-3
lines changed

5 files changed

+64
-3
lines changed

packages/runtime-core/src/apiWatch.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ import { warn } from './warning'
4040
import { DeprecationTypes } from './compat/compatConfig'
4141
import { checkCompatEnabled, isCompatEnabled } from './compat/compatConfig'
4242
import { ObjectWatchOptionItem } from './componentOptions'
43+
import { useSSRContext } from '@vue/runtime-core'
44+
import { SSRContext } from '@vue/server-renderer'
4345

4446
export type WatchEffect = (onCleanup: OnCleanup) => void
4547

@@ -280,7 +282,8 @@ function doWatch(
280282
}
281283

282284
// in SSR there is no need to setup an actual effect, and it should be noop
283-
// unless it's eager
285+
// unless it's eager or sync flush
286+
let ssrCleanup: (() => void)[] | undefined
284287
if (__SSR__ && isInSSRComponentSetup) {
285288
// we will also not call the invalidate callback (+ runner is not set up)
286289
onCleanup = NOOP
@@ -293,7 +296,12 @@ function doWatch(
293296
onCleanup
294297
])
295298
}
296-
return NOOP
299+
if (flush === 'sync') {
300+
const ctx = useSSRContext() as SSRContext
301+
ssrCleanup = ctx.__watcherHandles || (ctx.__watcherHandles = [])
302+
} else {
303+
return NOOP
304+
}
297305
}
298306

299307
let oldValue: any = isMultiSource
@@ -378,12 +386,15 @@ function doWatch(
378386
effect.run()
379387
}
380388

381-
return () => {
389+
const unwatch = () => {
382390
effect.stop()
383391
if (instance && instance.scope) {
384392
remove(instance.scope.effects!, effect)
385393
}
386394
}
395+
396+
if (__SSR__ && ssrCleanup) ssrCleanup.push(unwatch)
397+
return unwatch
387398
}
388399

389400
// this.$watch
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { createSSRApp, defineComponent, h, watch, ref } from 'vue'
2+
import { SSRContext, renderToString } from '../src'
3+
4+
describe('ssr: watch', () => {
5+
// #6013
6+
test('should work w/ flush:sync', async () => {
7+
const App = defineComponent(() => {
8+
const count = ref(0)
9+
let msg = ''
10+
watch(
11+
count,
12+
() => {
13+
msg = 'hello world'
14+
},
15+
{ flush: 'sync' }
16+
)
17+
count.value = 1
18+
expect(msg).toBe('hello world')
19+
return () => h('div', null, msg)
20+
})
21+
22+
const app = createSSRApp(App)
23+
const ctx: SSRContext = {}
24+
const html = await renderToString(app, ctx)
25+
26+
expect(ctx.__watcherHandles!.length).toBe(1)
27+
28+
expect(html).toMatch('hello world')
29+
})
30+
})

packages/server-renderer/src/render.ts

+7
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,14 @@ export type Props = Record<string, unknown>
4545
export type SSRContext = {
4646
[key: string]: any
4747
teleports?: Record<string, string>
48+
/**
49+
* @internal
50+
*/
4851
__teleportBuffers?: Record<string, SSRBuffer>
52+
/**
53+
* @internal
54+
*/
55+
__watcherHandles?: (() => void)[]
4956
}
5057

5158
// Each component has a buffer array.

packages/server-renderer/src/renderToStream.ts

+7
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ export function renderToSimpleStream<T extends SimpleReadable>(
7676
Promise.resolve(renderComponentVNode(vnode))
7777
.then(buffer => unrollBuffer(buffer, stream))
7878
.then(() => resolveTeleports(context))
79+
.then(() => {
80+
if (context.__watcherHandles) {
81+
for (const unwatch of context.__watcherHandles) {
82+
unwatch()
83+
}
84+
}
85+
})
7986
.then(() => stream.push(null))
8087
.catch(error => {
8188
stream.destroy(error)

packages/server-renderer/src/renderToString.ts

+6
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ export async function renderToString(
6767

6868
await resolveTeleports(context)
6969

70+
if (context.__watcherHandles) {
71+
for (const unwatch of context.__watcherHandles) {
72+
unwatch()
73+
}
74+
}
75+
7076
return result
7177
}
7278

0 commit comments

Comments
 (0)