From 97c40a69fb604df3210b99164a927ec8dc44529e Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 7 Mar 2025 20:38:03 +0800 Subject: [PATCH] refactor(vapor): refactor interpolation transform to make it hydration friendly --- .../__snapshots__/compile.spec.ts.snap | 22 +++-- .../__snapshots__/expression.spec.ts.snap | 15 ++-- .../transformChildren.spec.ts.snap | 18 ++-- .../__snapshots__/transformText.spec.ts.snap | 11 ++- .../__snapshots__/vOnce.spec.ts.snap | 10 +-- .../__snapshots__/vSlot.spec.ts.snap | 31 ++++--- .../transforms/transformChildren.spec.ts | 5 +- .../transforms/transformText.spec.ts | 19 ++-- .../__tests__/transforms/vOnce.spec.ts | 9 +- .../compiler-vapor/src/generators/template.ts | 5 +- .../src/transforms/transformText.ts | 87 +++++++++++++------ packages/runtime-vapor/src/dom/template.ts | 6 +- 12 files changed, 137 insertions(+), 101 deletions(-) diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap index 323b9df78..04e7d793b 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap @@ -149,17 +149,17 @@ export function render(_ctx, $props, $emit, $attrs, $slots) { `; exports[`compile > directives > v-pre > should not affect siblings after it 1`] = ` -"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, createTextNode as _createTextNode, insert as _insert, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; +"import { resolveComponent as _resolveComponent, child as _child, createComponentWithFallback as _createComponentWithFallback, prepend as _prepend, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue'; const t0 = _template("
{{ bar }}
") -const t1 = _template("
") +const t1 = _template("
") export function render(_ctx, $props, $emit, $attrs, $slots) { const _component_Comp = _resolveComponent("Comp") const n0 = t0() const n3 = t1() + const n2 = _child(n3) const n1 = _createComponentWithFallback(_component_Comp) - const n2 = _createTextNode() - _insert([n1, n2], n3) + _prepend(n3, n1) _renderEffect(() => { _setText(n2, _toDisplayString(_ctx.bar)) _setProp(n3, "id", _ctx.foo) @@ -169,10 +169,12 @@ export function render(_ctx, $props, $emit, $attrs, $slots) { `; exports[`compile > dynamic root 1`] = ` -"import { createTextNode as _createTextNode, toDisplayString as _toDisplayString } from 'vue'; +"import { toDisplayString as _toDisplayString, setText as _setText, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { - const n0 = _createTextNode(_toDisplayString(1) + _toDisplayString(2)) + const n0 = t0() + _setText(n0, _toDisplayString(1) + _toDisplayString(2)) return n0 }" `; @@ -197,7 +199,7 @@ export function render(_ctx) { exports[`compile > expression parsing > interpolation 1`] = ` " - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString(a + b.value))) return n0 " @@ -229,10 +231,12 @@ export function render(_ctx) { `; exports[`compile > static + dynamic root 1`] = ` -"import { createTextNode as _createTextNode, toDisplayString as _toDisplayString } from 'vue'; +"import { toDisplayString as _toDisplayString, setText as _setText, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { - const n0 = _createTextNode(_toDisplayString(1) + _toDisplayString(2) + "3" + _toDisplayString(4) + _toDisplayString(5) + "6" + _toDisplayString(7) + _toDisplayString(8) + "9" + 'A' + 'B') + const n0 = t0() + _setText(n0, _toDisplayString(1) + _toDisplayString(2) + "3" + _toDisplayString(4) + _toDisplayString(5) + "6" + _toDisplayString(7) + _toDisplayString(8) + "9" + 'A' + 'B') return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap index ec449cbd2..518c2a5fe 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/expression.spec.ts.snap @@ -1,30 +1,33 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`compiler: expression > basic 1`] = ` -"import { createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect } from 'vue'; +"import { toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString(_ctx.a))) return n0 }" `; exports[`compiler: expression > props 1`] = ` -"import { createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect } from 'vue'; +"import { toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx, $props, $emit, $attrs, $slots) { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString($props.foo))) return n0 }" `; exports[`compiler: expression > props aliased 1`] = ` -"import { createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect } from 'vue'; +"import { toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx, $props, $emit, $attrs, $slots) { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString($props['bar']))) return n0 }" diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformChildren.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformChildren.spec.ts.snap index 215ab9036..5f0121b5e 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformChildren.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformChildren.spec.ts.snap @@ -1,24 +1,22 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`compiler: children transform > children & sibling references 1`] = ` -"import { child as _child, nthChild as _nthChild, next as _next, createTextNode as _createTextNode, insert as _insert, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue'; -const t0 = _template("

", true) +"import { child as _child, next as _next, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template("

", true) export function render(_ctx) { - const n4 = t0() - const n0 = _child(n4) - const n3 = _nthChild(n4, 2) - const n2 = _next(n3) + const n3 = t0() + const n0 = _child(n3) + const n1 = _next(n0) + const n2 = _next(n1) const x0 = _child(n0) - const n1 = _createTextNode() const x2 = _child(n2) - _insert(n1, n4, n3) _renderEffect(() => { _setText(x0, _toDisplayString(_ctx.first)) - _setText(n1, _toDisplayString(_ctx.second) + " " + _toDisplayString(_ctx.third) + " ") + _setText(n1, " " + _toDisplayString(_ctx.second) + " " + _toDisplayString(_ctx.third) + " ") _setText(x2, _toDisplayString(_ctx.forth)) }) - return n4 + return n3 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformText.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformText.spec.ts.snap index 706b44c9a..f18f85203 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformText.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformText.spec.ts.snap @@ -1,20 +1,23 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`compiler: text transform > consecutive text 1`] = ` -"import { createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect } from 'vue'; +"import { toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString(_ctx.msg))) return n0 }" `; exports[`compiler: text transform > no consecutive text 1`] = ` -"import { createTextNode as _createTextNode } from 'vue'; +"import { setText as _setText, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { - const n0 = _createTextNode("hello world") + const n0 = t0() + _setText(n0, "hello world") return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap index 9cbe1bd0d..d7ec3ceed 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap @@ -12,15 +12,15 @@ export function render(_ctx) { `; exports[`compiler: v-once > basic 1`] = ` -"import { child as _child, createTextNode as _createTextNode, toDisplayString as _toDisplayString, setClass as _setClass, prepend as _prepend, template as _template } from 'vue'; -const t0 = _template("
", true) +"import { child as _child, next as _next, toDisplayString as _toDisplayString, setText as _setText, setClass as _setClass, template as _template } from 'vue'; +const t0 = _template("
", true) export function render(_ctx, $props, $emit, $attrs, $slots) { const n2 = t0() - const n1 = _child(n2) - const n0 = _createTextNode(_toDisplayString(_ctx.msg) + " ") + const n0 = _child(n2) + const n1 = _next(n0) + _setText(n0, _toDisplayString(_ctx.msg) + " ") _setClass(n1, _ctx.clz) - _prepend(n2, n0) return n2 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap index bab5c1046..6649e333b 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap @@ -22,7 +22,8 @@ export function render(_ctx) { `; exports[`compiler: transform slot > dynamic slots name w/ v-for 1`] = ` -"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createForSlots as _createForSlots, createComponentWithFallback as _createComponentWithFallback } from 'vue'; +"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createForSlots as _createForSlots, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") @@ -31,7 +32,7 @@ export function render(_ctx) { () => (_createForSlots(_ctx.list, (item) => ({ name: item, fn: (_slotProps0) => { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["bar"]))) return n0 } @@ -158,7 +159,7 @@ export function render(_ctx) { `; exports[`compiler: transform slot > nested slots scoping 1`] = ` -"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue'; +"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue'; const t0 = _template(" ") export function render(_ctx) { @@ -166,17 +167,16 @@ export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") const n5 = _createComponentWithFallback(_component_Comp, null, { "default": (_slotProps0) => { - const n2 = t0() + const n3 = t0() const n1 = _createComponentWithFallback(_component_Inner, null, { "default": (_slotProps1) => { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _slotProps1["bar"] + _ctx.baz))) return n0 } }) - const n3 = _createTextNode() - _renderEffect(() => _setText(n3, _toDisplayString(_slotProps0["foo"] + _ctx.bar + _ctx.baz))) - return [n1, n2, n3] + _renderEffect(() => _setText(n3, " " + _toDisplayString(_slotProps0["foo"] + _ctx.bar + _ctx.baz))) + return [n1, n3] } }, true) return n5 @@ -184,7 +184,8 @@ export function render(_ctx) { `; exports[`compiler: transform slot > on component dynamically named slot 1`] = ` -"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback } from 'vue'; +"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") @@ -193,7 +194,7 @@ export function render(_ctx) { () => ({ name: _ctx.named, fn: (_slotProps0) => { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _ctx.bar))) return n0 } @@ -205,13 +206,14 @@ export function render(_ctx) { `; exports[`compiler: transform slot > on component named slot 1`] = ` -"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback } from 'vue'; +"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") const n1 = _createComponentWithFallback(_component_Comp, null, { "named": (_slotProps0) => { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _ctx.bar))) return n0 } @@ -221,13 +223,14 @@ export function render(_ctx) { `; exports[`compiler: transform slot > on-component default slot 1`] = ` -"import { resolveComponent as _resolveComponent, createTextNode as _createTextNode, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback } from 'vue'; +"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue'; +const t0 = _template(" ") export function render(_ctx) { const _component_Comp = _resolveComponent("Comp") const n1 = _createComponentWithFallback(_component_Comp, null, { "default": (_slotProps0) => { - const n0 = _createTextNode() + const n0 = t0() _renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _ctx.bar))) return n0 } diff --git a/packages/compiler-vapor/__tests__/transforms/transformChildren.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformChildren.spec.ts index 152911dcd..b94e55535 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformChildren.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformChildren.spec.ts @@ -27,10 +27,11 @@ describe('compiler: children transform', () => { ) expect(code).toMatchSnapshot() expect(Array.from(helpers)).containSubset([ + 'child', + 'toDisplayString', + 'renderEffect', 'next', 'setText', - 'createTextNode', - 'insert', 'template', ]) }) diff --git a/packages/compiler-vapor/__tests__/transforms/transformText.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformText.spec.ts index a668c7625..20fa6d1fd 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformText.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformText.spec.ts @@ -1,4 +1,5 @@ // TODO: add tests for this transform +import { NodeTypes } from '@vue/compiler-dom' import { IRNodeTypes, transformChildren, @@ -24,14 +25,14 @@ describe('compiler: text transform', () => { '{{ "hello world" }}', ) expect(code).toMatchSnapshot() - expect(helpers).contains.all.keys('createTextNode') + expect(helpers).contains.all.keys('setText', 'template') expect(ir.block.operation).toMatchObject([ { - type: IRNodeTypes.CREATE_TEXT_NODE, - id: 0, + type: IRNodeTypes.SET_TEXT, + element: 0, values: [ { - type: IRNodeTypes.SET_TEXT, + type: NodeTypes.SIMPLE_EXPRESSION, content: '"hello world"', isStatic: false, }, @@ -43,14 +44,8 @@ describe('compiler: text transform', () => { it('consecutive text', () => { const { code, ir, helpers } = compileWithTextTransform('{{ msg }}') expect(code).toMatchSnapshot() - expect(helpers).contains.all.keys('createTextNode') - expect(ir.block.operation).toMatchObject([ - { - type: IRNodeTypes.CREATE_TEXT_NODE, - id: 0, - values: undefined, - }, - ]) + expect(helpers).contains.all.keys('setText', 'template') + expect(ir.block.operation).toMatchObject([]) expect(ir.block.effect.length).toBe(1) }) }) diff --git a/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts b/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts index 228350486..a3fb18aa1 100644 --- a/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts @@ -28,8 +28,8 @@ describe('compiler: v-once', () => { expect(ir.block.effect).lengthOf(0) expect(ir.block.operation).toMatchObject([ { - type: IRNodeTypes.CREATE_TEXT_NODE, - id: 0, + type: IRNodeTypes.SET_TEXT, + element: 0, values: [ { type: NodeTypes.SIMPLE_EXPRESSION, @@ -61,11 +61,6 @@ describe('compiler: v-once', () => { ], }, }, - { - type: IRNodeTypes.PREPEND_NODE, - elements: [0], - parent: 2, - }, ]) }) diff --git a/packages/compiler-vapor/src/generators/template.ts b/packages/compiler-vapor/src/generators/template.ts index 0c27a9192..906944479 100644 --- a/packages/compiler-vapor/src/generators/template.ts +++ b/packages/compiler-vapor/src/generators/template.ts @@ -66,11 +66,10 @@ export function genChildren( push(NEWLINE, `const ${variable} = `) if (prev) { - const offset = elementIndex - prev[1] - if (offset === 1) { + if (elementIndex - prev[1] === 1) { push(...genCall(helper('next'), prev[0])) } else { - push(...genCall(helper('nthChild'), from, String(offset))) + push(...genCall(helper('nthChild'), from, String(elementIndex))) } } else { if (newPath.length === 1 && newPath[0] === 0) { diff --git a/packages/compiler-vapor/src/transforms/transformText.ts b/packages/compiler-vapor/src/transforms/transformText.ts index 12f072818..7cdb1b1a7 100644 --- a/packages/compiler-vapor/src/transforms/transformText.ts +++ b/packages/compiler-vapor/src/transforms/transformText.ts @@ -30,32 +30,71 @@ export const transformText: NodeTransform = (node, context) => { return } + const isFragment = + node.type === NodeTypes.ROOT || + (node.type === NodeTypes.ELEMENT && + (node.tagType === ElementTypes.TEMPLATE || + node.tagType === ElementTypes.COMPONENT)) + if ( - node.type === NodeTypes.ELEMENT && - node.tagType === ElementTypes.ELEMENT && - isAllTextLike(node.children) + (isFragment || + (node.type === NodeTypes.ELEMENT && + node.tagType === ElementTypes.ELEMENT)) && + node.children.length ) { - processTextLikeContainer( - node.children, - context as TransformContext, - ) + let hasInterp = false + let isAllTextLike = true + for (const c of node.children) { + if (c.type === NodeTypes.INTERPOLATION) { + hasInterp = true + } else if (c.type !== NodeTypes.TEXT) { + isAllTextLike = false + } + } + // all text like with interpolation + if (!isFragment && isAllTextLike && hasInterp) { + processTextContainer( + node.children as TextLike[], + context as TransformContext, + ) + } else if (hasInterp) { + // check if there's any text before interpolation, it needs to be merged + for (let i = 0; i < node.children.length; i++) { + const c = node.children[i] + const prev = node.children[i - 1] + if ( + c.type === NodeTypes.INTERPOLATION && + prev && + prev.type === NodeTypes.TEXT + ) { + // mark leading text node for skipping + seen.get(context.root)!.add(prev) + } + } + } } else if (node.type === NodeTypes.INTERPOLATION) { - processTextLike(context as TransformContext) + processInterpolation(context as TransformContext) } else if (node.type === NodeTypes.TEXT) { context.template += node.content } } -function processTextLike(context: TransformContext) { - const nexts = context.parent!.node.children.slice(context.index) +function processInterpolation(context: TransformContext) { + const children = context.parent!.node.children + const nexts = children.slice(context.index) const idx = nexts.findIndex(n => !isTextLike(n)) const nodes = (idx > -1 ? nexts.slice(0, idx) : nexts) as Array + // merge leading text + const prev = children[context.index - 1] + if (prev && prev.type === NodeTypes.TEXT) { + nodes.unshift(prev) + } + + context.template += ' ' const id = context.reference() const values = nodes.map(node => createTextLikeExpression(node, context)) - context.dynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE - const nonConstantExps = values.filter(v => !isConstantExpression(v)) const isStatic = !nonConstantExps.length || @@ -64,12 +103,13 @@ function processTextLike(context: TransformContext) { ) || context.inVOnce - context.registerOperation({ - type: IRNodeTypes.CREATE_TEXT_NODE, - id, - values: isStatic ? values : undefined, - }) - if (!isStatic) { + if (isStatic) { + context.registerOperation({ + type: IRNodeTypes.SET_TEXT, + element: id, + values, + }) + } else { context.registerEffect(values, { type: IRNodeTypes.SET_TEXT, element: id, @@ -78,7 +118,7 @@ function processTextLike(context: TransformContext) { } } -function processTextLikeContainer( +function processTextContainer( children: TextLike[], context: TransformContext, ) { @@ -111,15 +151,6 @@ function createTextLikeExpression(node: TextLike, context: TransformContext) { } } -function isAllTextLike(children: TemplateChildNode[]): children is TextLike[] { - return ( - !!children.length && - children.every(isTextLike) && - // at least one an interpolation - children.some(n => n.type === NodeTypes.INTERPOLATION) - ) -} - function isTextLike(node: TemplateChildNode): node is TextLike { return node.type === NodeTypes.INTERPOLATION || node.type === NodeTypes.TEXT } diff --git a/packages/runtime-vapor/src/dom/template.ts b/packages/runtime-vapor/src/dom/template.ts index 8069301d2..dbe833641 100644 --- a/packages/runtime-vapor/src/dom/template.ts +++ b/packages/runtime-vapor/src/dom/template.ts @@ -3,7 +3,7 @@ import { currentHydrationNode, isHydrating, } from './hydration' -import { child } from './node' +import { child, createTextNode } from './node' let t: HTMLTemplateElement @@ -18,6 +18,10 @@ export function template(html: string, root?: boolean) { } return adoptHydrationNode(currentHydrationNode, html)! } + // fast path for text nodes + if (html[0] !== '<') { + return createTextNode(html) + } if (!node) { t = t || document.createElement('template') t.innerHTML = html