2023-11-17 03:01:19 +08:00
|
|
|
import {
|
|
|
|
CodegenContext,
|
|
|
|
CodegenOptions,
|
2023-11-23 23:42:08 +08:00
|
|
|
CodegenResult,
|
2023-11-17 03:01:19 +08:00
|
|
|
} from '@vue/compiler-dom'
|
2023-11-23 23:42:08 +08:00
|
|
|
import { DynamicChildren, IRNodeTypes, RootIRNode } from './transform'
|
2023-11-17 03:01:19 +08:00
|
|
|
|
|
|
|
// IR -> JS codegen
|
|
|
|
export function generate(
|
2023-11-23 23:42:08 +08:00
|
|
|
ir: RootIRNode,
|
2023-11-17 03:01:19 +08:00
|
|
|
options: CodegenOptions & {
|
|
|
|
onContextCreated?: (context: CodegenContext) => void
|
2023-11-23 23:42:08 +08:00
|
|
|
} = {},
|
2023-11-17 03:01:19 +08:00
|
|
|
): CodegenResult {
|
|
|
|
let code = ''
|
2023-11-23 23:42:08 +08:00
|
|
|
let preamble = `import { watchEffect } from 'vue'
|
|
|
|
import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
|
2023-11-17 03:01:19 +08:00
|
|
|
|
|
|
|
const isSetupInlined = !!options.inline
|
|
|
|
|
2023-11-23 23:42:08 +08:00
|
|
|
preamble += ir.template
|
2023-11-17 17:35:49 +08:00
|
|
|
.map((template, i) => `const t${i} = template(\`${template.template}\`)\n`)
|
|
|
|
.join('')
|
2023-11-17 03:01:19 +08:00
|
|
|
|
2023-11-23 23:42:08 +08:00
|
|
|
code += `const root = t0()\n`
|
|
|
|
|
|
|
|
if (ir.children[0]) {
|
|
|
|
code += `const {${genChildrens(
|
|
|
|
ir.children[0].children,
|
|
|
|
)}} = children(root)\n`
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const opration of ir.opration) {
|
|
|
|
switch (opration.type) {
|
|
|
|
case IRNodeTypes.TEXT_NODE: {
|
|
|
|
code += `const n${opration.id} = document.createTextNode(${opration.content})\n`
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
case IRNodeTypes.INSERT_NODE:
|
|
|
|
{
|
|
|
|
let anchor = ''
|
|
|
|
if (typeof opration.anchor === 'number') {
|
|
|
|
anchor = `, n${opration.anchor}`
|
|
|
|
} else if (opration.anchor === 'first') {
|
|
|
|
anchor = `, 0 /* InsertPosition.FIRST */`
|
|
|
|
}
|
|
|
|
code += `insert(n${opration.element}, n${opration.parent}${anchor})\n`
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const [expr, effects] of Object.entries(ir.effect)) {
|
|
|
|
let scope = `watchEffect(() => {\n`
|
|
|
|
for (const effect of effects) {
|
|
|
|
switch (effect.type) {
|
|
|
|
case IRNodeTypes.SET_PROP:
|
|
|
|
scope += `setAttr(n${effect.element}, ${JSON.stringify(
|
|
|
|
effect.name,
|
|
|
|
)}, undefined, ${expr})\n`
|
|
|
|
break
|
|
|
|
case IRNodeTypes.SET_TEXT:
|
|
|
|
scope += `setText(n${effect.element}, undefined, ${expr})\n`
|
|
|
|
break
|
|
|
|
case IRNodeTypes.SET_EVENT:
|
|
|
|
scope += `on(n${effect.element}, ${JSON.stringify(
|
|
|
|
effect.name,
|
|
|
|
)}, ${expr})\n`
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
scope += '})\n'
|
|
|
|
code += scope
|
|
|
|
}
|
|
|
|
|
2023-11-17 03:01:19 +08:00
|
|
|
code += 'return root'
|
|
|
|
|
|
|
|
const functionName = options.ssr ? `ssrRender` : `render`
|
|
|
|
if (isSetupInlined) {
|
|
|
|
code = `(() => {\n${code}\n})();`
|
|
|
|
} else {
|
2023-11-17 17:35:49 +08:00
|
|
|
code = `${preamble}export function ${functionName}() {\n${code}\n}`
|
2023-11-17 03:01:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
code,
|
2023-11-23 23:42:08 +08:00
|
|
|
ast: ir as any,
|
|
|
|
preamble,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function genChildrens(children: DynamicChildren) {
|
|
|
|
let str = ''
|
|
|
|
for (const [index, child] of Object.entries(children)) {
|
|
|
|
str += ` ${index}: [`
|
|
|
|
if (child.store) {
|
|
|
|
str += `n${child.id}`
|
|
|
|
}
|
|
|
|
if (Object.keys(child.children).length) {
|
|
|
|
str += `, {${genChildrens(child.children)}}`
|
|
|
|
}
|
|
|
|
str += '],'
|
2023-11-17 03:01:19 +08:00
|
|
|
}
|
2023-11-23 23:42:08 +08:00
|
|
|
return str
|
2023-11-17 03:01:19 +08:00
|
|
|
}
|