]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix: static + dynamic root nodes
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Sat, 25 Nov 2023 19:08:35 +0000 (03:08 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Sat, 25 Nov 2023 19:08:35 +0000 (03:08 +0800)
packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap
packages/compiler-vapor/__tests__/__snapshots__/fixtures.test.ts.snap
packages/compiler-vapor/__tests__/compile.test.ts
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/ir.ts
packages/compiler-vapor/src/transform.ts
playground/src/dynamic.vue [new file with mode: 0644]

index 3ec2aa6ab6350ca3f06a8f2598fe0361f8f04a79..8f977a9f7796ae2d0ead750c18b2a53e4780a206 100644 (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;
 }
 "
 `;
index a95e75c53959bf86a69e38020a3a044d9d800e05..c7d549c6c21678625aec58c133c9ac780dcf4f8b 100644 (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
 
 })();
 }
index fb17bd0c8d2a3d8118f6f8e479a9dd8f4c38f008..71773b35e55127810cfc9c5686efb114db8b4436 100644 (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()
index a21860373503ac47f15894c70ed2dc9000fa0988..dd155025ddae99c8698de089e57eae9823429217 100644 (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)
index a5c60056da346b1172aee65f6ec3a2e71a7a9ec2..dd399773f92f61e51c4d75e5ed648f472382e1c0 100644 (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>
index 797833db94809bd4e072906131065e0c4e398f78..c122d699430ee53b484f39a381d0a3f9b2ddce68 100644 (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
diff --git a/playground/src/dynamic.vue b/playground/src/dynamic.vue
new file mode 100644 (file)
index 0000000..b16aa5e
--- /dev/null
@@ -0,0 +1 @@
+<template>{{ '1' }}2{{ '3' }}</template>