-
Notifications
You must be signed in to change notification settings - Fork 356
/
Copy pathcreateRenderFn.ts
76 lines (54 loc) · 2.14 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { withCtx, h, DefineComponent, VNode, isVNode, Text, createBlock, ComputedRef, normalizeStyle } from 'vue'
type VueInternalRenderFunction = Function
export const renderSlotNode = (node: VNode, ctx = null) => {
return withCtx(() => [node], ctx)
}
export const makeVNode = (node: VNode | string | DefineComponent) => {
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
const result: VNode = originalRenderFn.call(thisArg, customCtx, ...args.slice(1))
if ('ctx' in result) {
const variables: ComputedRef<Map<string, string>> = (result.ctx as any).$vaCssVaraibles
if (!variables) {
return result
}
if (result.props === null) {
result.props = {}
}
const vars: Record<string, string> = {}
for (const key of variables.value.keys()) {
vars[key] = variables.value.get(key)!
}
result.props.style = normalizeStyle([result.props.style, vars])
}
return result
}
}