diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap index eb69bb359..f70e66d95 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap @@ -120,7 +120,7 @@ export function render(_ctx) { `; exports[`compile > directives > v-pre > should not affect siblings after it 1`] = ` -"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createTextNode as _createTextNode, insert as _insert, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor'; +"import { resolveComponent as _resolveComponent, createComponent as _createComponent, createTextNode as _createTextNode, insert as _insert, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor'; const t0 = _template("
{{ bar }}
") const t1 = _template("
") @@ -129,20 +129,18 @@ export function render(_ctx) { const n0 = t0() const n3 = t1() const n1 = _createComponent(_component_Comp) - const n2 = _createTextNode() + const n2 = _createTextNode(() => [_ctx.bar]) _insert([n1, n2], n3) - _renderEffect(() => _setText(n2, _ctx.bar)) _renderEffect(() => _setDynamicProp(n3, "id", _ctx.foo)) return [n0, n3] }" `; exports[`compile > dynamic root 1`] = ` -"import { createTextNode as _createTextNode, setText as _setText } from 'vue/vapor'; +"import { createTextNode as _createTextNode } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createTextNode() - _setText(n0, 1, 2) + const n0 = _createTextNode([1, 2]) return n0 }" `; @@ -163,8 +161,7 @@ export function render(_ctx) { exports[`compile > expression parsing > interpolation 1`] = ` "(() => { - const n0 = _createTextNode() - _renderEffect(() => _setText(n0, a + b.value)) + const n0 = _createTextNode(() => [a + b.value]) return n0 })()" `; @@ -192,11 +189,10 @@ export function render(_ctx) { `; exports[`compile > static + dynamic root 1`] = ` -"import { createTextNode as _createTextNode, setText as _setText } from 'vue/vapor'; +"import { createTextNode as _createTextNode } from 'vue/vapor'; export function render(_ctx) { - const n0 = _createTextNode() - _setText(n0, 1, 2, "3", 4, 5, "6", 7, 8, "9", 'A', 'B') + const n0 = _createTextNode([1, 2, "3", 4, 5, "6", 7, 8, "9", 'A', 'B']) 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 188aecb11..ea009cd8e 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformChildren.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformChildren.spec.ts.snap @@ -10,8 +10,7 @@ export function render(_ctx) { const n3 = _next(n0, 2) const n2 = n3.nextSibling _setText(n0, 'first') - const n1 = _createTextNode() - _setText(n1, 'second', " ", 'third', " ") + const n1 = _createTextNode(['second', " ", 'third', " "]) _setText(n2, 'forth') _insert(n1, n4, n3) return n4 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 7a1004f2d..859406fff 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap @@ -12,14 +12,13 @@ export function render(_ctx) { `; exports[`compiler: v-once > basic 1`] = ` -"import { createTextNode as _createTextNode, setText as _setText, setClass as _setClass, prepend as _prepend, template as _template } from 'vue/vapor'; +"import { createTextNode as _createTextNode, setClass as _setClass, prepend as _prepend, template as _template } from 'vue/vapor'; const t0 = _template("
") export function render(_ctx) { const n2 = t0() const n1 = n2.firstChild - const n0 = _createTextNode() - _setText(n0, _ctx.msg, " ") + const n0 = _createTextNode([_ctx.msg, " "]) _setClass(n1, _ctx.clz) _prepend(n2, n0) return n2 diff --git a/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts b/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts index 6f34e6fe1..5b72445c1 100644 --- a/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts @@ -31,10 +31,6 @@ describe('compiler: v-once', () => { { type: IRNodeTypes.CREATE_TEXT_NODE, id: 0, - }, - { - element: 0, - type: IRNodeTypes.SET_TEXT, values: [ { type: NodeTypes.SIMPLE_EXPRESSION, @@ -47,6 +43,7 @@ describe('compiler: v-once', () => { isStatic: true, }, ], + effect: false, }, { element: 1, diff --git a/packages/compiler-vapor/src/generators/text.ts b/packages/compiler-vapor/src/generators/text.ts index 5d032f74f..75894be10 100644 --- a/packages/compiler-vapor/src/generators/text.ts +++ b/packages/compiler-vapor/src/generators/text.ts @@ -1,19 +1,19 @@ import type { CodegenContext } from '../generate' import type { CreateTextNodeIRNode, SetTextIRNode } from '../ir' import { genExpression } from './expression' -import { type CodeFragment, NEWLINE, genCall } from './utils' +import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils' export function genSetText( oper: SetTextIRNode, context: CodegenContext, ): CodeFragment[] { const { vaporHelper } = context - const { values } = oper + const { element, values } = oper return [ NEWLINE, ...genCall( vaporHelper('setText'), - `n${oper.element}`, + `n${element}`, ...values.map(value => genExpression(value, context)), ), ] @@ -24,9 +24,16 @@ export function genCreateTextNode( context: CodegenContext, ): CodeFragment[] { const { vaporHelper } = context + const { id, values, effect } = oper return [ NEWLINE, - `const n${oper.id} = `, - ...genCall(vaporHelper('createTextNode')), + `const n${id} = `, + ...genCall(vaporHelper('createTextNode'), [ + effect && '() => ', + ...genMulti( + ['[', ']', ', '], + ...values.map(value => genExpression(value, context)), + ), + ]), ] } diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir.ts index e3f0284f2..40ccf3bf1 100644 --- a/packages/compiler-vapor/src/ir.ts +++ b/packages/compiler-vapor/src/ir.ts @@ -159,6 +159,8 @@ export interface SetModelValueIRNode extends BaseIRNode { export interface CreateTextNodeIRNode extends BaseIRNode { type: IRNodeTypes.CREATE_TEXT_NODE id: number + values: SimpleExpressionNode[] + effect: boolean } export interface InsertNodeIRNode extends BaseIRNode { diff --git a/packages/compiler-vapor/src/transforms/transformText.ts b/packages/compiler-vapor/src/transforms/transformText.ts index d44c9886e..96d1b6b80 100644 --- a/packages/compiler-vapor/src/transforms/transformText.ts +++ b/packages/compiler-vapor/src/transforms/transformText.ts @@ -11,6 +11,7 @@ import { } from '@vue/compiler-dom' import type { NodeTransform, TransformContext } from '../transform' import { DynamicFlag, IRNodeTypes } from '../ir' +import { isConstantExpression } from '../utils' type TextLike = TextNode | InterpolationNode const seen = new WeakMap< @@ -50,17 +51,13 @@ function processTextLike(context: TransformContext) { const values = nodes.map(node => createTextLikeExpression(node, context)) context.dynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE + context.registerOperation({ type: IRNodeTypes.CREATE_TEXT_NODE, id, + values, + effect: !values.some(isConstantExpression), }) - context.registerEffect(values, [ - { - type: IRNodeTypes.SET_TEXT, - element: id, - values, - }, - ]) } function processTextLikeContainer( diff --git a/packages/runtime-vapor/src/dom/element.ts b/packages/runtime-vapor/src/dom/element.ts index d7e450871..dc98b18c0 100644 --- a/packages/runtime-vapor/src/dom/element.ts +++ b/packages/runtime-vapor/src/dom/element.ts @@ -1,6 +1,8 @@ -import { isArray, toDisplayString } from '@vue/shared' +import { isArray } from '@vue/shared' import type { Block } from '../apiRender' import { componentKey } from '../component' +import { renderEffect } from '../renderEffect' +import { setText } from './prop' /*! #__NO_SIDE_EFFECTS__ */ export function normalizeBlock(block: Block): Node[] { @@ -34,10 +36,16 @@ export function remove(block: Block, parent: ParentNode) { normalizeBlock(block).forEach(node => parent.removeChild(node)) } -/*! #__NO_SIDE_EFFECTS__ */ -export function createTextNode(val?: unknown): Text { +export function createTextNode(values?: any[] | (() => any[])): Text { // eslint-disable-next-line no-restricted-globals - return document.createTextNode(val === undefined ? '' : toDisplayString(val)) + const node = document.createTextNode('') + if (values) + if (isArray(values)) { + setText(node, ...values) + } else { + renderEffect(() => setText(node, ...values())) + } + return node } /*! #__NO_SIDE_EFFECTS__ */