Skip to content

Commit

Permalink
fix(ssr/watch) flush: sync watchers should work in ssr (#6139)
Browse files Browse the repository at this point in the history
fix #6013
  • Loading branch information
webfansplz authored Oct 26, 2022
1 parent 32b5124 commit 0e09761
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 3 deletions.
17 changes: 14 additions & 3 deletions packages/runtime-core/src/apiWatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import { warn } from './warning'
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

Expand Down Expand Up @@ -280,7 +282,8 @@ function doWatch(
}

// 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
Expand All @@ -293,7 +296,12 @@ function doWatch(
onCleanup
])
}
return NOOP
if (flush === 'sync') {
const ctx = useSSRContext() as SSRContext
ssrCleanup = ctx.__watcherHandles || (ctx.__watcherHandles = [])
} else {
return NOOP
}
}

let oldValue: any = isMultiSource
Expand Down Expand Up @@ -378,12 +386,15 @@ function doWatch(
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
Expand Down
30 changes: 30 additions & 0 deletions packages/server-renderer/__tests__/ssrWatch.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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')
})
})
7 changes: 7 additions & 0 deletions packages/server-renderer/src/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,14 @@ export type Props = Record<string, unknown>
export type SSRContext = {
[key: string]: any
teleports?: Record<string, string>
/**
* @internal
*/
__teleportBuffers?: Record<string, SSRBuffer>
/**
* @internal
*/
__watcherHandles?: (() => void)[]
}

// Each component has a buffer array.
Expand Down
7 changes: 7 additions & 0 deletions packages/server-renderer/src/renderToStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ export function renderToSimpleStream<T extends SimpleReadable>(
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)
Expand Down
6 changes: 6 additions & 0 deletions packages/server-renderer/src/renderToString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export async function renderToString(

await resolveTeleports(context)

if (context.__watcherHandles) {
for (const unwatch of context.__watcherHandles) {
unwatch()
}
}

return result
}

Expand Down

0 comments on commit 0e09761

Please sign in to comment.