From da7adefa844265eecc9c336abfc727bc05b4f16e Mon Sep 17 00:00:00 2001 From: Vadim Kruglov <49036220+quiteeasy@users.noreply.github.com> Date: Mon, 22 Apr 2024 19:46:11 +0700 Subject: [PATCH] fix(compiler-core): handle template ref bound via v-bind object on v-for (#10706) close #10696 --- .../transformElement.spec.ts.snap | 228 ++++++++++++++++++ .../transforms/transformElement.spec.ts | 39 +++ .../__tests__/transforms/vFor.spec.ts | 2 +- .../src/transforms/transformElement.ts | 32 +-- 4 files changed, 285 insertions(+), 16 deletions(-) create mode 100644 packages/compiler-core/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap new file mode 100644 index 00000000000..3da778eb675 --- /dev/null +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap @@ -0,0 +1,228 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`compiler: v-for > codegen > basic v-for 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (item) => { + return (_openBlock(), _createElementBlock("span")) + }), 256 /* UNKEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > keyed template v-for 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (item) => { + return (_openBlock(), _createElementBlock(_Fragment, { key: item }, [ + "hello", + _createElementVNode("span") + ], 64 /* STABLE_FRAGMENT */)) + }), 128 /* KEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > keyed v-for 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (item) => { + return (_openBlock(), _createElementBlock("span", { key: item })) + }), 128 /* KEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > skipped key 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (item, __, index) => { + return (_openBlock(), _createElementBlock("span")) + }), 256 /* UNKEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > skipped value & key 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (_, __, index) => { + return (_openBlock(), _createElementBlock("span")) + }), 256 /* UNKEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > skipped value 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (_, key, index) => { + return (_openBlock(), _createElementBlock("span")) + }), 256 /* UNKEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > template v-for 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (item) => { + return (_openBlock(), _createElementBlock(_Fragment, null, [ + "hello", + _createElementVNode("span") + ], 64 /* STABLE_FRAGMENT */)) + }), 256 /* UNKEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > template v-for key injection with single child 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (item) => { + return (_openBlock(), _createElementBlock("span", { + key: item.id, + id: item.id + }, null, 8 /* PROPS */, ["id"])) + }), 128 /* KEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > template v-for w/ 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, renderSlot: _renderSlot } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (item) => { + return _renderSlot($slots, "default") + }), 256 /* UNKEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > v-for on 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, renderSlot: _renderSlot } = _Vue + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(items, (item) => { + return _renderSlot($slots, "default") + }), 256 /* UNKEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > v-for on element with custom directive 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, resolveDirective: _resolveDirective, withDirectives: _withDirectives } = _Vue + + const _directive_foo = _resolveDirective("foo") + + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (i) => { + return _withDirectives((_openBlock(), _createElementBlock("div", null, null, 512 /* NEED_PATCH */)), [ + [_directive_foo] + ]) + }), 256 /* UNKEYED_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > v-for with constant expression 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, toDisplayString: _toDisplayString, createElementVNode: _createElementVNode } = _Vue + + return (_openBlock(), _createElementBlock(_Fragment, null, _renderList(10, (item) => { + return _createElementVNode("p", null, _toDisplayString(item), 1 /* TEXT */) + }), 64 /* STABLE_FRAGMENT */)) + } +}" +`; + +exports[`compiler: v-for > codegen > v-if + v-for 1`] = ` +"const _Vue = Vue + +return function render(_ctx, _cache) { + with (_ctx) { + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createCommentVNode: _createCommentVNode } = _Vue + + return ok + ? (_openBlock(true), _createElementBlock(_Fragment, { key: 0 }, _renderList(list, (i) => { + return (_openBlock(), _createElementBlock("div")) + }), 256 /* UNKEYED_FRAGMENT */)) + : _createCommentVNode("v-if", true) + } +}" +`; + +exports[`compiler: v-for > codegen > v-if + v-for on