refactor(compiler-vapor): remove runtime fragment

returns array directly
This commit is contained in:
三咲智子 Kevin Deng 2024-02-07 17:29:04 +08:00
parent 823e47ca62
commit 99da2e5abe
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
12 changed files with 116 additions and 202 deletions

View File

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

View File

@ -1,13 +1,11 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler: v-for > basic v-for 1`] = ` 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 t0 = _template("<div></div>")
const t1 = _fragment()
export function render(_ctx) { export function render(_ctx) {
const n0 = t1()
const n1 = _createFor(() => (_ctx.items), (_block) => { const n1 = _createFor(() => (_ctx.items), (_block) => {
const n2 = t0() const n2 = t0()
const { 0: [n3],} = _children(n2) const { 0: [n3],} = _children(n2)
@ -18,19 +16,16 @@ export function render(_ctx) {
}) })
return n2 return n2
}) })
_append(n0, n1) return [n1]
return n0
}" }"
`; `;
exports[`compiler: v-for > multi effect 1`] = ` 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 t0 = _template("<div></div>")
const t1 = _fragment()
export function render(_ctx) { export function render(_ctx) {
const n0 = t1()
const n1 = _createFor(() => (_ctx.items), (_block) => { const n1 = _createFor(() => (_ctx.items), (_block) => {
const n2 = t0() const n2 = t0()
const { 0: [n3],} = _children(n2) const { 0: [n3],} = _children(n2)
@ -44,24 +39,20 @@ export function render(_ctx) {
}) })
return n2 return n2
}) })
_append(n0, n1) return [n1]
return n0
}" }"
`; `;
exports[`compiler: v-for > w/o value 1`] = ` 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 t0 = _template("<div>item</div>")
const t1 = _fragment()
export function render(_ctx) { export function render(_ctx) {
const n0 = t1()
const n1 = _createFor(() => (_ctx.items), (_block) => { const n1 = _createFor(() => (_ctx.items), (_block) => {
const n2 = t0() const n2 = t0()
return n2 return n2
}) })
_append(n0, n1) return [n1]
return n0
}" }"
`; `;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
import { fragment, template } from '../src' import { template } from '../src'
describe('api: template', () => { describe('api: template', () => {
test('create element', () => { test('create element', () => {
@ -11,16 +11,4 @@ describe('api: template', () => {
expect(root2).toBeInstanceOf(Array) expect(root2).toBeInstanceOf(Array)
expect(root2).not.toBe(root) 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)
})
}) })

View File

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