mirror of https://github.com/vuejs/core.git
feat: dynamic root node
This commit is contained in:
parent
acec2409c7
commit
91e7f9bb83
|
@ -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
|
||||||
|
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,14 @@ const html = '<b>HTML</b>'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1 id="title">Counter</h1>
|
<div>
|
||||||
<p>Count: {{ count }}</p>
|
<h1 id="title">Counter</h1>
|
||||||
<p>Double: {{ double }}</p>
|
<p>Count: {{ count }}</p>
|
||||||
<button @click="increment">Increment</button>
|
<p>Double: {{ double }}</p>
|
||||||
<div v-html="html" />
|
<button @click="increment">Increment</button>
|
||||||
<input type="text" />
|
<div v-html="html" />
|
||||||
<p v-once>once: {{ count }}</p>
|
<input type="text" />
|
||||||
<p v-pre>{{ count }}</p>
|
<p v-once>once: {{ count }}</p>
|
||||||
|
<p v-pre>{{ count }}</p>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -27,29 +27,32 @@ 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`
|
|
||||||
vaporHelpers.add('children')
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const operation of ir.operation) {
|
if (Object.keys(children).length) {
|
||||||
code += genOperation(operation)
|
code += `const {${genChildren(children)}} = children(n${id})\n`
|
||||||
}
|
vaporHelpers.add('children')
|
||||||
|
|
||||||
for (const [_expr, operations] of Object.entries(ir.effect)) {
|
|
||||||
// TODO don't use watchEffect from vue/core, implement `effect` function in runtime-vapor package
|
|
||||||
let scope = `watchEffect(() => {\n`
|
|
||||||
helpers.add('watchEffect')
|
|
||||||
for (const operation of operations) {
|
|
||||||
scope += genOperation(operation)
|
|
||||||
}
|
}
|
||||||
scope += '})\n'
|
|
||||||
code += scope
|
|
||||||
}
|
|
||||||
|
|
||||||
code += 'return root'
|
for (const operation of ir.operation) {
|
||||||
|
code += genOperation(operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [_expr, operations] of Object.entries(ir.effect)) {
|
||||||
|
// TODO don't use watchEffect from vue/core, implement `effect` function in runtime-vapor package
|
||||||
|
let scope = `watchEffect(() => {\n`
|
||||||
|
helpers.add('watchEffect')
|
||||||
|
for (const operation of operations) {
|
||||||
|
scope += genOperation(operation)
|
||||||
|
}
|
||||||
|
scope += '})\n'
|
||||||
|
code += scope
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO multiple-template
|
||||||
|
code += `return n${id}\n`
|
||||||
|
}
|
||||||
|
|
||||||
if (vaporHelpers.size)
|
if (vaporHelpers.size)
|
||||||
preamble =
|
preamble =
|
||||||
|
|
|
@ -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>)
|
||||||
|
|
|
@ -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>
|
|
@ -1,9 +1,11 @@
|
||||||
import { render } from 'vue/vapor'
|
import { render } from 'vue/vapor'
|
||||||
import App from './App.vue'
|
|
||||||
|
|
||||||
render(() => {
|
const modules = import.meta.glob<any>('./*.vue')
|
||||||
// @ts-expect-error
|
const mod = (modules['.' + location.pathname] || modules['./App.vue'])()
|
||||||
const returned = App.setup({}, { expose() {} })
|
|
||||||
// @ts-expect-error
|
mod.then(({ default: m }) => {
|
||||||
return App.render(returned)
|
render(() => {
|
||||||
}, '#app')
|
const returned = m.setup({}, { expose() {} })
|
||||||
|
return m.render(returned)
|
||||||
|
}, '#app')
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in New Issue