Просмотр исходного кода

refactor(compiler-vapor): remove runtime fragment

returns array directly
三咲智子 Kevin Deng 2 лет назад
Родитель
Сommit
99da2e5abe

+ 6 - 18
packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap

@@ -172,16 +172,12 @@ export function render(_ctx) {
 `;
 
 exports[`compile > dynamic root 1`] = `
-"import { fragment as _fragment, createTextNode as _createTextNode, append as _append, renderEffect as _renderEffect, setText as _setText } from 'vue/vapor';
-
-const t0 = _fragment()
+"import { createTextNode as _createTextNode, renderEffect as _renderEffect, setText as _setText } from 'vue/vapor';
 
 export function render(_ctx) {
-  const n0 = t0()
   const n1 = _createTextNode()
-  _append(n0, n1)
   _renderEffect(() => _setText(n1, 1, 2))
-  return n0
+  return [n1]
 }"
 `;
 
@@ -201,14 +197,10 @@ export function render(_ctx) {
 `;
 
 exports[`compile > expression parsing > interpolation 1`] = `
-"
-const t0 = _fragment()
-(() => {
-  const n0 = t0()
+"(() => {
   const n1 = _createTextNode()
-  _append(n0, n1)
   _renderEffect(() => _setText(n1, a + b.value))
-  return n0
+  return [n1]
 })()"
 `;
 
@@ -235,16 +227,12 @@ export function render(_ctx) {
 `;
 
 exports[`compile > static + dynamic root 1`] = `
-"import { fragment as _fragment, createTextNode as _createTextNode, append as _append, renderEffect as _renderEffect, setText as _setText } from 'vue/vapor';
-
-const t0 = _fragment()
+"import { createTextNode as _createTextNode, renderEffect as _renderEffect, setText as _setText } from 'vue/vapor';
 
 export function render(_ctx) {
-  const n0 = t0()
   const n1 = _createTextNode()
-  _append(n0, n1)
   _renderEffect(() => _setText(n1, 1, 2, "3", 4, 5, "6", 7, 8, "9", 'A', 'B'))
-  return n0
+  return [n1]
 }"
 `;
 

+ 6 - 15
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap

@@ -1,13 +1,11 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`compiler: v-for > basic v-for 1`] = `
-"import { template as _template, fragment as _fragment, children as _children, on as _on, renderEffect as _renderEffect, setText as _setText, createFor as _createFor, append as _append } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on, renderEffect as _renderEffect, setText as _setText, createFor as _createFor } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
-const t1 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t1()
   const n1 = _createFor(() => (_ctx.items), (_block) => {
     const n2 = t0()
     const { 0: [n3],} = _children(n2)
@@ -18,19 +16,16 @@ export function render(_ctx) {
     })
     return n2
   })
-  _append(n0, n1)
-  return n0
+  return [n1]
 }"
 `;
 
 exports[`compiler: v-for > multi effect 1`] = `
-"import { template as _template, fragment as _fragment, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor, append as _append } from 'vue/vapor';
+"import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
-const t1 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t1()
   const n1 = _createFor(() => (_ctx.items), (_block) => {
     const n2 = t0()
     const { 0: [n3],} = _children(n2)
@@ -44,24 +39,20 @@ export function render(_ctx) {
     })
     return n2
   })
-  _append(n0, n1)
-  return n0
+  return [n1]
 }"
 `;
 
 exports[`compiler: v-for > w/o value 1`] = `
-"import { template as _template, fragment as _fragment, createFor as _createFor, append as _append } from 'vue/vapor';
+"import { template as _template, createFor as _createFor } from 'vue/vapor';
 
 const t0 = _template("<div>item</div>")
-const t1 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t1()
   const n1 = _createFor(() => (_ctx.items), (_block) => {
     const n2 = t0()
     return n2
   })
