Skip to content

Commit c5e7d8b

Browse files
committed
fix(compiler-core): hoist pure annotations should apply to all nested calls
1 parent cad25d9 commit c5e7d8b

File tree

4 files changed

+56
-46
lines changed

4 files changed

+56
-46
lines changed

packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap

+12-12
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
exports[`scopeId compiler support should push scopeId for hoisted nodes 1`] = `
44
"import { createVNode as _createVNode, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \\"vue\\"
5-
const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
5+
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
66
77
_pushScopeId(\\"test\\")
8-
const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"div\\", null, \\"hello\\", -1 /* HOISTED */)
9-
const _hoisted_2 = /*#__PURE__*/ _createVNode(\\"div\\", null, \\"world\\", -1 /* HOISTED */)
8+
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"hello\\", -1 /* HOISTED */)
9+
const _hoisted_2 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"world\\", -1 /* HOISTED */)
1010
_popScopeId()
1111
12-
export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
12+
export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
1313
return (_openBlock(), _createBlock(\\"div\\", null, [
1414
_hoisted_1,
1515
_createTextVNode(_toDisplayString(_ctx.foo), 1 /* TEXT */),
@@ -20,9 +20,9 @@ export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
2020

2121
exports[`scopeId compiler support should wrap default slot 1`] = `
2222
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
23-
const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
23+
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
2424
25-
export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
25+
export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
2626
const _component_Child = _resolveComponent(\\"Child\\")
2727
2828
return (_openBlock(), _createBlock(_component_Child, null, {
@@ -36,9 +36,9 @@ export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
3636

3737
exports[`scopeId compiler support should wrap dynamic slots 1`] = `
3838
"import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, renderList as _renderList, createSlots as _createSlots, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
39-
const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
39+
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
4040
41-
export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
41+
export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
4242
const _component_Child = _resolveComponent(\\"Child\\")
4343
4444
return (_openBlock(), _createBlock(_component_Child, null, _createSlots({ _: 1 }, [
@@ -64,9 +64,9 @@ export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
6464

6565
exports[`scopeId compiler support should wrap named slots 1`] = `
6666
"import { toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
67-
const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
67+
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
6868
69-
export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
69+
export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
7070
const _component_Child = _resolveComponent(\\"Child\\")
7171
7272
return (_openBlock(), _createBlock(_component_Child, null, {
@@ -83,9 +83,9 @@ export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
8383

8484
exports[`scopeId compiler support should wrap render function 1`] = `
8585
"import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
86-
const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
86+
const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
8787
88-
export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
88+
export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
8989
return (_openBlock(), _createBlock(\\"div\\"))
9090
})"
9191
`;

packages/compiler-core/__tests__/scopeId.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ describe('scopeId compiler support', () => {
2020
scopeId: 'test'
2121
})
2222
expect(ast.helpers).toContain(WITH_SCOPE_ID)
23-
expect(code).toMatch(`const _withId = /*#__PURE__*/ _withScopeId("test")`)
23+
expect(code).toMatch(`const _withId = /*#__PURE__*/_withScopeId("test")`)
2424
expect(code).toMatch(
25-
`export const render = /*#__PURE__*/ _withId(function render(`
25+
`export const render = /*#__PURE__*/_withId(function render(`
2626
)
2727
expect(code).toMatchSnapshot()
2828
})
@@ -85,10 +85,10 @@ describe('scopeId compiler support', () => {
8585
expect(code).toMatch(
8686
[
8787
`_pushScopeId("test")`,
88-
`const _hoisted_1 = /*#__PURE__*/ _createVNode("div", null, "hello", ${genFlagText(
88+
`const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "hello", ${genFlagText(
8989
PatchFlags.HOISTED
9090
)})`,
91-
`const _hoisted_2 = /*#__PURE__*/ _createVNode("div", null, "world", ${genFlagText(
91+
`const _hoisted_2 = /*#__PURE__*/_createVNode("div", null, "world", ${genFlagText(
9292
PatchFlags.HOISTED
9393
)})`,
9494
`_popScopeId()`

packages/compiler-core/__tests__/transforms/__snapshots__/hoistStatic.spec.ts.snap

+13-13
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ exports[`compiler: hoistStatic transform hoist element with static key 1`] = `
44
"const _Vue = Vue
55
const { createVNode: _createVNode } = _Vue
66
7-
const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"div\\", { key: \\"foo\\" }, null, -1 /* HOISTED */)
7+
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", { key: \\"foo\\" }, null, -1 /* HOISTED */)
88
99
return function render(_ctx, _cache) {
1010
with (_ctx) {
@@ -21,9 +21,9 @@ exports[`compiler: hoistStatic transform hoist nested static tree 1`] = `
2121
"const _Vue = Vue
2222
const { createVNode: _createVNode } = _Vue
2323
24-
const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"p\\", null, [
25-
_createVNode(\\"span\\"),
26-
_createVNode(\\"span\\")
24+
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"p\\", null, [
25+
/*#__PURE__*/_createVNode(\\"span\\"),
26+
/*#__PURE__*/_createVNode(\\"span\\")
2727
], -1 /* HOISTED */)
2828
2929
return function render(_ctx, _cache) {
@@ -41,8 +41,8 @@ exports[`compiler: hoistStatic transform hoist nested static tree with comments
4141
"const _Vue = Vue
4242
const { createVNode: _createVNode, createCommentVNode: _createCommentVNode } = _Vue
4343
44-
const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"div\\", null, [
45-
_createCommentVNode(\\"comment\\")
44+
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", null, [
45+
/*#__PURE__*/_createCommentVNode(\\"comment\\")
4646
], -1 /* HOISTED */)
4747
4848
return function render(_ctx, _cache) {
@@ -60,8 +60,8 @@ exports[`compiler: hoistStatic transform hoist siblings with common non-hoistabl
6060
"const _Vue = Vue
6161
const { createVNode: _createVNode } = _Vue
6262
63-
const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"span\\", null, null, -1 /* HOISTED */)
64-
const _hoisted_2 = /*#__PURE__*/ _createVNode(\\"div\\", null, null, -1 /* HOISTED */)
63+
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"span\\", null, null, -1 /* HOISTED */)
64+
const _hoisted_2 = /*#__PURE__*/_createVNode(\\"div\\", null, null, -1 /* HOISTED */)
6565
6666
return function render(_ctx, _cache) {
6767
with (_ctx) {
@@ -79,7 +79,7 @@ exports[`compiler: hoistStatic transform hoist simple element 1`] = `
7979
"const _Vue = Vue
8080
const { createVNode: _createVNode } = _Vue
8181
82-
const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"span\\", { class: \\"inline\\" }, \\"hello\\", -1 /* HOISTED */)
82+
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"span\\", { class: \\"inline\\" }, \\"hello\\", -1 /* HOISTED */)
8383
8484
return function render(_ctx, _cache) {
8585
with (_ctx) {
@@ -172,7 +172,7 @@ exports[`compiler: hoistStatic transform prefixIdentifiers hoist nested static t
172172
"const _Vue = Vue
173173
const { createVNode: _createVNode } = _Vue
174174
175-
const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"span\\", null, \\"foo \\" + _toDisplayString(1) + \\" \\" + _toDisplayString(true), -1 /* HOISTED */)
175+
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"span\\", null, \\"foo \\" + /*#__PURE__*/_toDisplayString(1) + \\" \\" + /*#__PURE__*/_toDisplayString(true), -1 /* HOISTED */)
176176
177177
return function render(_ctx, _cache) {
178178
with (_ctx) {
@@ -189,7 +189,7 @@ exports[`compiler: hoistStatic transform prefixIdentifiers hoist nested static t
189189
"const _Vue = Vue
190190
const { createVNode: _createVNode } = _Vue
191191
192-
const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"span\\", { foo: 0 }, _toDisplayString(1), -1 /* HOISTED */)
192+
const _hoisted_1 = /*#__PURE__*/_createVNode(\\"span\\", { foo: 0 }, /*#__PURE__*/_toDisplayString(1), -1 /* HOISTED */)
193193
194194
return function render(_ctx, _cache) {
195195
with (_ctx) {
@@ -346,7 +346,7 @@ exports[`compiler: hoistStatic transform should hoist v-for children if static 1
346346
const { createVNode: _createVNode } = _Vue
347347
348348
const _hoisted_1 = { id: \\"foo\\" }
349-
const _hoisted_2 = /*#__PURE__*/ _createVNode(\\"span\\", null, null, -1 /* HOISTED */)
349+
const _hoisted_2 = /*#__PURE__*/_createVNode(\\"span\\", null, null, -1 /* HOISTED */)
350350
351351
return function render(_ctx, _cache) {
352352
with (_ctx) {
@@ -371,7 +371,7 @@ const _hoisted_1 = {
371371
key: 0,
372372
id: \\"foo\\"
373373
}
374-
const _hoisted_2 = /*#__PURE__*/ _createVNode(\\"span\\", null, null, -1 /* HOISTED */)
374+
const _hoisted_2 = /*#__PURE__*/_createVNode(\\"span\\", null, null, -1 /* HOISTED */)
375375
376376
return function render(_ctx, _cache) {
377377
with (_ctx) {

packages/compiler-core/src/codegen.ts

+27-17
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ import {
5454
} from './runtimeHelpers'
5555
import { ImportItem } from './transform'
5656

57+
const PURE_ANNOTATION = `/*#__PURE__*/`
58+
5759
type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
5860

5961
export interface CodegenResult {
@@ -69,6 +71,7 @@ export interface CodegenContext extends Required<CodegenOptions> {
6971
column: number
7072
offset: number
7173
indentLevel: number
74+
pure: boolean
7275
map?: SourceMapGenerator
7376
helper(key: symbol): string
7477
push(code: string, node?: CodegenNode): void
@@ -107,6 +110,7 @@ function createCodegenContext(
107110
line: 1,
108111
offset: 0,
109112
indentLevel: 0,
113+
pure: false,
110114
map: undefined,
111115
helper(key) {
112116
return `_${helperNameMap[key]}`
@@ -201,7 +205,7 @@ export function generate(
201205

202206
// enter render function
203207
if (genScopeId && !ssr) {
204-
push(`const render = /*#__PURE__*/ _withId(`)
208+
push(`const render = ${PURE_ANNOTATION}_withId(`)
205209
}
206210
if (!ssr) {
207211
push(`function render(_ctx, _cache) {`)
@@ -400,7 +404,9 @@ function genModulePreamble(
400404
}
401405

402406
if (genScopeId) {
403-
push(`const _withId = /*#__PURE__*/ ${helper(WITH_SCOPE_ID)}("${scopeId}")`)
407+
push(
408+
`const _withId = ${PURE_ANNOTATION}${helper(WITH_SCOPE_ID)}("${scopeId}")`
409+
)
404410
newline()
405411
}
406412

@@ -432,6 +438,7 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
432438
if (!hoists.length) {
433439
return
434440
}
441+
context.pure = true
435442
const { push, newline, helper, scopeId, mode } = context
436443
const genScopeId = !__BROWSER__ && scopeId != null && mode !== 'function'
437444
newline()
@@ -445,13 +452,6 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
445452

446453
hoists.forEach((exp, i) => {
447454
push(`const _hoisted_${i + 1} = `)
448-
// make hosit function calls tree-shakable
449-
if (
450-
exp.type === NodeTypes.VNODE_CALL ||
451-
exp.type === NodeTypes.JS_CALL_EXPRESSION
452-
) {
453-
push(`/*#__PURE__*/ `)
454-
}
455455
genNode(exp, context)
456456
newline()
457457
})
@@ -460,6 +460,7 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
460460
push(`${helper(POP_SCOPE_ID)}()`)
461461
newline()
462462
}
463+
context.pure = false
463464
}
464465

465466
function genImports(importsOptions: ImportItem[], context: CodegenContext) {
@@ -634,7 +635,8 @@ function genExpression(node: SimpleExpressionNode, context: CodegenContext) {
634635
}
635636

636637
function genInterpolation(node: InterpolationNode, context: CodegenContext) {
637-
const { push, helper } = context
638+
const { push, helper, pure } = context
639+
if (pure) push(PURE_ANNOTATION)
638640
push(`${helper(TO_DISPLAY_STRING)}(`)
639641
genNode(node.content, context)
640642
push(`)`)
@@ -676,13 +678,16 @@ function genExpressionAsPropertyKey(
676678

677679
function genComment(node: CommentNode, context: CodegenContext) {
678680
if (__DEV__) {
679-
const { push, helper } = context
681+
const { push, helper, pure } = context
682+
if (pure) {
683+
push(PURE_ANNOTATION)
684+
}
680685
push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node)
681686
}
682687
}
683688

684689
function genVNodeCall(node: VNodeCall, context: CodegenContext) {
685-
const { push, helper } = context
690+
const { push, helper, pure } = context
686691
const {
687692
tag,
688693
props,
@@ -699,6 +704,9 @@ function genVNodeCall(node: VNodeCall, context: CodegenContext) {
699704
if (isBlock) {
700705
push(`(${helper(OPEN_BLOCK)}(${isForBlock ? `true` : ``}), `)
701706
}
707+
if (pure) {
708+
push(PURE_ANNOTATION)
709+
}
702710
push(helper(isBlock ? CREATE_BLOCK : CREATE_VNODE) + `(`, node)
703711
genNodeList(
704712
genNullableArgs([tag, props, children, patchFlag, dynamicProps]),
@@ -725,12 +733,14 @@ function genNullableArgs(args: any[]): CallExpression['arguments'] {
725733

726734
// JavaScript
727735
function genCallExpression(node: CallExpression, context: CodegenContext) {
728-
const callee = isString(node.callee)
729-
? node.callee
730-
: context.helper(node.callee)
731-
context.push(callee + `(`, node)
736+
const { push, helper, pure } = context
737+
const callee = isString(node.callee) ? node.callee : helper(node.callee)
738+
if (pure) {
739+
push(PURE_ANNOTATION)
740+
}
741+
push(callee + `(`, node)
732742
genNodeList(node.arguments, context)
733-
context.push(`)`)
743+
push(`)`)
734744
}
735745

736746
function genObjectExpression(node: ObjectExpression, context: CodegenContext) {

0 commit comments

Comments
 (0)