]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-core): hoist pure annotations should apply to all nested calls
authorEvan You <yyx990803@gmail.com>
Fri, 1 May 2020 22:36:34 +0000 (18:36 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 1 May 2020 22:36:34 +0000 (18:36 -0400)
packages/compiler-core/__tests__/__snapshots__/scopeId.spec.ts.snap
packages/compiler-core/__tests__/scopeId.spec.ts
packages/compiler-core/__tests__/transforms/__snapshots__/hoistStatic.spec.ts.snap
packages/compiler-core/src/codegen.ts

index 3f9efc6e0fc8835394c49a1453a63d0abd07accf..ba004bb40641397ceb55bcf748f3fda1c3ce022a 100644 (file)
@@ -2,14 +2,14 @@
 
 exports[`scopeId compiler support should push scopeId for hoisted nodes 1`] = `
 "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\\"
-const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
+const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
 
 _pushScopeId(\\"test\\")
-const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"div\\", null, \\"hello\\", -1 /* HOISTED */)
-const _hoisted_2 = /*#__PURE__*/ _createVNode(\\"div\\", null, \\"world\\", -1 /* HOISTED */)
+const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"hello\\", -1 /* HOISTED */)
+const _hoisted_2 = /*#__PURE__*/_createVNode(\\"div\\", null, \\"world\\", -1 /* HOISTED */)
 _popScopeId()
 
-export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
   return (_openBlock(), _createBlock(\\"div\\", null, [
     _hoisted_1,
     _createTextVNode(_toDisplayString(_ctx.foo), 1 /* TEXT */),
@@ -20,9 +20,9 @@ export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
 
 exports[`scopeId compiler support should wrap default slot 1`] = `
 "import { createVNode as _createVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
-const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
+const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
 
-export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
   const _component_Child = _resolveComponent(\\"Child\\")
 
   return (_openBlock(), _createBlock(_component_Child, null, {
@@ -36,9 +36,9 @@ export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
 
 exports[`scopeId compiler support should wrap dynamic slots 1`] = `
 "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\\"
-const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
+const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
 
-export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
   const _component_Child = _resolveComponent(\\"Child\\")
 
   return (_openBlock(), _createBlock(_component_Child, null, _createSlots({ _: 1 }, [
@@ -64,9 +64,9 @@ export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
 
 exports[`scopeId compiler support should wrap named slots 1`] = `
 "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\\"
-const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
+const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
 
-export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
   const _component_Child = _resolveComponent(\\"Child\\")
 
   return (_openBlock(), _createBlock(_component_Child, null, {
@@ -83,9 +83,9 @@ export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
 
 exports[`scopeId compiler support should wrap render function 1`] = `
 "import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId } from \\"vue\\"
-const _withId = /*#__PURE__*/ _withScopeId(\\"test\\")
+const _withId = /*#__PURE__*/_withScopeId(\\"test\\")
 
-export const render = /*#__PURE__*/ _withId(function render(_ctx, _cache) {
+export const render = /*#__PURE__*/_withId(function render(_ctx, _cache) {
   return (_openBlock(), _createBlock(\\"div\\"))
 })"
 `;
index 0cf24e60cff718ec10336f8998acc8135c3c696e..4ca5a585e2c7201e719e803bf6bc934707c554fb 100644 (file)
@@ -20,9 +20,9 @@ describe('scopeId compiler support', () => {
       scopeId: 'test'
     })
     expect(ast.helpers).toContain(WITH_SCOPE_ID)
-    expect(code).toMatch(`const _withId = /*#__PURE__*/ _withScopeId("test")`)
+    expect(code).toMatch(`const _withId = /*#__PURE__*/_withScopeId("test")`)
     expect(code).toMatch(
-      `export const render = /*#__PURE__*/ _withId(function render(`
+      `export const render = /*#__PURE__*/_withId(function render(`
     )
     expect(code).toMatchSnapshot()
   })
@@ -85,10 +85,10 @@ describe('scopeId compiler support', () => {
     expect(code).toMatch(
       [
         `_pushScopeId("test")`,
-        `const _hoisted_1 = /*#__PURE__*/ _createVNode("div", null, "hello", ${genFlagText(
+        `const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "hello", ${genFlagText(
           PatchFlags.HOISTED
         )})`,
-        `const _hoisted_2 = /*#__PURE__*/ _createVNode("div", null, "world", ${genFlagText(
+        `const _hoisted_2 = /*#__PURE__*/_createVNode("div", null, "world", ${genFlagText(
           PatchFlags.HOISTED
         )})`,
         `_popScopeId()`
index 658e01c3a4680cb48a6ccd8b859388c683e898ba..fcad21be3d88fefc18708fa059ffc7e8184a2c01 100644 (file)
@@ -4,7 +4,7 @@ exports[`compiler: hoistStatic transform hoist element with static key 1`] = `
 "const _Vue = Vue
 const { createVNode: _createVNode } = _Vue
 
-const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"div\\", { key: \\"foo\\" }, null, -1 /* HOISTED */)
+const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", { key: \\"foo\\" }, null, -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
   with (_ctx) {
@@ -21,9 +21,9 @@ exports[`compiler: hoistStatic transform hoist nested static tree 1`] = `
 "const _Vue = Vue
 const { createVNode: _createVNode } = _Vue
 
-const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"p\\", null, [
-  _createVNode(\\"span\\"),
-  _createVNode(\\"span\\")
+const _hoisted_1 = /*#__PURE__*/_createVNode(\\"p\\", null, [
+  /*#__PURE__*/_createVNode(\\"span\\"),
+  /*#__PURE__*/_createVNode(\\"span\\")
 ], -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
@@ -41,8 +41,8 @@ exports[`compiler: hoistStatic transform hoist nested static tree with comments
 "const _Vue = Vue
 const { createVNode: _createVNode, createCommentVNode: _createCommentVNode } = _Vue
 
-const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"div\\", null, [
-  _createCommentVNode(\\"comment\\")
+const _hoisted_1 = /*#__PURE__*/_createVNode(\\"div\\", null, [
+  /*#__PURE__*/_createCommentVNode(\\"comment\\")
 ], -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
@@ -60,8 +60,8 @@ exports[`compiler: hoistStatic transform hoist siblings with common non-hoistabl
 "const _Vue = Vue
 const { createVNode: _createVNode } = _Vue
 
-const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"span\\", null, null, -1 /* HOISTED */)
-const _hoisted_2 = /*#__PURE__*/ _createVNode(\\"div\\", null, null, -1 /* HOISTED */)
+const _hoisted_1 = /*#__PURE__*/_createVNode(\\"span\\", null, null, -1 /* HOISTED */)
+const _hoisted_2 = /*#__PURE__*/_createVNode(\\"div\\", null, null, -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
   with (_ctx) {
@@ -79,7 +79,7 @@ exports[`compiler: hoistStatic transform hoist simple element 1`] = `
 "const _Vue = Vue
 const { createVNode: _createVNode } = _Vue
 
-const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"span\\", { class: \\"inline\\" }, \\"hello\\", -1 /* HOISTED */)
+const _hoisted_1 = /*#__PURE__*/_createVNode(\\"span\\", { class: \\"inline\\" }, \\"hello\\", -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
   with (_ctx) {
@@ -172,7 +172,7 @@ exports[`compiler: hoistStatic transform prefixIdentifiers hoist nested static t
 "const _Vue = Vue
 const { createVNode: _createVNode } = _Vue
 
-const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"span\\", null, \\"foo \\" + _toDisplayString(1) + \\" \\" + _toDisplayString(true), -1 /* HOISTED */)
+const _hoisted_1 = /*#__PURE__*/_createVNode(\\"span\\", null, \\"foo \\" + /*#__PURE__*/_toDisplayString(1) + \\" \\" + /*#__PURE__*/_toDisplayString(true), -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
   with (_ctx) {
@@ -189,7 +189,7 @@ exports[`compiler: hoistStatic transform prefixIdentifiers hoist nested static t
 "const _Vue = Vue
 const { createVNode: _createVNode } = _Vue
 
-const _hoisted_1 = /*#__PURE__*/ _createVNode(\\"span\\", { foo: 0 }, _toDisplayString(1), -1 /* HOISTED */)
+const _hoisted_1 = /*#__PURE__*/_createVNode(\\"span\\", { foo: 0 }, /*#__PURE__*/_toDisplayString(1), -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
   with (_ctx) {
@@ -346,7 +346,7 @@ exports[`compiler: hoistStatic transform should hoist v-for children if static 1
 const { createVNode: _createVNode } = _Vue
 
 const _hoisted_1 = { id: \\"foo\\" }
-const _hoisted_2 = /*#__PURE__*/ _createVNode(\\"span\\", null, null, -1 /* HOISTED */)
+const _hoisted_2 = /*#__PURE__*/_createVNode(\\"span\\", null, null, -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
   with (_ctx) {
@@ -371,7 +371,7 @@ const _hoisted_1 = {
   key: 0,
   id: \\"foo\\"
 }
-const _hoisted_2 = /*#__PURE__*/ _createVNode(\\"span\\", null, null, -1 /* HOISTED */)
+const _hoisted_2 = /*#__PURE__*/_createVNode(\\"span\\", null, null, -1 /* HOISTED */)
 
 return function render(_ctx, _cache) {
   with (_ctx) {
index 45e9ef5449fefe39125e57c4a4cc5f4613d9823b..7982eedafcc83a0520ef5d0161f94fc1f458cda7 100644 (file)
@@ -54,6 +54,8 @@ import {
 } from './runtimeHelpers'
 import { ImportItem } from './transform'
 
+const PURE_ANNOTATION = `/*#__PURE__*/`
+
 type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
 
 export interface CodegenResult {
@@ -69,6 +71,7 @@ export interface CodegenContext extends Required<CodegenOptions> {
   column: number
   offset: number
   indentLevel: number
+  pure: boolean
   map?: SourceMapGenerator
   helper(key: symbol): string
   push(code: string, node?: CodegenNode): void
@@ -107,6 +110,7 @@ function createCodegenContext(
     line: 1,
     offset: 0,
     indentLevel: 0,
+    pure: false,
     map: undefined,
     helper(key) {
       return `_${helperNameMap[key]}`
@@ -201,7 +205,7 @@ export function generate(
 
   // enter render function
   if (genScopeId && !ssr) {
-    push(`const render = /*#__PURE__*/ _withId(`)
+    push(`const render = ${PURE_ANNOTATION}_withId(`)
   }
   if (!ssr) {
     push(`function render(_ctx, _cache) {`)
@@ -400,7 +404,9 @@ function genModulePreamble(
   }
 
   if (genScopeId) {
-    push(`const _withId = /*#__PURE__*/ ${helper(WITH_SCOPE_ID)}("${scopeId}")`)
+    push(
+      `const _withId = ${PURE_ANNOTATION}${helper(WITH_SCOPE_ID)}("${scopeId}")`
+    )
     newline()
   }
 
@@ -432,6 +438,7 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
   if (!hoists.length) {
     return
   }
+  context.pure = true
   const { push, newline, helper, scopeId, mode } = context
   const genScopeId = !__BROWSER__ && scopeId != null && mode !== 'function'
   newline()
@@ -445,13 +452,6 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
 
   hoists.forEach((exp, i) => {
     push(`const _hoisted_${i + 1} = `)
-    // make hosit function calls tree-shakable
-    if (
-      exp.type === NodeTypes.VNODE_CALL ||
-      exp.type === NodeTypes.JS_CALL_EXPRESSION
-    ) {
-      push(`/*#__PURE__*/ `)
-    }
     genNode(exp, context)
     newline()
   })
@@ -460,6 +460,7 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
     push(`${helper(POP_SCOPE_ID)}()`)
     newline()
   }
+  context.pure = false
 }
 
 function genImports(importsOptions: ImportItem[], context: CodegenContext) {
@@ -634,7 +635,8 @@ function genExpression(node: SimpleExpressionNode, context: CodegenContext) {
 }
 
 function genInterpolation(node: InterpolationNode, context: CodegenContext) {
-  const { push, helper } = context
+  const { push, helper, pure } = context
+  if (pure) push(PURE_ANNOTATION)
   push(`${helper(TO_DISPLAY_STRING)}(`)
   genNode(node.content, context)
   push(`)`)
@@ -676,13 +678,16 @@ function genExpressionAsPropertyKey(
 
 function genComment(node: CommentNode, context: CodegenContext) {
   if (__DEV__) {
-    const { push, helper } = context
+    const { push, helper, pure } = context
+    if (pure) {
+      push(PURE_ANNOTATION)
+    }
     push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node)
   }
 }
 
 function genVNodeCall(node: VNodeCall, context: CodegenContext) {
-  const { push, helper } = context
+  const { push, helper, pure } = context
   const {
     tag,
     props,
@@ -699,6 +704,9 @@ function genVNodeCall(node: VNodeCall, context: CodegenContext) {
   if (isBlock) {
     push(`(${helper(OPEN_BLOCK)}(${isForBlock ? `true` : ``}), `)
   }
+  if (pure) {
+    push(PURE_ANNOTATION)
+  }
   push(helper(isBlock ? CREATE_BLOCK : CREATE_VNODE) + `(`, node)
   genNodeList(
     genNullableArgs([tag, props, children, patchFlag, dynamicProps]),
@@ -725,12 +733,14 @@ function genNullableArgs(args: any[]): CallExpression['arguments'] {
 
 // JavaScript
 function genCallExpression(node: CallExpression, context: CodegenContext) {
-  const callee = isString(node.callee)
-    ? node.callee
-    : context.helper(node.callee)
-  context.push(callee + `(`, node)
+  const { push, helper, pure } = context
+  const callee = isString(node.callee) ? node.callee : helper(node.callee)
+  if (pure) {
+    push(PURE_ANNOTATION)
+  }
+  push(callee + `(`, node)
   genNodeList(node.arguments, context)
-  context.push(`)`)
+  push(`)`)
 }
 
 function genObjectExpression(node: ObjectExpression, context: CodegenContext) {