-  _append(n0, n1)
-  return n0
+  return [n1]
 }"
 `;

+ 12 - 30
packages/compiler-vapor/__tests__/transforms/__snapshots__/vIf.spec.ts.snap

@@ -1,21 +1,18 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`compiler: v-if > basic v-if 1`] = `
-"import { template as _template, fragment as _fragment, children as _children, renderEffect as _renderEffect, setText as _setText, createIf as _createIf, append as _append } from 'vue/vapor';
+"import { template as _template, children as _children, renderEffect as _renderEffect, setText as _setText, createIf as _createIf } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
-const t1 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t1()
   const n1 = _createIf(() => (_ctx.ok), () => {
     const n2 = t0()
     const { 0: [n3],} = _children(n2)
     _renderEffect(() => _setText(n3, _ctx.msg))
     return n2
   })
-  _append(n0, n1)
-  return n0
+  return [n1]
 }"
 `;
 
@@ -47,13 +44,11 @@ export function render(_ctx) {
 `;
 
 exports[`compiler: v-if > dedupe same template 1`] = `
-"import { template as _template, fragment as _fragment, createIf as _createIf, append as _append } from 'vue/vapor';
+"import { template as _template, createIf as _createIf } from 'vue/vapor';
 
 const t0 = _template("<div>hello</div>")
-const t1 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t1()
   const n1 = _createIf(() => (_ctx.ok), () => {
     const n2 = t0()
     return n2
@@ -62,39 +57,33 @@ export function render(_ctx) {
     const n4 = t0()
     return n4
   })
-  _append(n0, n1, n3)
-  return n0
+  return [n1, n3]
 }"
 `;
 
 exports[`compiler: v-if > template v-if 1`] = `
-"import { template as _template, fragment as _fragment, children as _children, renderEffect as _renderEffect, setText as _setText, createIf as _createIf, append as _append } from 'vue/vapor';
+"import { template as _template, children as _children, renderEffect as _renderEffect, setText as _setText, createIf as _createIf } from 'vue/vapor';
 
 const t0 = _template("<div></div>hello<p></p>")
-const t1 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t1()
   const n1 = _createIf(() => (_ctx.ok), () => {
     const n2 = t0()
     const { 2: [n3],} = _children(n2)
     _renderEffect(() => _setText(n3, _ctx.msg))
     return n2
   })
-  _append(n0, n1)
-  return n0
+  return [n1]
 }"
 `;
 
 exports[`compiler: v-if > v-if + v-else 1`] = `
-"import { template as _template, fragment as _fragment, createIf as _createIf, append as _append } from 'vue/vapor';
+"import { template as _template, createIf as _createIf } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 const t1 = _template("<p></p>")
-const t2 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t2()
   const n1 = _createIf(() => (_ctx.ok), () => {
     const n2 = t0()
     return n2
@@ -102,21 +91,18 @@ export function render(_ctx) {
     const n3 = t1()
     return n3
   })
-  _append(n0, n1)
-  return n0
+  return [n1]
 }"
 `;
 
 exports[`compiler: v-if > v-if + v-else-if + v-else 1`] = `
-"import { template as _template, fragment as _fragment, createIf as _createIf, append as _append } from 'vue/vapor';
+"import { template as _template, createIf as _createIf } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 const t1 = _template("<p></p>")
 const t2 = _template("fine")
-const t3 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t3()
   const n1 = _createIf(() => (_ctx.ok), () => {
     const n2 = t0()
     return n2
@@ -127,20 +113,17 @@ export function render(_ctx) {
     const n4 = t2()
     return n4
   }))
-  _append(n0, n1)
-  return n0
+  return [n1]
 }"
 `;
 
 exports[`compiler: v-if > v-if + v-else-if 1`] = `
-"import { template as _template, fragment as _fragment, createIf as _createIf, append as _append } from 'vue/vapor';
+"import { template as _template, createIf as _createIf } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 const t1 = _template("<p></p>")
-const t2 = _fragment()
 
 export function render(_ctx) {
-  const n0 = t2()
   const n1 = _createIf(() => (_ctx.ok), () => {
     const n2 = t0()
     return n2
@@ -148,7 +131,6 @@ export function render(_ctx) {
     const n3 = t1()
     return n3
   }))
-  _append(n0, n1)
-  return n0
+  return [n1]
 }"
 `;

