Skip to content

Commit 219d83b

Browse files
authored
Revert "fix(server-renderer): cleanup component effect scopes after SSR render" (#14674)
Close #14669 This reverts commit 862f11e.
1 parent fa23116 commit 219d83b

File tree

5 files changed

+22
-159
lines changed

5 files changed

+22
-159
lines changed

packages/server-renderer/__tests__/render.spec.ts

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,9 @@ import {
1010
createTextVNode,
1111
createVNode,
1212
defineComponent,
13-
effectScope,
1413
getCurrentInstance,
1514
h,
1615
onErrorCaptured,
17-
onScopeDispose,
1816
onServerPrefetch,
1917
reactive,
2018
ref,
@@ -1004,84 +1002,6 @@ function testRender(type: string, render: typeof renderToString) {
10041002
expect(html).toBe(`<div>hello</div>`)
10051003
})
10061004

1007-
test('cleans up component effect scopes after each render', async () => {
1008-
const cleanups: number[] = []
1009-
const app = createApp({
1010-
setup() {
1011-
onScopeDispose(() => {
1012-
cleanups.push(1)
1013-
})
1014-
return () => h('div', 'ok')
1015-
},
1016-
})
1017-
1018-
expect(cleanups).toEqual([])
1019-
expect(await render(app)).toBe(`<div>ok</div>`)
1020-
expect(cleanups).toEqual([1])
1021-
})
1022-
1023-
test('concurrent renders isolate scope cleanup ownership', async () => {
1024-
const cleaned: string[] = []
1025-
1026-
const deferred = () => {
1027-
let resolve!: () => void
1028-
const promise = new Promise<void>(r => {
1029-
resolve = r
1030-
})
1031-
return { promise, resolve }
1032-
}
1033-
1034-
const gateA = deferred()
1035-
const gateB = deferred()
1036-
1037-
const makeApp = (id: string, gate: ReturnType<typeof deferred>) =>
1038-
createApp({
1039-
async setup() {
1040-
onScopeDispose(() => {
1041-
cleaned.push(id)
1042-
})
1043-
await gate.promise
1044-
return () => h('div', id)
1045-
},
1046-
})
1047-
1048-
const pA = render(makeApp('A', gateA))
1049-
const pB = render(makeApp('B', gateB))
1050-
1051-
gateB.resolve()
1052-
expect(await pB).toBe(`<div>B</div>`)
1053-
expect(cleaned).toEqual(['B'])
1054-
1055-
gateA.resolve()
1056-
expect(await pA).toBe(`<div>A</div>`)
1057-
expect(cleaned.sort()).toEqual(['A', 'B'])
1058-
})
1059-
1060-
test('detached scopes created during SSR are not auto-stopped', async () => {
1061-
let detachedStopped = false
1062-
let detached: any
1063-
1064-
const app = createApp({
1065-
setup() {
1066-
detached = effectScope(true)
1067-
detached.run(() => {
1068-
onScopeDispose(() => {
1069-
detachedStopped = true
1070-
})
1071-
})
1072-
return () => h('div', 'detached')
1073-
},
1074-
})
1075-
1076-
expect(await render(app)).toBe(`<div>detached</div>`)
1077-
expect(detached.active).toBe(true)
1078-
expect(detachedStopped).toBe(false)
1079-
1080-
detached.stop()
1081-
expect(detached.active).toBe(false)
1082-
expect(detachedStopped).toBe(true)
1083-
})
1084-
10851005
test('multiple onServerPrefetch', async () => {
10861006
const msg = Promise.resolve('hello')
10871007
const msg2 = Promise.resolve('hi')

packages/server-renderer/__tests__/ssrWatch.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('ssr: watch', () => {
3232
const ctx: SSRContext = {}
3333
const html = await renderToString(app, ctx)
3434

35-
expect(ctx.__watcherHandles!.length).toBe(0)
35+
expect(ctx.__watcherHandles!.length).toBe(1)
3636

3737
expect(html).toMatch('hello world')
3838
})
@@ -61,7 +61,7 @@ describe('ssr: watch', () => {
6161
const ctx: SSRContext = {}
6262
const html = await renderToString(app, ctx)
6363

64-
expect(ctx.__watcherHandles!.length).toBe(0)
64+
expect(ctx.__watcherHandles!.length).toBe(1)
6565
expect(html).toMatch('changed again')
6666
await nextTick()
6767
expect(msg).toBe('changed again')
@@ -229,7 +229,7 @@ describe('ssr: watchEffect', () => {
229229
const ctx: SSRContext = {}
230230
const html = await renderToString(app, ctx)
231231

232-
expect(ctx.__watcherHandles!.length).toBe(0)
232+
expect(ctx.__watcherHandles!.length).toBe(1)
233233
expect(html).toMatch('changed again')
234234
await nextTick()
235235
expect(msg).toBe('changed again')

packages/server-renderer/src/render.ts

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
type VNodeArrayChildren,
1212
type VNodeProps,
1313
mergeProps,
14-
ssrContextKey,
1514
ssrUtils,
1615
warn,
1716
} from 'vue'
@@ -56,37 +55,6 @@ export type SSRContext = {
5655
* @internal
5756
*/
5857
__watcherHandles?: (() => void)[]
59-
/**
60-
* @internal
61-
*/
62-
__instanceScopes?: { stop: () => void }[]
63-
}
64-
65-
export function cleanupContext(context: SSRContext): void {
66-
let firstError: unknown
67-
if (context.__watcherHandles) {
68-
for (const unwatch of context.__watcherHandles) {
69-
try {
70-
unwatch()
71-
} catch (err) {
72-
if (firstError === undefined) firstError = err
73-
}
74-
}
75-
context.__watcherHandles.length = 0
76-
}
77-
if (context.__instanceScopes) {
78-
for (const scope of context.__instanceScopes) {
79-
try {
80-
scope.stop()
81-
} catch (err) {
82-
if (firstError === undefined) firstError = err
83-
}
84-
}
85-
context.__instanceScopes.length = 0
86-
}
87-
if (firstError !== undefined) {
88-
throw firstError
89-
}
9058
}
9159

9260
// Each component has a buffer array.
@@ -130,14 +98,6 @@ export function renderComponentVNode(
13098
parentComponent,
13199
null,
132100
))
133-
const context = instance.appContext.provides[ssrContextKey as any] as
134-
| SSRContext
135-
| undefined
136-
if (context) {
137-
;(context.__instanceScopes || (context.__instanceScopes = [])).push(
138-
instance.scope,
139-
)
140-
}
141101
if (__DEV__) pushWarningContext(vnode)
142102
const res = setupComponent(instance, true /* isSSR */)
143103
if (__DEV__) popWarningContext()

packages/server-renderer/src/renderToStream.ts

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@ import {
77
ssrUtils,
88
} from 'vue'
99
import { isPromise, isString } from '@vue/shared'
10-
import {
11-
type SSRBuffer,
12-
type SSRContext,
13-
cleanupContext,
14-
renderComponentVNode,
15-
} from './render'
10+
import { type SSRBuffer, type SSRContext, renderComponentVNode } from './render'
1611
import type { Readable, Writable } from 'node:stream'
1712
import { resolveTeleports } from './renderToString'
1813

@@ -48,7 +43,7 @@ async function unrollBuffer(
4843

4944
function unrollBufferSync(buffer: SSRBuffer, stream: SimpleReadable) {
5045
for (let i = 0; i < buffer.length; i++) {
51-
const item = buffer[i]
46+
let item = buffer[i]
5247
if (isString(item)) {
5348
stream.push(item)
5449
} else {
@@ -78,27 +73,18 @@ export function renderToSimpleStream<T extends SimpleReadable>(
7873
// provide the ssr context to the tree
7974
input.provide(ssrContextKey, context)
8075

81-
let cleaned = false
82-
const finalize = () => {
83-
if (cleaned) return
84-
cleaned = true
85-
cleanupContext(context)
86-
}
87-
88-
Promise.resolve()
89-
.then(() => renderComponentVNode(vnode))
76+
Promise.resolve(renderComponentVNode(vnode))
9077
.then(buffer => unrollBuffer(buffer, stream))
9178
.then(() => resolveTeleports(context))
9279
.then(() => {
93-
finalize()
94-
return stream.push(null)
80+
if (context.__watcherHandles) {
81+
for (const unwatch of context.__watcherHandles) {
82+
unwatch()
83+
}
84+
}
9585
})
86+
.then(() => stream.push(null))
9687
.catch(error => {
97-
try {
98-
finalize()
99-
} catch {
100-
// preserve original render error as the stream failure reason
101-
}
10288
stream.destroy(error)
10389
})
10490

packages/server-renderer/src/renderToString.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@ import {
77
ssrUtils,
88
} from 'vue'
99
import { isPromise, isString } from '@vue/shared'
10-
import {
11-
type SSRBuffer,
12-
type SSRContext,
13-
cleanupContext,
14-
renderComponentVNode,
15-
} from './render'
10+
import { type SSRBuffer, type SSRContext, renderComponentVNode } from './render'
1611

1712
const { isVNode } = ssrUtils
1813

@@ -86,17 +81,19 @@ export async function renderToString(
8681
vnode.appContext = input._context
8782
// provide the ssr context to the tree
8883
input.provide(ssrContextKey, context)
89-
try {
90-
const buffer = await renderComponentVNode(vnode)
84+
const buffer = await renderComponentVNode(vnode)
9185

92-
const result = await unrollBuffer(buffer as SSRBuffer)
86+
const result = await unrollBuffer(buffer as SSRBuffer)
9387

94-
await resolveTeleports(context)
88+
await resolveTeleports(context)
9589

96-
return result
97-
} finally {
98-
cleanupContext(context)
90+
if (context.__watcherHandles) {
91+
for (const unwatch of context.__watcherHandles) {
92+
unwatch()
93+
}
9994
}
95+
96+
return result
10097
}
10198

10299
export async function resolveTeleports(context: SSRContext): Promise<void> {

0 commit comments

Comments
 (0)