feat: dynamic root node

This commit is contained in:
三咲智子 Kevin Deng 2023-11-24 20:29:05 +08:00
parent acec2409c7
commit 91e7f9bb83
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
7 changed files with 100 additions and 59 deletions

View File

@ -5,11 +5,12 @@ exports[`comile > bindings 1`] = `
import { template, setText } from 'vue/vapor' import { template, setText } from 'vue/vapor'
const t0 = template(\`<div></div>\`) const t0 = template(\`<div></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
watchEffect(() => { watchEffect(() => {
setText(n0, undefined, count.value) setText(n0, undefined, count.value)
}) })
return root return n0
}" }"
`; `;
@ -18,11 +19,12 @@ exports[`comile > directives > v-bind > simple expression 1`] = `
import { template, setAttr } from 'vue/vapor' import { template, setAttr } from 'vue/vapor'
const t0 = template(\`<div></div>\`) const t0 = template(\`<div></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
watchEffect(() => { watchEffect(() => {
setAttr(n0, \\"id\\", undefined, id.value) setAttr(n0, \\"id\\", undefined, id.value)
}) })
return root return n0
}" }"
`; `;
@ -31,11 +33,12 @@ exports[`comile > directives > v-html > no expression 1`] = `
import { template, setHtml } from 'vue/vapor' import { template, setHtml } from 'vue/vapor'
const t0 = template(\`<div></div>\`) const t0 = template(\`<div></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
watchEffect(() => { watchEffect(() => {
setHtml(n0, undefined, \\"\\") setHtml(n0, undefined, \\"\\")
}) })
return root return n0
}" }"
`; `;
@ -44,11 +47,12 @@ exports[`comile > directives > v-html > simple expression 1`] = `
import { template, setHtml } from 'vue/vapor' import { template, setHtml } from 'vue/vapor'
const t0 = template(\`<div></div>\`) const t0 = template(\`<div></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
watchEffect(() => { watchEffect(() => {
setHtml(n0, undefined, code.value) setHtml(n0, undefined, code.value)
}) })
return root return n0
}" }"
`; `;
@ -57,11 +61,12 @@ exports[`comile > directives > v-on > simple expression 1`] = `
import { template, on } from 'vue/vapor' import { template, on } from 'vue/vapor'
const t0 = template(\`<div></div>\`) const t0 = template(\`<div></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
watchEffect(() => { watchEffect(() => {
on(n0, \\"click\\", handleClick) on(n0, \\"click\\", handleClick)
}) })
return root return n0
}" }"
`; `;
@ -69,13 +74,14 @@ exports[`comile > directives > v-once 1`] = `
"import { template, children, insert, setText, setAttr } from 'vue/vapor' "import { template, children, insert, setText, setAttr } from 'vue/vapor'
const t0 = template(\`<div> <span></span></div>\`) const t0 = template(\`<div> <span></span></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
const { 1: [n2],} = children(root) const { 1: [n2],} = children(n0)
const n1 = document.createTextNode(msg.value) const n1 = document.createTextNode(msg.value)
insert(n1, n0, 0 /* InsertPosition.FIRST */) insert(n1, n0, 0 /* InsertPosition.FIRST */)
setText(n1, undefined, msg.value) setText(n1, undefined, msg.value)
setAttr(n2, \\"class\\", undefined, clz.value) setAttr(n2, \\"class\\", undefined, clz.value)
return root return n0
}" }"
`; `;
@ -84,11 +90,12 @@ exports[`comile > directives > v-text > no expression 1`] = `
import { template, setText } from 'vue/vapor' import { template, setText } from 'vue/vapor'
const t0 = template(\`<div></div>\`) const t0 = template(\`<div></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
watchEffect(() => { watchEffect(() => {
setText(n0, undefined, \\"\\") setText(n0, undefined, \\"\\")
}) })
return root return n0
}" }"
`; `;
@ -97,11 +104,12 @@ exports[`comile > directives > v-text > simple expression 1`] = `
import { template, setText } from 'vue/vapor' import { template, setText } from 'vue/vapor'
const t0 = template(\`<div></div>\`) const t0 = template(\`<div></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
watchEffect(() => { watchEffect(() => {
setText(n0, undefined, str.value) setText(n0, undefined, str.value)
}) })
return root return n0
}" }"
`; `;
@ -109,7 +117,8 @@ exports[`comile > static template 1`] = `
"import { template } from 'vue/vapor' "import { template } from 'vue/vapor'
const t0 = template(\`<div><p>hello</p><input><span></span></div>\`) const t0 = template(\`<div><p>hello</p><input><span></span></div>\`)
export function render() { export function render() {
const root = t0() const n0 = t0()
return root return n0
}" }"
`; `;

View File

@ -3,8 +3,8 @@
exports[`fixtures 1`] = ` exports[`fixtures 1`] = `
"import { defineComponent as _defineComponent } from 'vue' "import { defineComponent as _defineComponent } from 'vue'
import { watchEffect } from 'vue' import { watchEffect } from 'vue'
import { template, insert, setText, on, setHtml } from 'vue/vapor' import { template, children, insert, setText, on, setHtml } from 'vue/vapor'
const t0 = template(\`<h1 id=\\"title\\">Counter</h1><p>Count: </p><p>Double: </p><button>Increment</button><div></div><input type=\\"text\\"><p>once: </p><p>{{ count }}</p>\`) const t0 = template(\`<div><h1 id=\\"title\\">Counter</h1><p>Count: </p><p>Double: </p><button>Increment</button><div></div><input type=\\"text\\"><p>once: </p><p>{{ count }}</p></div>\`)
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
const html = '<b>HTML</b>' const html = '<b>HTML</b>'
@ -19,7 +19,8 @@ const increment = () => count.value++
return (() => { return (() => {
const root = t0() const n8 = t0()
const { 1: [n0], 2: [n2], 3: [n4], 4: [n5], 6: [n6],} = children(n8)
const n1 = document.createTextNode(count.value) const n1 = document.createTextNode(count.value)
insert(n1, n0) insert(n1, n0)
const n3 = document.createTextNode(double.value) const n3 = document.createTextNode(double.value)
@ -39,7 +40,8 @@ on(n4, \\"click\\", increment)
watchEffect(() => { watchEffect(() => {
setHtml(n5, undefined, html) setHtml(n5, undefined, html)
}) })
return root return n8
})(); })();
} }

View File

@ -10,6 +10,7 @@ const html = '<b>HTML</b>'
</script> </script>
<template> <template>
<div>
<h1 id="title">Counter</h1> <h1 id="title">Counter</h1>
<p>Count: {{ count }}</p> <p>Count: {{ count }}</p>
<p>Double: {{ double }}</p> <p>Double: {{ double }}</p>
@ -18,4 +19,5 @@ const html = '<b>HTML</b>'
<input type="text" /> <input type="text" />
<p v-once>once: {{ count }}</p> <p v-once>once: {{ count }}</p>
<p v-pre>{{ count }}</p> <p v-pre>{{ count }}</p>
</div>
</template> </template>

View File

@ -27,10 +27,11 @@ export function generate(
vaporHelpers.add('template') vaporHelpers.add('template')
} }
// TODO multiple-template for (const [, { id, children }] of Object.entries(ir.children)) {
code += `const root = t0()\n` code += `const n${id} = t0()\n`
if (ir.children[0] && Object.keys(ir.children[0].children).length) {
code += `const {${genChildren(ir.children[0].children)}} = children(root)\n` if (Object.keys(children).length) {
code += `const {${genChildren(children)}} = children(n${id})\n`
vaporHelpers.add('children') vaporHelpers.add('children')
} }
@ -49,7 +50,9 @@ export function generate(
code += scope code += scope
} }
code += 'return root' // TODO multiple-template
code += `return n${id}\n`
}
if (vaporHelpers.size) if (vaporHelpers.size)
preamble = preamble =

View File

@ -121,7 +121,7 @@ function createContext<T extends TemplateChildNode>(
if (ctx.once) { if (ctx.once) {
return ctx.registerOpration(operation) return ctx.registerOpration(operation)
} }
parent.registerEffect(expr, operation) return parent.registerEffect(expr, operation)
}, },
} }
return ctx return ctx
@ -168,6 +168,9 @@ function transformChildren(
const isFirst = i === 0 const isFirst = i === 0
const isLast = i === children.length - 1 const isLast = i === children.length - 1
// TODO: multiple root elements
if (root) child.store = true
switch (node.type) { switch (node.type) {
case 1 satisfies NodeTypes.ELEMENT: { case 1 satisfies NodeTypes.ELEMENT: {
transformElement(child as TransformContext<ElementNode>) transformElement(child as TransformContext<ElementNode>)

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(1)
const handleClick = () => {
count.value++
}
// @ts-expect-error
globalThis.count = count
// @ts-expect-error
globalThis.handleClick = handleClick
</script>
<template>
<button @click="handleClick">
{{ count }}
</button>
</template>

View File

@ -1,9 +1,11 @@
import { render } from 'vue/vapor' import { render } from 'vue/vapor'
import App from './App.vue'
const modules = import.meta.glob<any>('./*.vue')
const mod = (modules['.' + location.pathname] || modules['./App.vue'])()
mod.then(({ default: m }) => {
render(() => { render(() => {
// @ts-expect-error const returned = m.setup({}, { expose() {} })
const returned = App.setup({}, { expose() {} }) return m.render(returned)
// @ts-expect-error
return App.render(returned)
}, '#app') }, '#app')
})