`;
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("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
-const t1 = _template("<div></div>")
+const t1 = _template("<div> </div>")
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)
`;
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
}"
`;
exports[`compile > expression parsing > interpolation 1`] = `
"
- const n0 = _createTextNode()
+ const n0 = t0()
_renderEffect(() => _setText(n0, _toDisplayString(a + b.value)))
return n0
"
`;
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
}"
`;
// 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
}"
// 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("<div><p> </p> <!><p> </p></div>", 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("<div><p> </p> <p> </p></div>", 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
}"
`;
// 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
}"
`;
`;
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("<div><span></span></div>", 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("<div> <span></span></div>", 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
}"
`;
`;
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")
() => (_createForSlots(_ctx.list, (item) => ({
name: item,
fn: (_slotProps0) => {
- const n0 = _createTextNode()
+ const n0 = t0()
_renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["bar"])))
return n0
}
`;
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) {
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
`;
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")
() => ({
name: _ctx.named,
fn: (_slotProps0) => {
- const n0 = _createTextNode()
+ const n0 = t0()
_renderEffect(() => _setText(n0, _toDisplayString(_slotProps0["foo"] + _ctx.bar)))
return n0
}
`;
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
}
`;
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
}
)
expect(code).toMatchSnapshot()
expect(Array.from(helpers)).containSubset([
+ 'child',
+ 'toDisplayString',
+ 'renderEffect',
'next',
'setText',
- 'createTextNode',
- 'insert',
'template',
])
})
// TODO: add tests for this transform
+import { NodeTypes } from '@vue/compiler-dom'
import {
IRNodeTypes,
transformChildren,
'{{ "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,
},
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)
})
})
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,
],
},
},
- {
- type: IRNodeTypes.PREPEND_NODE,
- elements: [0],
- parent: 2,
- },
])
})
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) {
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<ElementNode>,
- )
+ 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<ElementNode>,
+ )
+ } 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<InterpolationNode>)
+ processInterpolation(context as TransformContext<InterpolationNode>)
} else if (node.type === NodeTypes.TEXT) {
context.template += node.content
}
}
-function processTextLike(context: TransformContext<InterpolationNode>) {
- const nexts = context.parent!.node.children.slice(context.index)
+function processInterpolation(context: TransformContext<InterpolationNode>) {
+ 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<TextLike>
+ // 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 ||
) ||
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,
}
}
-function processTextLikeContainer(
+function processTextContainer(
children: TextLike[],
context: TransformContext<ElementNode>,
) {
}
}
-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
}
currentHydrationNode,
isHydrating,
} from './hydration'
-import { child } from './node'
+import { child, createTextNode } from './node'
let t: HTMLTemplateElement
}
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