From ad6401343c3da8a882deea05ec5ea9d46876f7f2 Mon Sep 17 00:00:00 2001 From: Vadim Kruglov Date: Mon, 15 Apr 2024 23:53:53 +0700 Subject: [PATCH 1/4] fix(compiler-core): Refs inside v-for are not applied through v-bind --- packages/compiler-core/src/transforms/transformElement.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index ca6e59df32b..b104dbe320e 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -615,6 +615,14 @@ export function buildProps( hasDynamicKeys = true if (exp) { if (isVBind) { + // if in v-bind object will have a ref we should set ref_for to true + // otherwise the ref will be set to a random element in the list + if (context.scopes.vFor > 0) properties.push( + createObjectProperty( + createSimpleExpression('ref_for', true), + createSimpleExpression('true'), + ), + ) // have to merge early for compat build check pushMergeArg() if (__COMPAT__) { From 91043002e2bfbdffcb14fd0fe0115c254863ca05 Mon Sep 17 00:00:00 2001 From: Vadim Kruglov Date: Thu, 18 Apr 2024 14:17:14 +0700 Subject: [PATCH 2/4] refactor(compiler-core): add in buildProps an auxiliary variable hasVFor --- packages/compiler-core/src/transforms/transformElement.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index b104dbe320e..d497876076c 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -411,6 +411,7 @@ export function buildProps( const mergeArgs: PropsExpression[] = [] const runtimeDirectives: DirectiveNode[] = [] const hasChildren = children.length > 0 + const hasVFor = context.scopes.vFor > 0 let shouldUseBlock = false // patchFlag analysis @@ -502,7 +503,7 @@ export function buildProps( let isStatic = true if (name === 'ref') { hasRef = true - if (context.scopes.vFor > 0) { + if (hasVFor) { properties.push( createObjectProperty( createSimpleExpression('ref_for', true), @@ -601,7 +602,7 @@ export function buildProps( shouldUseBlock = true } - if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) { + if (isVBind && isStaticArgOf(arg, 'ref') && hasVFor) { properties.push( createObjectProperty( createSimpleExpression('ref_for', true), @@ -617,7 +618,7 @@ export function buildProps( if (isVBind) { // if in v-bind object will have a ref we should set ref_for to true // otherwise the ref will be set to a random element in the list - if (context.scopes.vFor > 0) properties.push( + if (hasVFor) properties.push( createObjectProperty( createSimpleExpression('ref_for', true), createSimpleExpression('true'), From 88a4a30a430e2158641266de4fa850634073eb68 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 07:54:05 +0000 Subject: [PATCH 3/4] [autofix.ci] apply automated fixes --- .../src/transforms/transformElement.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index d497876076c..5882b5bf314 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -618,12 +618,13 @@ export function buildProps( if (isVBind) { // if in v-bind object will have a ref we should set ref_for to true // otherwise the ref will be set to a random element in the list - if (hasVFor) properties.push( - createObjectProperty( - createSimpleExpression('ref_for', true), - createSimpleExpression('true'), - ), - ) + if (hasVFor) + properties.push( + createObjectProperty( + createSimpleExpression('ref_for', true), + createSimpleExpression('true'), + ), + ) // have to merge early for compat build check pushMergeArg() if (__COMPAT__) { From 5cce191294288883bb596dde1ab576b2d81a646c Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 22 Apr 2024 20:39:58 +0800 Subject: [PATCH 4/4] refactor: extract pushRefVForMarker + tests --- .../transformElement.spec.ts.snap | 228 ++++++++++++++++++ .../transforms/transformElement.spec.ts | 39 +++ .../__tests__/transforms/vFor.spec.ts | 2 +- .../src/transforms/transformElement.ts | 42 ++-- 4 files changed, 285 insertions(+), 26 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