]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
chore(compiler-core): reduce unnecessary cache inside v-once (#4112)
authorfishDog <40156382+Bigfish8@users.noreply.github.com>
Thu, 15 Jul 2021 20:50:54 +0000 (04:50 +0800)
committerEvan You <yyx990803@gmail.com>
Fri, 16 Jul 2021 18:30:49 +0000 (14:30 -0400)
packages/compiler-core/__tests__/transforms/vModel.spec.ts
packages/compiler-core/__tests__/transforms/vOn.spec.ts
packages/compiler-core/__tests__/transforms/vOnce.spec.ts
packages/compiler-core/src/transform.ts
packages/compiler-core/src/transforms/vModel.ts
packages/compiler-core/src/transforms/vOn.ts
packages/compiler-core/src/transforms/vOnce.ts

index 8acaa493e2c01b673843e97205bd5c45a3d7df53..fd611cddfe9947fd899414da771bf8233a718aa3 100644 (file)
@@ -425,6 +425,18 @@ describe('compiler: transform v-model', () => {
     ).not.toBe(NodeTypes.JS_CACHE_EXPRESSION)
   })
 
+  test('should not cache update handler if it inside v-once', () => {
+    const root = parseWithVModel(
+      '<div v-once><input v-model="foo" /></div>',
+      {
+        prefixIdentifiers: true,
+        cacheHandlers: true
+      }
+    )
+    expect(root.cached).not.toBe(2)
+    expect(root.cached).toBe(1)
+  })
+
   test('should mark update handler dynamic if it refers slot scope variables', () => {
     const root = parseWithVModel(
       '<Comp v-slot="{ foo }"><input v-model="foo.bar"/></Comp>',
index 24789d16f83fc817e6244f709a153526a5c60a4a..fe2f6be78cea50832e5bf227cca57f35f16de798 100644 (file)
@@ -530,6 +530,15 @@ describe('compiler: transform v-on', () => {
       expect(root.cached).toBe(0)
     })
 
+    test('should not be cached inside v-once', () => {
+      const { root } = parseWithVOn(`<div v-once><div v-on:click="foo"/></div>`, {
+        prefixIdentifiers: true,
+        cacheHandlers: true
+      })
+      expect(root.cached).not.toBe(2)
+      expect(root.cached).toBe(1)
+    })
+
     test('inline function expression handler', () => {
       const { root, node } = parseWithVOn(`<div v-on:click="() => foo()" />`, {
         prefixIdentifiers: true,
index d3b74f92409396e242bd5ee52c4e3244cbc835dc..553ac1dfac4951e85b3b6f64e5e9f559ea0b7678 100644 (file)
@@ -80,6 +80,13 @@ describe('compiler: v-once transform', () => {
     expect(generate(root).code).toMatchSnapshot()
   })
 
+  // v-once inside v-once should not be cached
+  test('inside v-once', () => {
+    const root = transformWithOnce(`<div v-once><div v-once/></div>`)
+    expect(root.cached).not.toBe(2)
+    expect(root.cached).toBe(1)
+  })
+
   // cached nodes should be ignored by hoistStatic transform
   test('with hoistStatic: true', () => {
     const root = transformWithOnce(`<div><div v-once /></div>`, {
index eb328dcd257659d3c617321ff46496606a74d7c9..77164f90aeedf74a414b69d8fd320853a608f2d0 100644 (file)
@@ -105,6 +105,7 @@ export interface TransformContext
   parent: ParentNode | null
   childIndex: number
   currentNode: RootNode | TemplateChildNode | null
+  inVOnce: boolean
   helper<T extends symbol>(name: T): T
   removeHelper<T extends symbol>(name: T): void
   helperString(name: symbol): string
@@ -192,6 +193,7 @@ export function createTransformContext(
     parent: null,
     currentNode: root,
     childIndex: 0,
+    inVOnce: false,
 
     // methods
     helper(name) {
index 011e4c620a9b72418c56a8635cd759dae7ce8a70..d55c4c617e5ffbf971dc48f9eef8f7253a50f0a7 100644 (file)
@@ -107,6 +107,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
   if (
     !__BROWSER__ &&
     context.prefixIdentifiers &&
+    !context.inVOnce &&
     context.cacheHandlers &&
     !hasScopeRef(exp, context.identifiers)
   ) {
index 68fd77b49bd38f0246f49ce33f1bb8327fec0fa3..42a289bb888f0b91281b464d73cd09dc2156968f 100644 (file)
@@ -70,7 +70,7 @@ export const transformOn: DirectiveTransform = (
   if (exp && !exp.content.trim()) {
     exp = undefined
   }
-  let shouldCache: boolean = context.cacheHandlers && !exp
+  let shouldCache: boolean = context.cacheHandlers && !exp && !context.inVOnce
   if (exp) {
     const isMemberExp = isMemberExpression(exp.content)
     const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content))
@@ -90,6 +90,8 @@ export const transformOn: DirectiveTransform = (
       // to scope variables.
       shouldCache =
         context.cacheHandlers &&
+        // unnecessary to cache inside v-once
+        !context.inVOnce &&
         // runtime constants don't need to be cached
         // (this is analyzed by compileScript in SFC <script setup>)
         !(exp.type === NodeTypes.SIMPLE_EXPRESSION && exp.constType > 0) &&
index 06c5171e1d83b5cc613cd94702fc0e08432d9afe..1b58c6763b64f5dd16a42e1ff3b3ce46e004cb4b 100644 (file)
@@ -7,12 +7,14 @@ const seen = new WeakSet()
 
 export const transformOnce: NodeTransform = (node, context) => {
   if (node.type === NodeTypes.ELEMENT && findDir(node, 'once', true)) {
-    if (seen.has(node)) {
+    if (seen.has(node) || context.inVOnce) {
       return
     }
     seen.add(node)
+    context.inVOnce = true
     context.helper(SET_BLOCK_TRACKING)
     return () => {
+      context.inVOnce = false
       const cur = context.currentNode as ElementNode | IfNode | ForNode
       if (cur.codegenNode) {
         cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */)