test('explicit default slot', () => {
expect(compile(`<foo v-slot="{ msg }">{{ msg + outer }}</foo>`).code)
.toMatchInlineSnapshot(`
- "const { resolveComponent: _resolveComponent, createTextVNode: _createTextVNode } = require(\\"vue\\")
+ "const { resolveComponent: _resolveComponent, toDisplayString: _toDisplayString, createTextVNode: _createTextVNode } = require(\\"vue\\")
const { ssrRenderComponent: _ssrRenderComponent, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
_push(\`\${_ssrInterpolate(msg + _ctx.outer)}\`)
} else {
return [
- _createTextVNode(_toDisplayString(msg + _ctx.outer))
+ _createTextVNode(_toDisplayString(msg + _ctx.outer), 1 /* TEXT */)
]
}
},
<template v-for="key in names" v-slot:[key]="{ msg }">{{ msg + key + bar }}</template>
</foo>`).code
).toMatchInlineSnapshot(`
- "const { resolveComponent: _resolveComponent, createTextVNode: _createTextVNode, renderList: _renderList, createSlots: _createSlots } = require(\\"vue\\")
+ "const { resolveComponent: _resolveComponent, toDisplayString: _toDisplayString, createTextVNode: _createTextVNode, renderList: _renderList, createSlots: _createSlots } = require(\\"vue\\")
const { ssrRenderComponent: _ssrRenderComponent, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent) {
_push(\`\${_ssrInterpolate(msg + key + _ctx.bar)}\`)
} else {
return [
- _createTextVNode(_toDisplayString(msg + _ctx.key + _ctx.bar))
+ _createTextVNode(_toDisplayString(msg + _ctx.key + _ctx.bar), 1 /* TEXT */)
]
}
}
const clonedNode = clone(node)
return function ssrPostTransformComponent() {
+ // Using the cloned node, build the normal VNode-based branches (for
+ // fallback in case the child is render-fn based). Store them in an array
+ // for later use.
buildSlots(clonedNode, context, (props, children) => {
vnodeBranches.push(createVNodeSlotBranch(props, children, context))
return createFunctionExpression(undefined)
wipEntries.push({
fn,
children,
- // build the children using normal vnode-based transforms
- // TODO fixme: `children` here has already been mutated at this point
- // so the sub-transform runs into errors :/
+ // also collect the corresponding vnode branch built earlier
vnodeBranch: vnodeBranches[wipEntries.length]
})
return fn
) {
const childRoot = createRoot([node])
const childContext = createTransformContext(childRoot, options)
+ // this sub transform is for vnode fallback branch so it should be handled
+ // like normal render functions
+ childContext.ssr = false
// inherit parent scope analysis state
childContext.scopes = { ...parentContext.scopes }
childContext.identifiers = { ...parentContext.identifiers }
// setup stateful logic
let setupResult
if (shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
- setupResult = setupStatefulComponent(instance, parentSuspense)
+ setupResult = setupStatefulComponent(instance, parentSuspense, isSSR)
}
isInSSRComponentSetup = false
return setupResult
function setupStatefulComponent(
instance: ComponentInternalInstance,
- parentSuspense: SuspenseBoundary | null
+ parentSuspense: SuspenseBoundary | null,
+ isSSR: boolean
) {
const Component = instance.type as ComponentOptions
if (isInSSRComponentSetup) {
// return the promise so server-renderer can wait on it
return setupResult.then(resolvedResult => {
- handleSetupResult(instance, resolvedResult, parentSuspense)
+ handleSetupResult(instance, resolvedResult, parentSuspense, isSSR)
})
} else if (__FEATURE_SUSPENSE__) {
// async setup returned Promise.
)
}
} else {
- handleSetupResult(instance, setupResult, parentSuspense)
+ handleSetupResult(instance, setupResult, parentSuspense, isSSR)
}
} else {
- finishComponentSetup(instance, parentSuspense)
+ finishComponentSetup(instance, parentSuspense, isSSR)
}
}
export function handleSetupResult(
instance: ComponentInternalInstance,
setupResult: unknown,
- parentSuspense: SuspenseBoundary | null
+ parentSuspense: SuspenseBoundary | null,
+ isSSR: boolean
) {
if (isFunction(setupResult)) {
// setup returned an inline render function
}`
)
}
- finishComponentSetup(instance, parentSuspense)
+ finishComponentSetup(instance, parentSuspense, isSSR)
}
type CompileFunction = (
function finishComponentSetup(
instance: ComponentInternalInstance,
- parentSuspense: SuspenseBoundary | null
+ parentSuspense: SuspenseBoundary | null,
+ isSSR: boolean
) {
const Component = instance.type as ComponentOptions
- if (!instance.render) {
+
+ // template / render function normalization
+ if (__NODE_JS__ && isSSR) {
+ if (Component.render) {
+ instance.render = Component.render as RenderFunction
+ }
+ } else if (!instance.render) {
if (__RUNTIME_COMPILE__ && Component.template && !Component.render) {
// __RUNTIME_COMPILE__ ensures `compile` is provided
Component.render = compile!(Component.template, {
;(Component.render as RenderFunction).isRuntimeCompiled = true
}
- if (__DEV__ && !Component.render && !Component.ssrRender) {
+ if (__DEV__ && !Component.render) {
/* istanbul ignore if */
if (!__RUNTIME_COMPILE__ && Component.template) {
warn(
if (__DEV__) {
pushWarningContext(vnode)
}
- handleSetupResult(instance, asyncSetupResult, suspense)
+ handleSetupResult(instance, asyncSetupResult, suspense, false)
// unset placeholder, otherwise this will be treated as a hydration mount
vnode.el = null
setupRenderEffect(
}
}
+function renderComponentSubTree(
+ instance: ComponentInternalInstance
+): ResolvedSSRBuffer | Promise<ResolvedSSRBuffer> {
+ const comp = instance.type as Component
+ const { getBuffer, push } = createBuffer()
+ if (isFunction(comp)) {
+ renderVNode(push, renderComponentRoot(instance), instance)
+ } else {
+ if (!instance.render && !comp.ssrRender && isString(comp.template)) {
+ comp.ssrRender = ssrCompile(comp.template, instance)
+ }
+
+ if (comp.ssrRender) {
+ // optimized
+ // set current rendering instance for asset resolution
+ setCurrentRenderingInstance(instance)
+ comp.ssrRender(instance.proxy, push, instance)
+ setCurrentRenderingInstance(null)
+ } else if (instance.render) {
+ renderVNode(push, renderComponentRoot(instance), instance)
+ } else {
+ throw new Error(
+ `Component ${
+ comp.name ? `${comp.name} ` : ``
+ } is missing template or render function.`
+ )
+ }
+ }
+ return getBuffer()
+}
+
type SSRRenderFunction = (
context: any,
push: (item: any) => void,
}
}
})
- return (compileCache[template] = Function(code)())
-}
-
-function renderComponentSubTree(
- instance: ComponentInternalInstance
-): ResolvedSSRBuffer | Promise<ResolvedSSRBuffer> {
- const comp = instance.type as Component
- const { getBuffer, push } = createBuffer()
- if (isFunction(comp)) {
- renderVNode(push, renderComponentRoot(instance), instance)
- } else {
- if (!instance.render && !comp.ssrRender && isString(comp.template)) {
- comp.ssrRender = ssrCompile(comp.template, instance)
- }
-
- if (comp.ssrRender) {
- // optimized
- // set current rendering instance for asset resolution
- setCurrentRenderingInstance(instance)
- comp.ssrRender(instance.proxy, push, instance)
- setCurrentRenderingInstance(null)
- } else if (instance.render) {
- renderVNode(push, renderComponentRoot(instance), instance)
- } else {
- throw new Error(
- `Component ${
- comp.name ? `${comp.name} ` : ``
- } is missing template or render function.`
- )
- }
- }
- return getBuffer()
+ return (compileCache[template] = Function('require', code)(require))
}
function renderVNode(