]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(ssr): properly update currentRenderingInstance state during ssr
authorEvan You <yyx990803@gmail.com>
Fri, 26 Mar 2021 18:00:03 +0000 (14:00 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 26 Mar 2021 18:00:03 +0000 (14:00 -0400)
fix #2863

packages/runtime-core/src/componentRenderContext.ts
packages/runtime-core/src/componentRenderUtils.ts
packages/server-renderer/__tests__/render.spec.ts
packages/server-renderer/src/render.ts

index 78297dc5a5456d4f2a33ae5bcb389bca6a73cadd..c74712a0353e3468a87a23307cb3586208bfa052 100644 (file)
@@ -9,11 +9,23 @@ import { closeBlock, openBlock } from './vnode'
 export let currentRenderingInstance: ComponentInternalInstance | null = null
 export let currentScopeId: string | null = null
 
+/**
+ * Note: rendering calls maybe nested. The function returns the parent rendering
+ * instance if present, which should be restored after the render is done:
+ *
+ * ```js
+ * const prev = setCurrentRenderingInstance(i)
+ * // ...render
+ * setCurrentRenderingInstance(prev)
+ * ```
+ */
 export function setCurrentRenderingInstance(
   instance: ComponentInternalInstance | null
-) {
+): ComponentInternalInstance | null {
+  const prev = currentRenderingInstance
   currentRenderingInstance = instance
   currentScopeId = (instance && instance.type.__scopeId) || null
+  return prev
 }
 
 /**
@@ -40,8 +52,7 @@ export function withCtx(
     if (!isRenderingCompiledSlot) {
       openBlock(true /* null block that disables tracking */)
     }
-    const prevInstance = currentRenderingInstance
-    setCurrentRenderingInstance(ctx)
+    const prevInstance = setCurrentRenderingInstance(ctx)
     const res = fn(...args)
     setCurrentRenderingInstance(prevInstance)
     if (!isRenderingCompiledSlot) {
index eee05f18bb67959fa1d42f11f1299bf4beb58f4c..1274f474e635507a74e7c67249f22ee3c45679dd 100644 (file)
@@ -53,7 +53,7 @@ export function renderComponentRoot(
   } = instance
 
   let result
-  setCurrentRenderingInstance(instance)
+  const prev = setCurrentRenderingInstance(instance)
   if (__DEV__) {
     accessedAttrs = false
   }
@@ -207,7 +207,7 @@ export function renderComponentRoot(
     result = createVNode(Comment)
   }
 
-  setCurrentRenderingInstance(null)
+  setCurrentRenderingInstance(prev)
   return result
 }
 
index bb7009f8776c9f2ae12702036dfa1e935f03f472..67bc23450b8719a0684408aaddfee596293b57ad 100644 (file)
@@ -11,7 +11,9 @@ import {
   withCtx,
   KeepAlive,
   Transition,
-  watchEffect
+  watchEffect,
+  createVNode,
+  resolveDynamicComponent
 } from 'vue'
 import { escapeHtml } from '@vue/shared'
 import { renderToString } from '../src/renderToString'
@@ -19,6 +21,7 @@ import { renderToStream as _renderToStream } from '../src/renderToStream'
 import { ssrRenderSlot, SSRSlot } from '../src/helpers/ssrRenderSlot'
 import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent'
 import { Readable } from 'stream'
+import { ssrRenderVNode } from '../src'
 
 const promisifyStream = (stream: Readable) => {
   return new Promise<string>((resolve, reject) => {
@@ -824,5 +827,34 @@ function testRender(type: string, render: typeof renderToString) {
       })
       expect(await render(app)).toBe('<!---->')
     })
+
+    // #2863
+    test('assets should be resolved correctly', async () => {
+      expect(
+        await render(
+          createApp({
+            components: {
+              A: {
+                ssrRender(_ctx, _push) {
+                  _push(`<div>A</div>`)
+                }
+              },
+              B: {
+                render: () => h('div', 'B')
+              }
+            },
+            ssrRender(_ctx, _push, _parent) {
+              const A: any = resolveComponent('A')
+              _push(ssrRenderComponent(A, null, null, _parent))
+              ssrRenderVNode(
+                _push,
+                createVNode(resolveDynamicComponent('B'), null, null),
+                _parent
+              )
+            }
+          })
+        )
+      ).toBe(`<div>A</div><div>B</div>`)
+    })
   })
 }
index 77a268b516b91ade7e1547cba2cf2ba39ffee934..4f20e52e3f8ec55e24744bf377673a61df57b7ce 100644 (file)
@@ -139,7 +139,7 @@ function renderComponentSubTree(
       }
 
       // set current rendering instance for asset resolution
-      setCurrentRenderingInstance(instance)
+      const prev = setCurrentRenderingInstance(instance)
       ssrRender(
         instance.proxy,
         push,
@@ -151,7 +151,7 @@ function renderComponentSubTree(
         instance.data,
         instance.ctx
       )
-      setCurrentRenderingInstance(null)
+      setCurrentRenderingInstance(prev)
     } else if (instance.render && instance.render !== NOOP) {
       renderVNode(
         push,