+ 2 - 9
packages/compiler-vapor/__tests__/transforms/vFor.spec.ts

@@ -27,15 +27,12 @@ describe('compiler: v-for', () => {
     expect(code).matchSnapshot()
     expect(vaporHelpers).contains('createFor')
     expect(helpers.size).toBe(0)
-    expect(ir.template).lengthOf(2)
+    expect(ir.template).lengthOf(1)
     expect(ir.template).toMatchObject([
       {
         template: '<div></div>',
         type: IRNodeTypes.TEMPLATE_FACTORY,
       },
-      {
-        type: IRNodeTypes.FRAGMENT_FACTORY,
-      },
     ])
     expect(ir.operation).toMatchObject([
       {
@@ -56,12 +53,8 @@ describe('compiler: v-for', () => {
           templateIndex: 0,
         },
       },
-      {
-        type: IRNodeTypes.APPEND_NODE,
-        elements: [1],
-        parent: 0,
-      },
     ])
+    expect(ir.returns).toEqual([1])
     expect(ir.dynamic).toMatchObject({
       id: 0,
       children: { 0: { id: 1 } },

+ 23 - 38
packages/compiler-vapor/__tests__/transforms/vIf.spec.ts

@@ -31,15 +31,12 @@ describe('compiler: v-if', () => {
     expect(vaporHelpers).contains('createIf')
     expect(helpers.size).toBe(0)
 
-    expect(ir.template).lengthOf(2)
+    expect(ir.template).lengthOf(1)
     expect(ir.template).toMatchObject([
       {
         template: '<div></div>',
         type: IRNodeTypes.TEMPLATE_FACTORY,
       },
-      {
-        type: IRNodeTypes.FRAGMENT_FACTORY,
-      },
     ])
     expect(ir.operation).toMatchObject([
       {
@@ -55,12 +52,8 @@ describe('compiler: v-if', () => {
           templateIndex: 0,
         },
       },
-      {
-        type: IRNodeTypes.APPEND_NODE,
-        elements: [1],
-        parent: 0,
-      },
     ])
+    expect(ir.returns).toEqual([1])
 
     expect(ir.dynamic).toMatchObject({
       id: 0,
@@ -79,11 +72,13 @@ describe('compiler: v-if', () => {
     )
     expect(code).matchSnapshot()
 
-    expect(ir.template).lengthOf(2)
-    expect(ir.template[0]).toMatchObject({
-      template: '<div></div>hello<p></p>',
-      type: IRNodeTypes.TEMPLATE_FACTORY,
-    })
+    expect(ir.template).lengthOf(1)
+    expect(ir.template).toMatchObject([
+      {
+        template: '<div></div>hello<p></p>',
+        type: IRNodeTypes.TEMPLATE_FACTORY,
+      },
+    ])
 
     expect(ir.effect).toEqual([])
     expect((ir.operation[0] as IfIRNode).positive.effect).toMatchObject([
@@ -114,7 +109,14 @@ describe('compiler: v-if', () => {
       `<div v-if="ok">hello</div><div v-if="ok">hello</div>`,
     )
     expect(code).matchSnapshot()
-    expect(ir.template).lengthOf(2)
+    expect(ir.template).lengthOf(1)
+    expect(ir.template).toMatchObject([
+      {
+        template: '<div>hello</div>',
+        type: 2,
+      },
+    ])
+    expect(ir.returns).toEqual([1, 3])
   })
 
   test.todo('v-if with v-once')
@@ -125,7 +127,7 @@ describe('compiler: v-if', () => {
       `<div v-if="ok"/><p v-else/>`,
     )
     expect(code).matchSnapshot()
-    expect(ir.template).lengthOf(3)
+    expect(ir.template).lengthOf(2)
     expect(ir.template).toMatchObject([
       {
         template: '<div></div>',
@@ -135,9 +137,6 @@ describe('compiler: v-if', () => {
         template: '<p></p>',
         type: IRNodeTypes.TEMPLATE_FACTORY,
       },
-      {
-        type: IRNodeTypes.FRAGMENT_FACTORY,
-      },
     ])
 
     expect(vaporHelpers).contains('createIf')
@@ -161,12 +160,8 @@ describe('compiler: v-if', () => {
           templateIndex: 1,
         },
       },
-      {
-        type: IRNodeTypes.APPEND_NODE,
-        elements: [1],
-        parent: 0,
-      },
     ])
+    expect(ir.returns).toEqual([1])
   })
 
   test('v-if + v-else-if', () => {
@@ -174,7 +169,7 @@ describe('compiler: v-if', () => {
       `<div v-if="ok"/><p v-else-if="orNot"/>`,
     )
     expect(code).matchSnapshot()
-    expect(ir.template).lengthOf(3)
+    expect(ir.template).lengthOf(2)
     expect(ir.template).toMatchObject([
       {
         template: '<div></div>',
@@ -184,7 +179,6 @@ describe('compiler: v-if', () => {
         template: '<p></p>',
         type: IRNodeTypes.TEMPLATE_FACTORY,
       },
-      { type: IRNodeTypes.FRAGMENT_FACTORY },
     ])
 
     expect(ir.operation).toMatchObject([
@@ -213,12 +207,8 @@ describe('compiler: v-if', () => {
           },
         },
       },
-      {
-        type: IRNodeTypes.APPEND_NODE,
-        elements: [1],
-        parent: 0,
-      },
     ])
+    expect(ir.returns).toEqual([1])
   })
 
   test('v-if + v-else-if + v-else', () => {
@@ -226,7 +216,7 @@ describe('compiler: v-if', () => {
       `<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`,
     )
     expect(code).matchSnapshot()
-    expect(ir.template).lengthOf(4)
+    expect(ir.template).lengthOf(3)
     expect(ir.template).toMatchObject([
       {
         template: '<div></div>',
@@ -240,9 +230,9 @@ describe('compiler: v-if', () => {
         template: 'fine',
         type: IRNodeTypes.TEMPLATE_FACTORY,
       },
-      { type: IRNodeTypes.FRAGMENT_FACTORY },
     ])
 
+    expect(ir.returns).toEqual([1])
     expect(ir.operation).toMatchObject([
       {
         type: IRNodeTypes.IF,
@@ -263,11 +253,6 @@ describe('compiler: v-if', () => {
           },
         },
       },
-      {
-        type: IRNodeTypes.APPEND_NODE,
-        elements: [1],
-        parent: 0,
-      },
     ])
   })
 

+ 15 - 6
packages/compiler-vapor/src/generators/block.ts

@@ -38,11 +38,12 @@ export function genBlockFunctionContent(
   ir: BlockFunctionIRNode | RootIRNode,
   context: CodegenContext,
 ): CodeFragment[] {
-  const { vaporHelper } = context
-  const [frag, push] = buildCodeFragment(
-    NEWLINE,
-    `const n${ir.dynamic.id} = t${ir.templateIndex}()`,
-  )
+  const { vaporHelper, multi } = context
+  const [frag, push] = buildCodeFragment()
+
+  if (ir.templateIndex > -1) {
+    push(NEWLINE, `const n${ir.dynamic.id} = t${ir.templateIndex}()`)
+  }
 
   const children = genChildren(ir.dynamic.children)
   if (children) {
@@ -62,7 +63,15 @@ export function genBlockFunctionContent(
 
   push(...genOperations(ir.operation, context))
   push(...(context.genEffect || genEffects)(ir.effect, context))
-  push(NEWLINE, `return n${ir.dynamic.id}`)
+  if (ir.returns) {
+    push(
+      NEWLINE,
+      `return `,
+      ...multi(['[', ']', ', '], ...ir.returns.map(n => `n${n}`)),
+    )
+  } else {
+    push(NEWLINE, `return n${ir.dynamic.id}`)
+  }
 
   return frag
 }

+ 9 - 18
packages/compiler-vapor/src/generators/template.ts

@@ -1,25 +1,16 @@
 import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
-import {
-  type FragmentFactoryIRNode,
-  IRNodeTypes,
-  type TemplateFactoryIRNode,
-} from '../ir'
+import type { TemplateFactoryIRNode } from '../ir'
 
 export function genTemplate(
-  node: TemplateFactoryIRNode | FragmentFactoryIRNode,
+  node: TemplateFactoryIRNode,
   index: number,
   { vaporHelper }: CodegenContext,
 ): CodeFragment[] {
-  if (node.type === IRNodeTypes.TEMPLATE_FACTORY) {
-    // TODO source map?
-    return [
-      NEWLINE,
-      `const t${index} = ${vaporHelper('template')}(${JSON.stringify(
-        node.template,
-      )})`,
-    ]
-  } else {
-    // fragment
-    return [NEWLINE, `const t${index} = ${vaporHelper('fragment')}()`]
-  }
+  // TODO source map?
+  return [
+    NEWLINE,
+    `const t${index} = ${vaporHelper('template')}(${JSON.stringify(
+      node.template,
+    )})`,
+  ]
 }

+ 3 - 11
packages/compiler-vapor/src/ir.ts

@@ -18,7 +18,6 @@ export enum IRNodeTypes {
   BLOCK_FUNCTION,
 
   TEMPLATE_FACTORY,
-  FRAGMENT_FACTORY,
 
   SET_PROP,
   SET_DYNAMIC_PROPS,
@@ -52,13 +51,14 @@ export interface BlockFunctionIRNode extends BaseIRNode {
   dynamic: IRDynamicInfo
   effect: IREffect[]
   operation: OperationNode[]
+  returns?: number[]
 }
 
 export interface RootIRNode extends Omit<BlockFunctionIRNode, 'type'> {
   type: IRNodeTypes.ROOT
   node: RootNode
   source: string
-  template: Array<TemplateFactoryIRNode | FragmentFactoryIRNode>
+  template: Array<TemplateFactoryIRNode>
 }
 
 export interface IfIRNode extends BaseIRNode {
@@ -84,10 +84,6 @@ export interface TemplateFactoryIRNode extends BaseIRNode {
   template: string
 }
 
-export interface FragmentFactoryIRNode extends BaseIRNode {
-  type: IRNodeTypes.FRAGMENT_FACTORY
-}
-
 export interface IRProp extends Omit<DirectiveTransformResult, 'value'> {
   values: SimpleExpressionNode[]
 }
@@ -180,11 +176,7 @@ export interface WithDirectiveIRNode extends BaseIRNode {
   builtin?: VaporHelper
 }
 
-export type IRNode =
-  | OperationNode
-  | RootIRNode
-  | TemplateFactoryIRNode
-  | FragmentFactoryIRNode
+export type IRNode = OperationNode | RootIRNode | TemplateFactoryIRNode
 export type OperationNode =
   | SetPropIRNode
   | SetDynamicPropsIRNode

+ 24 - 20
packages/compiler-vapor/src/transform.ts

@@ -19,14 +19,12 @@ import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
 import {
   type BlockIRNode,
   DynamicFlag,
-  type FragmentFactoryIRNode,
   type HackOptions,
   type IRDynamicInfo,
   type IRExpression,
   IRNodeTypes,
   type OperationNode,
   type RootIRNode,
-  type TemplateFactoryIRNode,
   type VaporDirectiveNode,
 } from './ir'
 
@@ -191,29 +189,21 @@ function createRootContext(
     childrenTemplate: [],
     registerTemplate() {
       this.template += this.childrenTemplate.filter(Boolean).join('')
-      let templateNode: TemplateFactoryIRNode | FragmentFactoryIRNode
+      if (!this.template) {
+        return -1
+      }
 
-      const existing = root.template.findIndex(t =>
-        this.template
-          ? t.type === IRNodeTypes.TEMPLATE_FACTORY &&
-            t.template === this.template
-          : t.type === IRNodeTypes.FRAGMENT_FACTORY,
+      const existing = root.template.findIndex(
+        t => t.template === this.template,
       )
       if (existing !== -1) {
         return (this.block.templateIndex = existing)
       }
 
-      if (this.template) {
-        templateNode = {
-          type: IRNodeTypes.TEMPLATE_FACTORY,
-          template: this.template,
-        }
-      } else {
-        templateNode = {
-          type: IRNodeTypes.FRAGMENT_FACTORY,
-        }
-      }
-      root.template.push(templateNode)
+      root.template.push({
+        type: IRNodeTypes.TEMPLATE_FACTORY,
+        template: this.template,
+      })
       return (this.block.templateIndex = root.template.length - 1)
     },
     registerOperation(...node) {
@@ -334,8 +324,22 @@ function processDynamicChildren(
 ) {
   let prevDynamics: IRDynamicInfo[] = []
   let hasStaticTemplate = false
+  const children = context.dynamic.children
+
+  const isFragment = context.block.node === context.node
+  const allNonTemplate = children.every(
+    child => child.flags & DynamicFlag.NON_TEMPLATE,
+  )
+  // all non-template: don't gen fragment but return array directly
+  if (isFragment && allNonTemplate) {
+    context.block.returns = children
+      .filter(child => child.flags & DynamicFlag.INSERT)
+      .map(child => child.id!)
+    return
+  }
 
-  for (const [index, child] of context.dynamic.children.entries()) {
+  // mixed: insert with anchor
+  for (const [index, child] of children.entries()) {
     if (child.flags & DynamicFlag.INSERT) {
       prevDynamics.push(child)
     }

+ 15 - 20
packages/runtime-vapor/__tests__/if.spec.ts

@@ -3,7 +3,6 @@ import {
   append,
   children,
   createIf,
-  fragment,
   insert,
   nextTick,
   ref,
@@ -116,31 +115,27 @@ describe('createIf', () => {
 
     const t0 = template('Vapor')
     const t1 = template('Hello ')
-    const t2 = fragment()
     render(
       defineComponent({
         setup() {
           // render
           return (() => {
-            const n0 = t2()
-            append(
-              n0,
-              createIf(
-                () => ok1.value,
-                () => {
-                  const n2 = t1()
-                  append(
-                    n2,
-                    createIf(
-                      () => ok2.value,
-                      () => t0(),
-                    ),
-                  )
-                  return n2
-                },
-              ),
+            const n1 = createIf(
+              () => ok1.value,
+              () => {
+                const n2 = t1()
+                const n3 = createIf(
+                  () => ok2.value,
+                  () => {
+                    const n4 = t0()
+                    return n4
+                  },
+                )
+                append(n2, n3)
+                return n2
+              },
             )
-            return n0
+            return [n1]
           })()
         },
       }) as any,

+ 1 - 13
packages/runtime-vapor/__tests__/template.spec.ts

@@ -1,4 +1,4 @@
-import { fragment, template } from '../src'
+import { template } from '../src'
 
 describe('api: template', () => {
   test('create element', () => {
@@ -11,16 +11,4 @@ describe('api: template', () => {
     expect(root2).toBeInstanceOf(Array)
     expect(root2).not.toBe(root)
   })
-
-  test('create fragment', () => {
-    const frag = fragment()
-
-    const root = frag()
-    expect(root).toBeInstanceOf(Array)
-    expect(root.length).toBe(0)
-
-    const root2 = frag()
-    expect(root2).toBeInstanceOf(Array)
-    expect(root2).not.toBe(root)
-  })
 })

+ 0 - 4
packages/runtime-vapor/src/template.ts

@@ -23,7 +23,3 @@ export function template(str: string): () => ChildNode[] {
 function fragmentToNodes(node: DocumentFragment): ChildNode[] {
   return Array.from((node.cloneNode(true) as DocumentFragment).childNodes)
 }
-
-export function fragment(): () => ChildNode[] {
-  return () => []
-}