2
0
Эх сурвалжийг харах

fix(runtime-core): do not throw on unknown directives (#6671)

fix #6340

This commit improves the case when a directive is not found in a template.
As `resolveDirective` returns `undefined`, some code was failing with the following error:

```
TypeError: Cannot read properties of undefined (reading 'deep')
```
Cédric Exbrayat 3 жил өмнө
parent
commit
04553786e4

+ 21 - 1
packages/runtime-core/__tests__/directives.spec.ts

@@ -242,7 +242,7 @@ describe('directives', () => {
       expect(root.children[0]).toBe(el)
 
       // node should not have been updated yet
-      // expect(el.children[0].text).toBe(`${count.value - 1}`)
+      expect(el.children[0].text).toBe(`${count.value - 1}`)
 
       assertBindings(binding)
 
@@ -421,4 +421,24 @@ describe('directives', () => {
     render(h(App), root)
     expect(res!).toBe('Test')
   })
+
+  test('should not throw with unknown directive', async () => {
+    const d1 = {
+      mounted: jest.fn()
+    }
+    const App = {
+      name: 'App',
+      render() {
+        // simulates the code generated on an unknown directive
+        return withDirectives(h('div'), [
+          [undefined],
+          [d1]
+        ])
+      }
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+    expect(d1.mounted).toHaveBeenCalled()
+  })
 })

+ 22 - 20
packages/runtime-core/src/directives.ts

@@ -71,10 +71,10 @@ export function validateDirectiveName(name: string) {
 
 // Directive, value, argument, modifiers
 export type DirectiveArguments = Array<
-  | [Directive]
-  | [Directive, any]
-  | [Directive, any, string]
-  | [Directive, any, string, DirectiveModifiers]
+  | [Directive | undefined]
+  | [Directive | undefined, any]
+  | [Directive | undefined, any, string]
+  | [Directive | undefined, any, string, DirectiveModifiers]
 >
 
 /**
@@ -95,23 +95,25 @@ export function withDirectives<T extends VNode>(
   const bindings: DirectiveBinding[] = vnode.dirs || (vnode.dirs = [])
   for (let i = 0; i < directives.length; i++) {
     let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i]
-    if (isFunction(dir)) {
-      dir = {
-        mounted: dir,
-        updated: dir
-      } as ObjectDirective
+    if (dir) {
+      if (isFunction(dir)) {
+        dir = {
+          mounted: dir,
+          updated: dir
+        } as ObjectDirective
+      }
+      if (dir.deep) {
+        traverse(value)
+      }
+      bindings.push({
+        dir,
+        instance,
+        value,
+        oldValue: void 0,
+        arg,
+        modifiers
+      })
     }
-    if (dir.deep) {
-      traverse(value)
-    }
-    bindings.push({
-      dir,
-      instance,
-      value,
-      oldValue: void 0,
-      arg,
-      modifiers
-    })
   }
   return vnode
 }