fix: static + dynamic root nodes

This commit is contained in:
三咲智子 Kevin Deng 2023-11-26 03:08:35 +08:00
parent ac686033aa
commit 45858c085d
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
7 changed files with 96 additions and 78 deletions

View File

@ -5,7 +5,7 @@ exports[`comile > bindings 1`] = `
import { template, children, insert, setText } from 'vue/vapor';
const t0 = template(\`<div>count is <!>.</div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [
n1,
@ -19,7 +19,7 @@ export function render() {
watchEffect(() => {
setText(n2, undefined, count.value);
});
return root;
return n0;
}
"
`;
@ -29,14 +29,14 @@ exports[`comile > directives > v-bind > simple expression 1`] = `
import { template, children, setAttr } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setAttr(n1, 'id', undefined, id.value);
});
return root;
return n0;
}
"
`;
@ -46,14 +46,14 @@ exports[`comile > directives > v-html > no expression 1`] = `
import { template, children, setHtml } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setHtml(n1, undefined, '');
});
return root;
return n0;
}
"
`;
@ -63,14 +63,14 @@ exports[`comile > directives > v-html > simple expression 1`] = `
import { template, children, setHtml } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setHtml(n1, undefined, code.value);
});
return root;
return n0;
}
"
`;
@ -80,14 +80,14 @@ exports[`comile > directives > v-on > simple expression 1`] = `
import { template, children, on } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
on(n1, 'click', handleClick);
});
return root;
return n0;
}
"
`;
@ -97,14 +97,14 @@ exports[`comile > directives > v-once > as root node 1`] = `
import { template, children, setAttr } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setAttr(n1, 'id', undefined, foo);
});
return root;
return n0;
}
"
`;
@ -113,7 +113,7 @@ exports[`comile > directives > v-once > basic 1`] = `
"import { template, children, insert, setText, setAttr } from 'vue/vapor';
const t0 = template(\`<div> <span></span></div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [
n1,
@ -126,7 +126,7 @@ export function render() {
insert(n2, n1, 0 /* InsertPosition.FIRST */);
setText(n2, undefined, msg.value);
setAttr(n3, 'class', undefined, clz.value);
return root;
return n0;
}
"
`;
@ -136,14 +136,14 @@ exports[`comile > directives > v-text > no expression 1`] = `
import { template, children, setText } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setText(n1, undefined, '');
});
return root;
return n0;
}
"
`;
@ -153,42 +153,55 @@ exports[`comile > directives > v-text > simple expression 1`] = `
import { template, children, setText } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
const root = t0();
const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setText(n1, undefined, str.value);
});
return root;
return n0;
}
"
`;
exports[`comile > fragment 1`] = `
"import { template, children } from 'vue/vapor';
"import { template } from 'vue/vapor';
const t0 = template(\`<p></p><span></span><div></div>\`);
export function render() {
const root = t0();
const {
0: [n1],
1: [n2],
2: [n3],
} = children(root);
return root;
const n0 = t0();
return n0;
}
"
`;
exports[`comile > static + dynamic root 1`] = `
"import { watchEffect } from 'vue';
import { template, insert, setText } from 'vue/vapor';
const t0 = template(\`2\`);
export function render() {
const n0 = t0();
const n1 = document.createTextNode(1);
insert(n1, n0, 0 /* InsertPosition.FIRST */);
const n2 = document.createTextNode(3);
insert(n2, n0);
watchEffect(() => {
setText(n1, undefined, 1);
});
watchEffect(() => {
setText(n2, undefined, 3);
});
return n0;
}
"
`;
exports[`comile > static template 1`] = `
"import { template, children } from 'vue/vapor';
"import { template } from 'vue/vapor';
const t0 = template(\`<div><p>hello</p><input><span></span></div>\`);
export function render() {
const root = t0();
const {
0: [n1],
} = children(root);
return root;
const n0 = t0();
return n0;
}
"
`;

View File

@ -19,28 +19,28 @@ const increment = () => count.value++
return (() => {
const root = t0()
const { 0: [n1], 1: [n2], 2: [n4], 3: [n6], 4: [n7], 5: [n8], 6: [n9], 7: [n11],} = children(root)
const n3 = document.createTextNode(count.value)
insert(n3, n2)
const n5 = document.createTextNode(double.value)
insert(n5, n4)
const n10 = document.createTextNode(count.value)
insert(n10, n9)
setText(n10, undefined, count.value)
const n0 = t0()
const { 1: [n1], 2: [n3], 3: [n5], 4: [n6], 6: [n7],} = children(root)
const n2 = document.createTextNode(count.value)
insert(n2, n1)
const n4 = document.createTextNode(double.value)
insert(n4, n3)
const n8 = document.createTextNode(count.value)
insert(n8, n7)
setText(n8, undefined, count.value)
watchEffect(() => {
setText(n3, undefined, count.value)
setText(n2, undefined, count.value)
})
watchEffect(() => {
setText(n5, undefined, double.value)
setText(n4, undefined, double.value)
})
watchEffect(() => {
on(n6, \\"click\\", increment)
on(n5, \\"click\\", increment)
})
watchEffect(() => {
setHtml(n7, undefined, html)
setHtml(n6, undefined, html)
})
return root
return n0
})();
}

View File

