import { DeprecationTypes } from './compat/compatConfig'
import { checkCompatEnabled, isCompatEnabled } from './compat/compatConfig'
import { ObjectWatchOptionItem } from './componentOptions'
+import { useSSRContext } from '@vue/runtime-core'
+import { SSRContext } from '@vue/server-renderer'
export type WatchEffect = (onCleanup: OnCleanup) => void
}
// in SSR there is no need to setup an actual effect, and it should be noop
- // unless it's eager
+ // unless it's eager or sync flush
+ let ssrCleanup: (() => void)[] | undefined
if (__SSR__ && isInSSRComponentSetup) {
// we will also not call the invalidate callback (+ runner is not set up)
onCleanup = NOOP
onCleanup
])
}
- return NOOP
+ if (flush === 'sync') {
+ const ctx = useSSRContext() as SSRContext
+ ssrCleanup = ctx.__watcherHandles || (ctx.__watcherHandles = [])
+ } else {
+ return NOOP
+ }
}
let oldValue: any = isMultiSource
effect.run()
}
- return () => {
+ const unwatch = () => {
effect.stop()
if (instance && instance.scope) {
remove(instance.scope.effects!, effect)
}
}
+
+ if (__SSR__ && ssrCleanup) ssrCleanup.push(unwatch)
+ return unwatch
}
// this.$watch
--- /dev/null
+import { createSSRApp, defineComponent, h, watch, ref } from 'vue'
+import { SSRContext, renderToString } from '../src'
+
+describe('ssr: watch', () => {
+ // #6013
+ test('should work w/ flush:sync', async () => {
+ const App = defineComponent(() => {
+ const count = ref(0)
+ let msg = ''
+ watch(
+ count,
+ () => {
+ msg = 'hello world'
+ },
+ { flush: 'sync' }
+ )
+ count.value = 1
+ expect(msg).toBe('hello world')
+ return () => h('div', null, msg)
+ })
+
+ const app = createSSRApp(App)
+ const ctx: SSRContext = {}
+ const html = await renderToString(app, ctx)
+
+ expect(ctx.__watcherHandles!.length).toBe(1)
+
+ expect(html).toMatch('hello world')
+ })
+})
export type SSRContext = {
[key: string]: any
teleports?: Record<string, string>
+ /**
+ * @internal
+ */
__teleportBuffers?: Record<string, SSRBuffer>
+ /**
+ * @internal
+ */
+ __watcherHandles?: (() => void)[]
}
// Each component has a buffer array.
Promise.resolve(renderComponentVNode(vnode))
.then(buffer => unrollBuffer(buffer, stream))
.then(() => resolveTeleports(context))
+ .then(() => {
+ if (context.__watcherHandles) {
+ for (const unwatch of context.__watcherHandles) {
+ unwatch()
+ }
+ }
+ })
.then(() => stream.push(null))
.catch(error => {
stream.destroy(error)
await resolveTeleports(context)
+ if (context.__watcherHandles) {
+ for (const unwatch of context.__watcherHandles) {
+ unwatch()
+ }
+ }
+
return result
}