From 45858c085d2d0a323bcfa9be9fb6a5fba3c5cf84 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Sun, 26 Nov 2023 03:08:35 +0800 Subject: [PATCH] fix: static + dynamic root nodes --- .../__snapshots__/compile.test.ts.snap | 77 +++++++++++-------- .../__snapshots__/fixtures.test.ts.snap | 28 +++---- .../compiler-vapor/__tests__/compile.test.ts | 5 ++ packages/compiler-vapor/src/generate.ts | 10 ++- packages/compiler-vapor/src/ir.ts | 1 + packages/compiler-vapor/src/transform.ts | 52 ++++++------- playground/src/dynamic.vue | 1 + 7 files changed, 96 insertions(+), 78 deletions(-) create mode 100644 playground/src/dynamic.vue diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap index 3ec2aa6ab6..8f977a9f77 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap @@ -5,7 +5,7 @@ exports[`comile > bindings 1`] = ` import { template, children, insert, setText } from 'vue/vapor'; const t0 = template(\`
count is .
\`); 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(\`
\`); 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(\`
\`); 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(\`
\`); 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(\`
\`); 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(\`
\`); 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(\`
\`); 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(\`
\`); 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(\`
\`); 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(\`

\`); 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(\`

hello

\`); export function render() { - const root = t0(); - const { - 0: [n1], - } = children(root); - return root; + const n0 = t0(); + return n0; } " `; diff --git a/packages/compiler-vapor/__tests__/__snapshots__/fixtures.test.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/fixtures.test.ts.snap index a95e75c539..c7d549c6c2 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/fixtures.test.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/fixtures.test.ts.snap @@ -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 })(); } diff --git a/packages/compiler-vapor/__tests__/compile.test.ts b/packages/compiler-vapor/__tests__/compile.test.ts index fb17bd0c8d..71773b35e5 100644 --- a/packages/compiler-vapor/__tests__/compile.test.ts +++ b/packages/compiler-vapor/__tests__/compile.test.ts @@ -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(`

`) expect(code).matchSnapshot() diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index a218603735..dd155025dd 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -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) diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir.ts index a5c60056da..dd399773f9 100644 --- a/packages/compiler-vapor/src/ir.ts +++ b/packages/compiler-vapor/src/ir.ts @@ -83,6 +83,7 @@ export type OperationNode = export interface DynamicChild { id: number | null store: boolean + ghost: boolean children: DynamicChildren } export type DynamicChildren = Record diff --git a/packages/compiler-vapor/src/transform.ts b/packages/compiler-vapor/src/transform.ts index 797833db94..c122d69943 100644 --- a/packages/compiler-vapor/src/transform.ts +++ b/packages/compiler-vapor/src/transform.ts @@ -29,8 +29,10 @@ export interface TransformContext { 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 { - let i = 0 + let globalId = 0 const { effect, operation: operation, helpers, vaporHelpers } = ir const ctx: TransformContext = { @@ -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( parent: TransformContext, index: number, ): TransformContext { - let id: number | undefined - const getElementId = () => { - if (id !== undefined) return id - return (id = parent.root.getElementId()) - } const children = {} const ctx: TransformContext = { ...parent, + id: null, node, parent, index, @@ -112,8 +115,6 @@ function createContext( 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) @@ -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 diff --git a/playground/src/dynamic.vue b/playground/src/dynamic.vue new file mode 100644 index 0000000000..b16aa5e951 --- /dev/null +++ b/playground/src/dynamic.vue @@ -0,0 +1 @@ + -- 2.47.2