فهرست منبع

Revert "fix(server-renderer): cleanup component effect scopes after SSR render" (#14674)

Close #14669
This reverts commit 862f11ee017d51cb9573a8c0642055b3b17cace8.
edison 3 هفته پیش
والد
کامیت
219d83bd30

+ 0 - 80
packages/server-renderer/__tests__/render.spec.ts

@@ -10,11 +10,9 @@ import {
   createTextVNode,
   createVNode,
   defineComponent,
-  effectScope,
   getCurrentInstance,
   h,
   onErrorCaptured,
-  onScopeDispose,
   onServerPrefetch,
   reactive,
   ref,
@@ -1004,84 +1002,6 @@ function testRender(type: string, render: typeof renderToString) {
       expect(html).toBe(`<div>hello</div>`)
     })
 
-    test('cleans up component effect scopes after each render', async () => {
-      const cleanups: number[] = []
-      const app = createApp({
-        setup() {
-          onScopeDispose(() => {
-            cleanups.push(1)
-          })
-          return () => h('div', 'ok')
-        },
-      })
-
-      expect(cleanups).toEqual([])
-      expect(await render(app)).toBe(`<div>ok</div>`)
-      expect(cleanups).toEqual([1])
-    })
-
-    test('concurrent renders isolate scope cleanup ownership', async () => {
-      const cleaned: string[] = []
-
-      const deferred = () => {
-        let resolve!: () => void
-        const promise = new Promise<void>(r => {
-          resolve = r
-        })
-        return { promise, resolve }
-      }
-
-      const gateA = deferred()
-      const gateB = deferred()
-
-      const makeApp = (id: string, gate: ReturnType<typeof deferred>) =>
-        createApp({
-          async setup() {
-            onScopeDispose(() => {
-              cleaned.push(id)
-            })
-            await gate.promise
-            return () => h('div', id)
-          },
-        })
-
-      const pA = render(makeApp('A', gateA))
-      const pB = render(makeApp('B', gateB))
-
-      gateB.resolve()
-      expect(await pB).toBe(`<div>B</div>`)
-      expect(cleaned).toEqual(['B'])
-
-      gateA.resolve()
-      expect(await pA).toBe(`<div>A</div>`)
-      expect(cleaned.sort()).toEqual(['A', 'B'])
-    })
-
-    test('detached scopes created during SSR are not auto-stopped', async () => {
-      let detachedStopped = false
-      let detached: any
-
-      const app = createApp({
-        setup() {
-          detached = effectScope(true)
-          detached.run(() => {
-            onScopeDispose(() => {
-              detachedStopped = true
-            })
-          })
-          return () => h('div', 'detached')
-        },
-      })
-
-      expect(await render(app)).toBe(`<div>detached</div>`)
-      expect(detached.active).toBe(true)
-      expect(detachedStopped).toBe(false)
-
-      detached.stop()
-      expect(detached.active).toBe(false)
-      expect(detachedStopped).toBe(true)
-    })
-
     test('multiple onServerPrefetch', async () => {
       const msg = Promise.resolve('hello')
       const msg2 = Promise.resolve('hi')

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

@@ -32,7 +32,7 @@ describe('ssr: watch', () => {
     const ctx: SSRContext = {}
     const html = await renderToString(app, ctx)
 
-    expect(ctx.__watcherHandles!.length).toBe(0)
+    expect(ctx.__watcherHandles!.length).toBe(1)
 
     expect(html).toMatch('hello world')
   })
@@ -61,7 +61,7 @@ describe('ssr: watch', () => {
     const ctx: SSRContext = {}
     const html = await renderToString(app, ctx)
 
-    expect(ctx.__watcherHandles!.length).toBe(0)
+    expect(ctx.__watcherHandles!.length).toBe(1)
     expect(html).toMatch('changed again')
     await nextTick()
     expect(msg).toBe('changed again')
@@ -229,7 +229,7 @@ describe('ssr: watchEffect', () => {
     const ctx: SSRContext = {}
     const html = await renderToString(app, ctx)
 
-    expect(ctx.__watcherHandles!.length).toBe(0)
+    expect(ctx.__watcherHandles!.length).toBe(1)
     expect(html).toMatch('changed again')
     await nextTick()
     expect(msg).toBe('changed again')

+ 0 - 40
packages/server-renderer/src/render.ts

@@ -11,7 +11,6 @@ import {
   type VNodeArrayChildren,
   type VNodeProps,
   mergeProps,
-  ssrContextKey,
   ssrUtils,
   warn,
 } from 'vue'
@@ -56,37 +55,6 @@ export type SSRContext = {
    * @internal
    */
   __watcherHandles?: (() => void)[]
-  /**
-   * @internal
-   */
-  __instanceScopes?: { stop: () => void }[]
-}
-
-export function cleanupContext(context: SSRContext): void {
-  let firstError: unknown
-  if (context.__watcherHandles) {
-    for (const unwatch of context.__watcherHandles) {
-      try {
-        unwatch()
-      } catch (err) {
-        if (firstError === undefined) firstError = err
-      }
-    }
-    context.__watcherHandles.length = 0
-  }
-  if (context.__instanceScopes) {
-    for (const scope of context.__instanceScopes) {
-      try {
-        scope.stop()
-      } catch (err) {
-        if (firstError === undefined) firstError = err
-      }
-    }
-    context.__instanceScopes.length = 0
-  }
-  if (firstError !== undefined) {
-    throw firstError
-  }
 }
 
 // Each component has a buffer array.
@@ -130,14 +98,6 @@ export function renderComponentVNode(
     parentComponent,
     null,
   ))
-  const context = instance.appContext.provides[ssrContextKey as any] as
-    | SSRContext
-    | undefined
-  if (context) {
-    ;(context.__instanceScopes || (context.__instanceScopes = [])).push(
-      instance.scope,
-    )
-  }
   if (__DEV__) pushWarningContext(vnode)
   const res = setupComponent(instance, true /* isSSR */)
   if (__DEV__) popWarningContext()

+ 9 - 23
packages/server-renderer/src/renderToStream.ts

@@ -7,12 +7,7 @@ import {
   ssrUtils,
 } from 'vue'
 import { isPromise, isString } from '@vue/shared'
-import {
-  type SSRBuffer,
-  type SSRContext,
-  cleanupContext,
-  renderComponentVNode,
-} from './render'
+import { type SSRBuffer, type SSRContext, renderComponentVNode } from './render'
 import type { Readable, Writable } from 'node:stream'
 import { resolveTeleports } from './renderToString'
 
@@ -48,7 +43,7 @@ async function unrollBuffer(
 
 function unrollBufferSync(buffer: SSRBuffer, stream: SimpleReadable) {
   for (let i = 0; i < buffer.length; i++) {
-    const item = buffer[i]
+    let item = buffer[i]
     if (isString(item)) {
       stream.push(item)
     } else {
@@ -78,27 +73,18 @@ export function renderToSimpleStream<T extends SimpleReadable>(
   // provide the ssr context to the tree
   input.provide(ssrContextKey, context)
 
-  let cleaned = false
-  const finalize = () => {
-    if (cleaned) return
-    cleaned = true
-    cleanupContext(context)
-  }
-
-  Promise.resolve()
-    .then(() => renderComponentVNode(vnode))
+  Promise.resolve(renderComponentVNode(vnode))
     .then(buffer => unrollBuffer(buffer, stream))
     .then(() => resolveTeleports(context))
     .then(() => {
-      finalize()
-      return stream.push(null)
+      if (context.__watcherHandles) {
+        for (const unwatch of context.__watcherHandles) {
+          unwatch()
+        }
+      }
     })
+    .then(() => stream.push(null))
     .catch(error => {
-      try {
-        finalize()
-      } catch {
-        // preserve original render error as the stream failure reason
-      }
       stream.destroy(error)
     })
 

+ 10 - 13
packages/server-renderer/src/renderToString.ts

@@ -7,12 +7,7 @@ import {
   ssrUtils,
 } from 'vue'
 import { isPromise, isString } from '@vue/shared'
-import {
-  type SSRBuffer,
-  type SSRContext,
-  cleanupContext,
-  renderComponentVNode,
-} from './render'
+import { type SSRBuffer, type SSRContext, renderComponentVNode } from './render'
 
 const { isVNode } = ssrUtils
 
@@ -86,17 +81,19 @@ export async function renderToString(
   vnode.appContext = input._context
   // provide the ssr context to the tree
   input.provide(ssrContextKey, context)
-  try {
-    const buffer = await renderComponentVNode(vnode)
+  const buffer = await renderComponentVNode(vnode)
 
-    const result = await unrollBuffer(buffer as SSRBuffer)
+  const result = await unrollBuffer(buffer as SSRBuffer)
 
-    await resolveTeleports(context)
+  await resolveTeleports(context)
 
-    return result
-  } finally {
-    cleanupContext(context)
+  if (context.__watcherHandles) {
+    for (const unwatch of context.__watcherHandles) {
+      unwatch()
+    }
   }
+
+  return result
 }
 
 export async function resolveTeleports(context: SSRContext): Promise<void> {