@ -28,6 +28,11 @@ describe('comile', () => {
expect(code).matchSnapshot()
})
test('static + dynamic root', async () => {
const code = await compile(`{{ 1 }}2{{ 3 }}`)
expect(code).matchSnapshot()
})
test('fragment', async () => {
const code = await compile(`<p/><span/><div/>`)
expect(code).matchSnapshot()

View File

@ -28,9 +28,11 @@ export function generate(
}
{
code += `const root = t0()\n`
code += `const {${genChildren(ir.children.children)}} = children(root)\n`
vaporHelpers.add('children')
code += `const n${ir.children.id} = t0()\n`
if (Object.keys(ir.children.children).length) {
code += `const {${genChildren(ir.children.children)}} = children(root)\n`
vaporHelpers.add('children')
}
for (const operation of ir.operation) {
code += genOperation(operation)
@ -46,7 +48,7 @@ export function generate(
code += scope
}
// TODO multiple-template
code += `return root\n`
code += `return n${ir.children.id}\n`
}
if (vaporHelpers.size)

View File

@ -83,6 +83,7 @@ export type OperationNode =
export interface DynamicChild {
id: number | null
store: boolean
ghost: boolean
children: DynamicChildren
}
export type DynamicChildren = Record<number, DynamicChild>

View File

@ -29,8 +29,10 @@ export interface TransformContext<T extends Node = Node> {
store: boolean
ghost: boolean
once: boolean
id: number | null
getElementId(): number
getId(): number
incraseId(): number
registerTemplate(): number
registerEffect(expr: string, operation: OperationNode): void
registerOpration(...oprations: OperationNode[]): void
@ -42,7 +44,7 @@ function createRootContext(
node: RootNode,
options: TransformOptions,
): TransformContext<RootNode> {
let i = 0
let globalId = 0
const { effect, operation: operation, helpers, vaporHelpers } = ir
const ctx: TransformContext<RootNode> = {
@ -56,7 +58,12 @@ function createRootContext(
ghost: false,
once: false,
getElementId: () => i++,
id: null,
incraseId: () => globalId++,
getId() {
if (this.id !== null) return this.id
return (this.id = this.incraseId())
},
registerEffect(expr, operation) {
if (!effect[expr]) effect[expr] = []
effect[expr].push(operation)
@ -94,15 +101,11 @@ function createContext<T extends TemplateChildNode>(
parent: TransformContext,
index: number,
): TransformContext<T> {
let id: number | undefined
const getElementId = () => {
if (id !== undefined) return id
return (id = parent.root.getElementId())
}
const children = {}
const ctx: TransformContext<T> = {
...parent,
id: null,
node,
parent,
index,
@ -112,8 +115,6 @@ function createContext<T extends TemplateChildNode>(
set template(t) {
parent.template = t
},
getElementId,
children,
store: false,
registerEffect(expr, operation) {
@ -142,13 +143,14 @@ export function transform(
vaporHelpers: new Set([]),
}
const ctx = createRootContext(ir, root, options)
const rootId = ctx.getElementId()
const rootId = ctx.getId()
// TODO: transform presets, see packages/compiler-core/src/transforms
transformChildren(ctx, true)
ir.children = {
store: true,
id: rootId,
store: true,
ghost: false,
children: ctx.children,
}
@ -172,13 +174,6 @@ function transformChildren(
const isFirst = i === 0
const isLast = i === children.length - 1
// TODO: multiple root elements
if (root) {
child.store = true
// generate id for root element early
child.getElementId()
}
switch (node.type) {
case 1 satisfies NodeTypes.ELEMENT: {
transformElement(child as TransformContext<ElementNode>)
@ -215,9 +210,10 @@ function transformChildren(
if (Object.keys(child.children).length > 0 || child.store)
ctx.children[index] = {
id: child.store ? child.getElementId() : null,
id: child.store ? child.getId() : null,
store: child.store,
children: child.children,
ghost: child.ghost,
}
if (!child.ghost) index++
@ -252,7 +248,7 @@ function transformInterpolation(
const expr = processExpression(ctx, node.content)!
const parent = ctx.parent!
const parentId = parent.getElementId()
const parentId = parent.getId()
parent.store = true
if (isFirst && isLast) {
@ -267,12 +263,12 @@ function transformInterpolation(
let anchor: number | 'first' | 'last'
if (!isFirst && !isLast) {
id = ctx.root.getElementId()
anchor = ctx.getElementId()
id = ctx.incraseId()
anchor = ctx.getId()
ctx.template += '<!>'
ctx.store = true
} else {
id = ctx.getElementId()
id = ctx.getId()
ctx.ghost = true
anchor = isFirst ? 'first' : 'last'
}
@ -342,7 +338,7 @@ function transformProp(
ctx.registerEffect(expr, {
type: IRNodeTypes.SET_PROP,
loc: node.loc,
element: ctx.getElementId(),
element: ctx.getId(),
name: node.arg.content,
value: expr,
})
@ -366,7 +362,7 @@ function transformProp(
ctx.registerEffect(expr, {
type: IRNodeTypes.SET_EVENT,
loc: node.loc,
element: ctx.getElementId(),
element: ctx.getId(),
name: node.arg.content,
value: expr,
})
@ -377,7 +373,7 @@ function transformProp(
ctx.registerEffect(value, {
type: IRNodeTypes.SET_HTML,
loc: node.loc,
element: ctx.getElementId(),
element: ctx.getId(),
value,
})
break
@ -387,7 +383,7 @@ function transformProp(
ctx.registerEffect(value, {
type: IRNodeTypes.SET_TEXT,
loc: node.loc,
element: ctx.getElementId(),
element: ctx.getId(),
value,
})
break

View File

@ -0,0 +1 @@
<template>{{ '1' }}2{{ '3' }}</template>