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')
```
This commit is contained in:
Cédric Exbrayat 2022-11-08 03:49:49 +01:00 committed by GitHub
parent b72a4af38a
commit 04553786e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 21 deletions

View File

@ -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()
})
})

View File

@ -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
}