diff --git a/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap index 2bdb4afa4c0..82697ec1f9d 100644 --- a/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap @@ -134,8 +134,8 @@ return function render(_ctx, _cache) { exports[`compiler: codegen > hoists 1`] = ` " -const _hoisted_1 = hello -const _hoisted_2 = { id: "foo" } +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (hello)) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ({ id: "foo" })) return function render(_ctx, _cache) { with (_ctx) { diff --git a/packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap index 445d3fd13ed..0c58a646f9f 100644 --- a/packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap @@ -1,17 +1,17 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`scopeId compiler support > should push scopeId for hoisted nodes 1`] = ` -"import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "vue" +"import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, hoistLazy as _hoistLazy, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "vue" const _withScopeId = n => (_pushScopeId("test"),n=n(),_popScopeId(),n) -const _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "hello", -1 /* HOISTED */)) -const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "world", -1 /* HOISTED */)) +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (_withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "hello", -1 /* HOISTED */)))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => (_withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "world", -1 /* HOISTED */)))) export function render(_ctx, _cache) { return (_openBlock(), _createElementBlock("div", null, [ - _hoisted_1, + _hoisted_1(), _createTextVNode(_toDisplayString(_ctx.foo), 1 /* TEXT */), - _hoisted_2 + _hoisted_2() ])) }" `; diff --git a/packages/compiler-core/__tests__/codegen.spec.ts b/packages/compiler-core/__tests__/codegen.spec.ts index 9c923075634..a4059b39888 100644 --- a/packages/compiler-core/__tests__/codegen.spec.ts +++ b/packages/compiler-core/__tests__/codegen.spec.ts @@ -154,8 +154,12 @@ describe('compiler: codegen', () => { ], }) const { code } = generate(root) - expect(code).toMatch(`const _hoisted_1 = hello`) - expect(code).toMatch(`const _hoisted_2 = { id: "foo" }`) + expect(code).toMatch( + `const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (hello))`, + ) + expect(code).toMatch( + `const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ({ id: "foo" }))`, + ) expect(code).toMatchSnapshot() }) diff --git a/packages/compiler-core/__tests__/scopeId.spec.ts b/packages/compiler-core/__tests__/scopeId.spec.ts index c7a21df7a78..39a3d78a7b3 100644 --- a/packages/compiler-core/__tests__/scopeId.spec.ts +++ b/packages/compiler-core/__tests__/scopeId.spec.ts @@ -72,12 +72,12 @@ describe('scopeId compiler support', () => { expect(ast.hoists.length).toBe(2) ;[ `const _withScopeId = n => (_pushScopeId("test"),n=n(),_popScopeId(),n)`, - `const _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "hello", ${genFlagText( + `const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (_withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "hello", ${genFlagText( PatchFlags.HOISTED, - )}))`, - `const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "world", ${genFlagText( + )})))`, + `const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => (_withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "world", ${genFlagText( PatchFlags.HOISTED, - )}))`, + )})))`, ].forEach(c => expect(code).toMatch(c)) expect(code).toMatchSnapshot() }) diff --git a/packages/compiler-core/__tests__/transform.spec.ts b/packages/compiler-core/__tests__/transform.spec.ts index a56be51bc5c..2ee14b9474b 100644 --- a/packages/compiler-core/__tests__/transform.spec.ts +++ b/packages/compiler-core/__tests__/transform.spec.ts @@ -197,8 +197,8 @@ describe('compiler: transform', () => { nodeTransforms: [mock], }) expect(ast.hoists).toMatchObject(hoisted) - expect((ast as any).children[0].props[0].exp.content).toBe(`_hoisted_1`) - expect((ast as any).children[1].props[0].exp.content).toBe(`_hoisted_2`) + expect((ast as any).children[0].props[0].exp.content).toBe(`_hoisted_1()`) + expect((ast as any).children[1].props[0].exp.content).toBe(`_hoisted_2()`) }) test('context.filename and selfName', () => { diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/hoistStatic.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/hoistStatic.spec.ts.snap index ef3e2b8f4d6..01f2049fa5c 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/hoistStatic.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/hoistStatic.spec.ts.snap @@ -2,115 +2,115 @@ exports[`compiler: hoistStatic transform > hoist element with static key 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", { key: "foo" }, null, -1 /* HOISTED */) -const _hoisted_2 = [ - _hoisted_1 -] +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("div", { key: "foo" }, null, -1 /* HOISTED */))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_1() +])) return function render(_ctx, _cache) { with (_ctx) { - const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue - return (_openBlock(), _createElementBlock("div", null, _hoisted_2)) + return (_openBlock(), _createElementBlock("div", null, _hoisted_2())) } }" `; exports[`compiler: hoistStatic transform > hoist nested static tree 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = /*#__PURE__*/_createElementVNode("p", null, [ +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("p", null, [ /*#__PURE__*/_createElementVNode("span"), /*#__PURE__*/_createElementVNode("span") -], -1 /* HOISTED */) -const _hoisted_2 = [ - _hoisted_1 -] +], -1 /* HOISTED */))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_1() +])) return function render(_ctx, _cache) { with (_ctx) { - const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue - return (_openBlock(), _createElementBlock("div", null, _hoisted_2)) + return (_openBlock(), _createElementBlock("div", null, _hoisted_2())) } }" `; exports[`compiler: hoistStatic transform > hoist nested static tree with comments 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue +const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", null, [ +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("div", null, [ /*#__PURE__*/_createCommentVNode("comment") -], -1 /* HOISTED */) -const _hoisted_2 = [ - _hoisted_1 -] +], -1 /* HOISTED */))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_1() +])) return function render(_ctx, _cache) { with (_ctx) { - const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue - return (_openBlock(), _createElementBlock("div", null, _hoisted_2)) + return (_openBlock(), _createElementBlock("div", null, _hoisted_2())) } }" `; exports[`compiler: hoistStatic transform > hoist siblings with common non-hoistable parent 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */) -const _hoisted_2 = /*#__PURE__*/_createElementVNode("div", null, null, -1 /* HOISTED */) -const _hoisted_3 = [ - _hoisted_1, - _hoisted_2 -] +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("div", null, null, -1 /* HOISTED */))) +const _hoisted_3 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_1(), + _hoisted_2() +])) return function render(_ctx, _cache) { with (_ctx) { - const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue - return (_openBlock(), _createElementBlock("div", null, _hoisted_3)) + return (_openBlock(), _createElementBlock("div", null, _hoisted_3())) } }" `; exports[`compiler: hoistStatic transform > hoist simple element 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", { class: "inline" }, "hello", -1 /* HOISTED */) -const _hoisted_2 = [ - _hoisted_1 -] +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("span", { class: "inline" }, "hello", -1 /* HOISTED */))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_1() +])) return function render(_ctx, _cache) { with (_ctx) { - const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue - return (_openBlock(), _createElementBlock("div", null, _hoisted_2)) + return (_openBlock(), _createElementBlock("div", null, _hoisted_2())) } }" `; exports[`compiler: hoistStatic transform > hoist static props for elements with directives 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = { id: "foo" } +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => ({ id: "foo" })) return function render(_ctx, _cache) { with (_ctx) { - const { resolveDirective: _resolveDirective, createElementVNode: _createElementVNode, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { resolveDirective: _resolveDirective, createElementVNode: _createElementVNode, withDirectives: _withDirectives, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const _directive_foo = _resolveDirective("foo") return (_openBlock(), _createElementBlock("div", null, [ - _withDirectives(_createElementVNode("div", _hoisted_1, null, 512 /* NEED_PATCH */), [ + _withDirectives(_createElementVNode("div", _hoisted_1(), null, 512 /* NEED_PATCH */), [ [_directive_foo] ]) ])) @@ -120,16 +120,16 @@ return function render(_ctx, _cache) { exports[`compiler: hoistStatic transform > hoist static props for elements with dynamic text children 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = { id: "foo" } +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => ({ id: "foo" })) return function render(_ctx, _cache) { with (_ctx) { - const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue return (_openBlock(), _createElementBlock("div", null, [ - _createElementVNode("div", _hoisted_1, _toDisplayString(hello), 1 /* TEXT */) + _createElementVNode("div", _hoisted_1(), _toDisplayString(hello), 1 /* TEXT */) ])) } }" @@ -137,18 +137,18 @@ return function render(_ctx, _cache) { exports[`compiler: hoistStatic transform > hoist static props for elements with unhoistable children 1`] = ` "const _Vue = Vue -const { createVNode: _createVNode, createElementVNode: _createElementVNode } = _Vue +const { createVNode: _createVNode, createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = { id: "foo" } +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => ({ id: "foo" })) return function render(_ctx, _cache) { with (_ctx) { - const { resolveComponent: _resolveComponent, createVNode: _createVNode, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { resolveComponent: _resolveComponent, createVNode: _createVNode, createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue const _component_Comp = _resolveComponent("Comp") return (_openBlock(), _createElementBlock("div", null, [ - _createElementVNode("div", _hoisted_1, [ + _createElementVNode("div", _hoisted_1(), [ _createVNode(_component_Comp) ]) ])) @@ -158,18 +158,18 @@ return function render(_ctx, _cache) { exports[`compiler: hoistStatic transform > prefixIdentifiers > hoist class with static object value 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = { +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => ({ class: /*#__PURE__*/_normalizeClass({ foo: true }) -} +})) return function render(_ctx, _cache) { with (_ctx) { - const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue return (_openBlock(), _createElementBlock("div", null, [ - _createElementVNode("span", _hoisted_1, _toDisplayString(_ctx.bar), 1 /* TEXT */) + _createElementVNode("span", _hoisted_1(), _toDisplayString(_ctx.bar), 1 /* TEXT */) ])) } }" @@ -177,57 +177,57 @@ return function render(_ctx, _cache) { exports[`compiler: hoistStatic transform > prefixIdentifiers > hoist nested static tree with static interpolation 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", null, "foo " + /*#__PURE__*/_toDisplayString(1) + " " + /*#__PURE__*/_toDisplayString(true), -1 /* HOISTED */) -const _hoisted_2 = [ - _hoisted_1 -] +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("span", null, "foo " + /*#__PURE__*/_toDisplayString(1) + " " + /*#__PURE__*/_toDisplayString(true), -1 /* HOISTED */))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_1() +])) return function render(_ctx, _cache) { with (_ctx) { - const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue - return (_openBlock(), _createElementBlock("div", null, _hoisted_2)) + return (_openBlock(), _createElementBlock("div", null, _hoisted_2())) } }" `; exports[`compiler: hoistStatic transform > prefixIdentifiers > hoist nested static tree with static prop value 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", { foo: 0 }, /*#__PURE__*/_toDisplayString(1), -1 /* HOISTED */) -const _hoisted_2 = [ - _hoisted_1 -] +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("span", { foo: 0 }, /*#__PURE__*/_toDisplayString(1), -1 /* HOISTED */))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_1() +])) return function render(_ctx, _cache) { with (_ctx) { - const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue - return (_openBlock(), _createElementBlock("div", null, _hoisted_2)) + return (_openBlock(), _createElementBlock("div", null, _hoisted_2())) } }" `; exports[`compiler: hoistStatic transform > prefixIdentifiers > should NOT hoist SVG with directives 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = /*#__PURE__*/_createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* HOISTED */) -const _hoisted_2 = [ - _hoisted_1 -] +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* HOISTED */))) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_1() +])) return function render(_ctx, _cache) { with (_ctx) { - const { createElementVNode: _createElementVNode, resolveDirective: _resolveDirective, openBlock: _openBlock, createElementBlock: _createElementBlock, withDirectives: _withDirectives } = _Vue + const { createElementVNode: _createElementVNode, resolveDirective: _resolveDirective, openBlock: _openBlock, createElementBlock: _createElementBlock, withDirectives: _withDirectives, hoistLazy: _hoistLazy } = _Vue const _directive_foo = _resolveDirective("foo") return (_openBlock(), _createElementBlock("div", null, [ - _withDirectives((_openBlock(), _createElementBlock("svg", null, _hoisted_2)), [ + _withDirectives((_openBlock(), _createElementBlock("svg", null, _hoisted_2())), [ [_directive_foo] ]) ])) @@ -367,16 +367,16 @@ return function render(_ctx, _cache) { exports[`compiler: hoistStatic transform > should NOT hoist element with dynamic props (but hoist the props list) 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = ["id"] +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => (["id"])) return function render(_ctx, _cache) { with (_ctx) { - const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue + const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue return (_openBlock(), _createElementBlock("div", null, [ - _createElementVNode("div", { id: foo }, null, 8 /* PROPS */, _hoisted_1) + _createElementVNode("div", { id: foo }, null, 8 /* PROPS */, _hoisted_1()) ])) } }" @@ -410,21 +410,21 @@ return function render(_ctx, _cache) { exports[`compiler: hoistStatic transform > should hoist v-for children if static 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode } = _Vue +const { createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = { id: "foo" } -const _hoisted_2 = /*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */) -const _hoisted_3 = [ - _hoisted_2 -] +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => ({ id: "foo" })) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */))) +const _hoisted_3 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_2() +])) return function render(_ctx, _cache) { with (_ctx) { - const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode } = _Vue + const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode, hoistLazy: _hoistLazy } = _Vue return (_openBlock(), _createElementBlock("div", null, [ (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (i) => { - return (_openBlock(), _createElementBlock("div", _hoisted_1, _hoisted_3)) + return (_openBlock(), _createElementBlock("div", _hoisted_1(), _hoisted_3())) }), 256 /* UNKEYED_FRAGMENT */)) ])) } @@ -433,24 +433,24 @@ return function render(_ctx, _cache) { exports[`compiler: hoistStatic transform > should hoist v-if props/children if static 1`] = ` "const _Vue = Vue -const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue +const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode, hoistLazy: _hoistLazy } = _Vue -const _hoisted_1 = { +const _hoisted_1 = /*#__PURE__*/ _hoistLazy(() => ({ key: 0, id: "foo" -} -const _hoisted_2 = /*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */) -const _hoisted_3 = [ - _hoisted_2 -] +})) +const _hoisted_2 = /*#__PURE__*/ _hoistLazy(() => (/*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */))) +const _hoisted_3 = /*#__PURE__*/ _hoistLazy(() => ([ + _hoisted_2() +])) return function render(_ctx, _cache) { with (_ctx) { - const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock, createCommentVNode: _createCommentVNode } = _Vue + const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock, createCommentVNode: _createCommentVNode, hoistLazy: _hoistLazy } = _Vue return (_openBlock(), _createElementBlock("div", null, [ ok - ? (_openBlock(), _createElementBlock("div", _hoisted_1, _hoisted_3)) + ? (_openBlock(), _createElementBlock("div", _hoisted_1(), _hoisted_3())) : _createCommentVNode("v-if", true) ])) } diff --git a/packages/compiler-core/__tests__/transforms/hoistStatic.spec.ts b/packages/compiler-core/__tests__/transforms/hoistStatic.spec.ts index d6c46b52eb3..650a8005cce 100644 --- a/packages/compiler-core/__tests__/transforms/hoistStatic.spec.ts +++ b/packages/compiler-core/__tests__/transforms/hoistStatic.spec.ts @@ -31,7 +31,7 @@ const hoistedChildrenArrayMatcher = (startIndex = 1, length = 1) => ({ type: NodeTypes.ELEMENT, codegenNode: { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_${startIndex + i}`, + content: `_hoisted_${startIndex + i}()`, }, })), }) @@ -91,7 +91,7 @@ describe('compiler: hoistStatic transform', () => { expect(root.codegenNode).toMatchObject({ tag: `"div"`, props: undefined, - children: { content: `_hoisted_2` }, + children: { content: `_hoisted_2()` }, }) expect(generate(root).code).toMatchSnapshot() }) @@ -111,7 +111,7 @@ describe('compiler: hoistStatic transform', () => { hoistedChildrenArrayMatcher(), ]) expect((root.codegenNode as VNodeCall).children).toMatchObject({ - content: '_hoisted_2', + content: '_hoisted_2()', }) expect(generate(root).code).toMatchSnapshot() }) @@ -128,7 +128,7 @@ describe('compiler: hoistStatic transform', () => { hoistedChildrenArrayMatcher(), ]) expect((root.codegenNode as VNodeCall).children).toMatchObject({ - content: `_hoisted_2`, + content: `_hoisted_2()`, }) expect(generate(root).code).toMatchSnapshot() }) @@ -147,7 +147,7 @@ describe('compiler: hoistStatic transform', () => { hoistedChildrenArrayMatcher(1, 2), ]) expect((root.codegenNode as VNodeCall).children).toMatchObject({ - content: '_hoisted_3', + content: '_hoisted_3()', }) expect(generate(root).code).toMatchSnapshot() }) @@ -183,7 +183,7 @@ describe('compiler: hoistStatic transform', () => { patchFlag: genFlagText(PatchFlags.PROPS), dynamicProps: { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_1`, + content: `_hoisted_1()`, isStatic: false, }, }, @@ -206,7 +206,7 @@ describe('compiler: hoistStatic transform', () => { expect(root.codegenNode).toMatchObject({ tag: `"div"`, props: undefined, - children: { content: `_hoisted_2` }, + children: { content: `_hoisted_2()` }, }) expect(generate(root).code).toMatchSnapshot() }) @@ -260,7 +260,7 @@ describe('compiler: hoistStatic transform', () => { tag: `"div"`, props: { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_1`, + content: `_hoisted_1()`, }, children: undefined, patchFlag: genFlagText(PatchFlags.NEED_PATCH), @@ -284,7 +284,7 @@ describe('compiler: hoistStatic transform', () => { codegenNode: { type: NodeTypes.VNODE_CALL, tag: `"div"`, - props: { content: `_hoisted_1` }, + props: { content: `_hoisted_1()` }, children: { type: NodeTypes.INTERPOLATION }, patchFlag: genFlagText(PatchFlags.TEXT), }, @@ -302,7 +302,7 @@ describe('compiler: hoistStatic transform', () => { codegenNode: { type: NodeTypes.VNODE_CALL, tag: `"div"`, - props: { content: `_hoisted_1` }, + props: { content: `_hoisted_1()` }, children: [{ type: NodeTypes.ELEMENT, tag: `Comp` }], }, }, @@ -333,8 +333,8 @@ describe('compiler: hoistStatic transform', () => { // blocks should NOT be hoisted type: NodeTypes.VNODE_CALL, tag: `"div"`, - props: { content: `_hoisted_1` }, - children: { content: `_hoisted_3` }, + props: { content: `_hoisted_1()` }, + children: { content: `_hoisted_3()` }, }, }) expect(generate(root).code).toMatchSnapshot() @@ -371,8 +371,8 @@ describe('compiler: hoistStatic transform', () => { expect(innerBlockCodegen.returns).toMatchObject({ type: NodeTypes.VNODE_CALL, tag: `"div"`, - props: { content: `_hoisted_1` }, - children: { content: `_hoisted_3` }, + props: { content: `_hoisted_1()` }, + children: { content: `_hoisted_3()` }, }) expect(generate(root).code).toMatchSnapshot() }) @@ -401,7 +401,7 @@ describe('compiler: hoistStatic transform', () => { props: undefined, children: { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_2`, + content: `_hoisted_2()`, }, }) expect(generate(root).code).toMatchSnapshot() @@ -436,7 +436,7 @@ describe('compiler: hoistStatic transform', () => { props: undefined, children: { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_2`, + content: `_hoisted_2()`, }, }) expect(generate(root).code).toMatchSnapshot() @@ -486,7 +486,7 @@ describe('compiler: hoistStatic transform', () => { tag: `"span"`, props: { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_1`, + content: `_hoisted_1()`, }, children: { type: NodeTypes.INTERPOLATION, @@ -601,7 +601,7 @@ describe('compiler: hoistStatic transform', () => { expect(root.hoists.length).toBe(2) expect(root.codegenNode).toMatchObject({ children: { - content: '[..._hoisted_2]', + content: '[..._hoisted_2()]', }, }) }) diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index 987293d5124..ef94fb16a4e 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -42,6 +42,7 @@ import { CREATE_STATIC, CREATE_TEXT, CREATE_VNODE, + HOIST_LAZY, OPEN_BLOCK, POP_SCOPE_ID, PUSH_SCOPE_ID, @@ -436,6 +437,7 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) { CREATE_COMMENT, CREATE_TEXT, CREATE_STATIC, + HOIST_LAZY, ] .filter(helper => helpers.includes(helper)) .map(aliasHelper) @@ -585,14 +587,15 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) { if (exp) { const needScopeIdWrapper = genScopeId && exp.type === NodeTypes.VNODE_CALL push( - `const _hoisted_${i + 1} = ${ - needScopeIdWrapper ? `${PURE_ANNOTATION} _withScopeId(() => ` : `` + `const _hoisted_${i + 1} = ${PURE_ANNOTATION} ${helper(HOIST_LAZY)}(() => (${ + needScopeIdWrapper ? `_withScopeId(() => ` : `` }`, ) genNode(exp, context) if (needScopeIdWrapper) { push(`)`) } + push('))') newline() } } diff --git a/packages/compiler-core/src/runtimeHelpers.ts b/packages/compiler-core/src/runtimeHelpers.ts index 47ab73e011a..fe1e6a376c4 100644 --- a/packages/compiler-core/src/runtimeHelpers.ts +++ b/packages/compiler-core/src/runtimeHelpers.ts @@ -9,6 +9,7 @@ export const CREATE_ELEMENT_BLOCK = Symbol(__DEV__ ? `createElementBlock` : ``) export const CREATE_VNODE = Symbol(__DEV__ ? `createVNode` : ``) export const CREATE_ELEMENT_VNODE = Symbol(__DEV__ ? `createElementVNode` : ``) export const CREATE_COMMENT = Symbol(__DEV__ ? `createCommentVNode` : ``) +export const HOIST_LAZY = Symbol(__DEV__ ? `hoistLazy` : ``) export const CREATE_TEXT = Symbol(__DEV__ ? `createTextVNode` : ``) export const CREATE_STATIC = Symbol(__DEV__ ? `createStaticVNode` : ``) export const RESOLVE_COMPONENT = Symbol(__DEV__ ? `resolveComponent` : ``) @@ -79,6 +80,7 @@ export const helperNameMap: Record = { [POP_SCOPE_ID]: `popScopeId`, [WITH_CTX]: `withCtx`, [UNREF]: `unref`, + [HOIST_LAZY]: `hoistLazy`, [IS_REF]: `isRef`, [WITH_MEMO]: `withMemo`, [IS_MEMO_SAME]: `isMemoSame`, diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts index 69821f7f879..401ff786594 100644 --- a/packages/compiler-core/src/transform.ts +++ b/packages/compiler-core/src/transform.ts @@ -34,6 +34,7 @@ import { defaultOnError, defaultOnWarn } from './errors' import { CREATE_COMMENT, FRAGMENT, + HOIST_LAZY, TO_DISPLAY_STRING, helperNameMap, } from './runtimeHelpers' @@ -285,10 +286,11 @@ export function createTransformContext( } }, hoist(exp) { + context.helper(HOIST_LAZY) if (isString(exp)) exp = createSimpleExpression(exp) context.hoists.push(exp) const identifier = createSimpleExpression( - `_hoisted_${context.hoists.length}`, + `_hoisted_${context.hoists.length}()`, false, exp.loc, ConstantTypes.CAN_HOIST, diff --git a/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap b/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap index 57d880a03f6..e813d2c435a 100644 --- a/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap +++ b/packages/compiler-dom/__tests__/transforms/__snapshots__/stringifyStatic.spec.ts.snap @@ -1,96 +1,96 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`stringify static html > should bail for