vue3-core/packages/compiler-vapor/src/generate.ts

107 lines
2.7 KiB
TypeScript
Raw Normal View History

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
}