-
Notifications
You must be signed in to change notification settings - Fork 355
/
Copy pathcreateRenderFn.ts
55 lines (40 loc) · 1.64 KB
/
createRenderFn.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import { withCtx, h, DefineComponent, VNode, isVNode, Text, createBlock } from 'vue'
import type { SlotProp } from '../component-config'
type VueInternalRenderFunction = Function
export const renderSlotNode = (node: VNode, ctx = null) => {
return withCtx(() => [node], ctx)
}
export const makeVNode = <T>(node: SlotProp<T>) => {
if (typeof node === 'string') {
return h(Text, node)
}
return isVNode(node) ? node : createBlock(node)
}
const renderSlots = (slots: Record<string, VNode | VueInternalRenderFunction>, ctx = null) => {
return Object.keys(slots).reduce((acc, slotName) => {
const slot = slots[slotName]
// Maybe already compiled slot or just VNode provided by user
acc[slotName] = typeof slot === 'function' ? slot : renderSlotNode(slot, ctx)
return acc
}, {} as Record<string, VueInternalRenderFunction>)
}
export const createRenderFn = (component: DefineComponent): VueInternalRenderFunction | undefined => {
const originalRenderFn = component.render || component.ssrRender
if (!originalRenderFn) { return undefined }
const compiledRenderedFn = originalRenderFn.name === '_sfc_render' || originalRenderFn.name === '_sfc_ssrRender'
return function (...args: any[]) {
const ctx = args[0]
const slots = ctx.$.slots
const customCtx = new Proxy(ctx, {
get (target, key: any) {
if (key === '$slots') {
return renderSlots(slots)
}
return target[key]
},
})
// When compile rendered function, it doesn't require thisArg
const thisArg = compiledRenderedFn ? undefined : customCtx
return originalRenderFn.call(thisArg, customCtx, ...args.slice(1))
}
}