Skip to content

Commit 8c3c14a

Browse files
committed
fix(ssr): properly update currentRenderingInstance state during ssr
fix #2863
1 parent 9036f88 commit 8c3c14a

File tree

4 files changed

+51
-8
lines changed

4 files changed

+51
-8
lines changed

packages/runtime-core/src/componentRenderContext.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,23 @@ import { closeBlock, openBlock } from './vnode'
99
export let currentRenderingInstance: ComponentInternalInstance | null = null
1010
export let currentScopeId: string | null = null
1111

12+
/**
13+
* Note: rendering calls maybe nested. The function returns the parent rendering
14+
* instance if present, which should be restored after the render is done:
15+
*
16+
* ```js
17+
* const prev = setCurrentRenderingInstance(i)
18+
* // ...render
19+
* setCurrentRenderingInstance(prev)
20+
* ```
21+
*/
1222
export function setCurrentRenderingInstance(
1323
instance: ComponentInternalInstance | null
14-
) {
24+
): ComponentInternalInstance | null {
25+
const prev = currentRenderingInstance
1526
currentRenderingInstance = instance
1627
currentScopeId = (instance && instance.type.__scopeId) || null
28+
return prev
1729
}
1830

1931
/**
@@ -40,8 +52,7 @@ export function withCtx(
4052
if (!isRenderingCompiledSlot) {
4153
openBlock(true /* null block that disables tracking */)
4254
}
43-
const prevInstance = currentRenderingInstance
44-
setCurrentRenderingInstance(ctx)
55+
const prevInstance = setCurrentRenderingInstance(ctx)
4556
const res = fn(...args)
4657
setCurrentRenderingInstance(prevInstance)
4758
if (!isRenderingCompiledSlot) {

packages/runtime-core/src/componentRenderUtils.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export function renderComponentRoot(
5353
} = instance
5454

5555
let result
56-
setCurrentRenderingInstance(instance)
56+
const prev = setCurrentRenderingInstance(instance)
5757
if (__DEV__) {
5858
accessedAttrs = false
5959
}
@@ -207,7 +207,7 @@ export function renderComponentRoot(
207207
result = createVNode(Comment)
208208
}
209209

210-
setCurrentRenderingInstance(null)
210+
setCurrentRenderingInstance(prev)
211211
return result
212212
}
213213

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

+33-1
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ import {
1111
withCtx,
1212
KeepAlive,
1313
Transition,
14-
watchEffect
14+
watchEffect,
15+
createVNode,
16+
resolveDynamicComponent
1517
} from 'vue'
1618
import { escapeHtml } from '@vue/shared'
1719
import { renderToString } from '../src/renderToString'
1820
import { renderToStream as _renderToStream } from '../src/renderToStream'
1921
import { ssrRenderSlot, SSRSlot } from '../src/helpers/ssrRenderSlot'
2022
import { ssrRenderComponent } from '../src/helpers/ssrRenderComponent'
2123
import { Readable } from 'stream'
24+
import { ssrRenderVNode } from '../src'
2225

2326
const promisifyStream = (stream: Readable) => {
2427
return new Promise<string>((resolve, reject) => {
@@ -824,5 +827,34 @@ function testRender(type: string, render: typeof renderToString) {
824827
})
825828
expect(await render(app)).toBe('<!---->')
826829
})
830+
831+
// #2863
832+
test('assets should be resolved correctly', async () => {
833+
expect(
834+
await render(
835+
createApp({
836+
components: {
837+
A: {
838+
ssrRender(_ctx, _push) {
839+
_push(`<div>A</div>`)
840+
}
841+
},
842+
B: {
843+
render: () => h('div', 'B')
844+
}
845+
},
846+
ssrRender(_ctx, _push, _parent) {
847+
const A: any = resolveComponent('A')
848+
_push(ssrRenderComponent(A, null, null, _parent))
849+
ssrRenderVNode(
850+
_push,
851+
createVNode(resolveDynamicComponent('B'), null, null),
852+
_parent
853+
)
854+
}
855+
})
856+
)
857+
).toBe(`<div>A</div><div>B</div>`)
858+
})
827859
})
828860
}

packages/server-renderer/src/render.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ function renderComponentSubTree(
139139
}
140140

141141
// set current rendering instance for asset resolution
142-
setCurrentRenderingInstance(instance)
142+
const prev = setCurrentRenderingInstance(instance)
143143
ssrRender(
144144
instance.proxy,
145145
push,
@@ -151,7 +151,7 @@ function renderComponentSubTree(
151151
instance.data,
152152
instance.ctx
153153
)
154-
setCurrentRenderingInstance(null)
154+
setCurrentRenderingInstance(prev)
155155
} else if (instance.render && instance.render !== NOOP) {
156156
renderVNode(
157157
push,

0 commit comments

Comments
 (0)