]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(vapor): dom event error handling edison/fix/eventErrorHandling 13769/head
authordaiwei <daiwei521@126.com>
Fri, 15 Aug 2025 08:06:02 +0000 (16:06 +0800)
committerdaiwei <daiwei521@126.com>
Fri, 15 Aug 2025 08:06:02 +0000 (16:06 +0800)
packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vOn.spec.ts
packages/compiler-vapor/src/generators/event.ts
packages/runtime-vapor/__tests__/errorHandling.spec.ts
packages/runtime-vapor/src/dom/event.ts
packages/runtime-vapor/src/index.ts

index b10a98d32cba702483ed45d2d0175ec8232ffc37..a7461f119302c02670dead520f23c3e0d016f745 100644 (file)
@@ -180,14 +180,14 @@ export function render(_ctx) {
 `;
 
 exports[`compile > dynamic root nodes and interpolation 1`] = `
-"import { child as _child, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { child as _child, createInvoker as _createInvoker, setProp as _setProp, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<button> </button>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
   const x0 = _child(n0)
-  n0.$evtclick = e => _ctx.handleClick(e)
+  n0.$evtclick = _createInvoker(e => _ctx.handleClick(e))
   _renderEffect(() => {
     const _count = _ctx.count
     _setProp(n0, "id", _count)
index 7aa56aa9c2f880745a40a482fc1fbdfe419e2dcd..46d596b57fe6f5126a30299ecd7ecfc67762bcf0 100644 (file)
@@ -374,14 +374,14 @@ export function render(_ctx) {
 `;
 
 exports[`compiler: element transform > props merging: event handlers 1`] = `
-"import { withKeys as _withKeys, delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withKeys as _withKeys, delegate as _delegate, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  _delegate(n0, "click", _withKeys(e => _ctx.a(e), ["foo"]))
-  _delegate(n0, "click", _withKeys(e => _ctx.b(e), ["bar"]))
+  _delegate(n0, "click", _createInvoker(_withKeys(e => _ctx.a(e), ["foo"])))
+  _delegate(n0, "click", _createInvoker(_withKeys(e => _ctx.b(e), ["bar"])))
   return n0
 }"
 `;
index 69c695a246a424ef1a2ca66d473d418854fc4016..3dde66569e11734fe32cea44702439654c90d954 100644 (file)
@@ -31,7 +31,7 @@ export function render(_ctx) {
 `;
 
 exports[`compiler: v-for > basic v-for 1`] = `
-"import { child as _child, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { child as _child, createInvoker as _createInvoker, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div> </div>", true)
 _delegateEvents("click")
 
@@ -39,7 +39,7 @@ export function render(_ctx) {
   const n0 = _createFor(() => (_ctx.items), (_for_item0) => {
     const n2 = t0()
     const x2 = _child(n2)
-    n2.$evtclick = () => (_ctx.remove(_for_item0.value))
+    n2.$evtclick = _createInvoker(() => (_ctx.remove(_for_item0.value)))
     _renderEffect(() => _setText(x2, _toDisplayString(_for_item0.value)))
     return n2
   }, (item) => (item.id))
index e7a2b30e69cc0655e2c1b19e1016b028fd6aa791..223e45d1bcb9855399882d9550201d2d59dbf467 100644 (file)
@@ -1,13 +1,13 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`v-on > complex member expression w/ prefixIdentifiers: true 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = e => _ctx.a['b' + _ctx.c](e)
+  n0.$evtclick = _createInvoker(e => _ctx.a['b' + _ctx.c](e))
   return n0
 }"
 `;
@@ -28,14 +28,14 @@ export function render(_ctx) {
 `;
 
 exports[`v-on > dynamic arg 1`] = `
-"import { on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
   _renderEffect(() => {
     
-    _on(n0, _ctx.event, e => _ctx.handler(e), {
+    _on(n0, _ctx.event, _createInvoker(e => _ctx.handler(e)), {
       effect: true
     })
   })
@@ -44,14 +44,14 @@ export function render(_ctx) {
 `;
 
 exports[`v-on > dynamic arg with complex exp prefixing 1`] = `
-"import { on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
   _renderEffect(() => {
     
-    _on(n0, _ctx.event(_ctx.foo), e => _ctx.handler(e), {
+    _on(n0, _ctx.event(_ctx.foo), _createInvoker(e => _ctx.handler(e)), {
       effect: true
     })
   })
@@ -60,14 +60,14 @@ export function render(_ctx) {
 `;
 
 exports[`v-on > dynamic arg with prefixing 1`] = `
-"import { on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
   _renderEffect(() => {
     
-    _on(n0, _ctx.event, e => _ctx.handler(e), {
+    _on(n0, _ctx.event, _createInvoker(e => _ctx.handler(e)), {
       effect: true
     })
   })
@@ -76,7 +76,7 @@ export function render(_ctx) {
 `;
 
 exports[`v-on > event modifier 1`] = `
-"import { withModifiers as _withModifiers, on as _on, withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, on as _on, withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<a></a>")
 const t1 = _template("<form></form>")
 const t2 = _template("<div></div>")
@@ -106,233 +106,233 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n19 = t3()
   const n20 = t3()
   const n21 = t3()
-  n0.$evtclick = _withModifiers(_ctx.handleEvent, ["stop"])
-  _on(n1, "submit", _withModifiers(_ctx.handleEvent, ["prevent"]))
-  n2.$evtclick = _withModifiers(_ctx.handleEvent, ["stop","prevent"])
-  n3.$evtclick = _withModifiers(_ctx.handleEvent, ["self"])
-  _on(n4, "click", _ctx.handleEvent, {
+  n0.$evtclick = _createInvoker(_withModifiers(_ctx.handleEvent, ["stop"]))
+  _on(n1, "submit", _createInvoker(_withModifiers(_ctx.handleEvent, ["prevent"])))
+  n2.$evtclick = _createInvoker(_withModifiers(_ctx.handleEvent, ["stop","prevent"]))
+  n3.$evtclick = _createInvoker(_withModifiers(_ctx.handleEvent, ["self"]))
+  _on(n4, "click", _createInvoker(_ctx.handleEvent), {
     capture: true
   })
-  _on(n5, "click", _ctx.handleEvent, {
+  _on(n5, "click", _createInvoker(_ctx.handleEvent), {
     once: true
   })
-  _on(n6, "scroll", _ctx.handleEvent, {
+  _on(n6, "scroll", _createInvoker(_ctx.handleEvent), {
     passive: true
   })
-  n7.$evtcontextmenu = _withModifiers(_ctx.handleEvent, ["right"])
-  n8.$evtclick = _withModifiers(_ctx.handleEvent, ["left"])
-  n9.$evtmouseup = _withModifiers(_ctx.handleEvent, ["middle"])
-  n10.$evtcontextmenu = _withKeys(_withModifiers(_ctx.handleEvent, ["right"]), ["enter"])
-  n11.$evtkeyup = _withKeys(_ctx.handleEvent, ["enter"])
-  n12.$evtkeyup = _withKeys(_ctx.handleEvent, ["tab"])
-  n13.$evtkeyup = _withKeys(_ctx.handleEvent, ["delete"])
-  n14.$evtkeyup = _withKeys(_ctx.handleEvent, ["esc"])
-  n15.$evtkeyup = _withKeys(_ctx.handleEvent, ["space"])
-  n16.$evtkeyup = _withKeys(_ctx.handleEvent, ["up"])
-  n17.$evtkeyup = _withKeys(_ctx.handleEvent, ["down"])
-  n18.$evtkeyup = _withKeys(_ctx.handleEvent, ["left"])
-  n19.$evtkeyup = _withModifiers(e => _ctx.submit(e), ["middle"])
-  n20.$evtkeyup = _withModifiers(e => _ctx.submit(e), ["middle","self"])
-  n21.$evtkeyup = _withKeys(_withModifiers(_ctx.handleEvent, ["self"]), ["enter"])
+  n7.$evtcontextmenu = _createInvoker(_withModifiers(_ctx.handleEvent, ["right"]))
+  n8.$evtclick = _createInvoker(_withModifiers(_ctx.handleEvent, ["left"]))
+  n9.$evtmouseup = _createInvoker(_withModifiers(_ctx.handleEvent, ["middle"]))
+  n10.$evtcontextmenu = _createInvoker(_withKeys(_withModifiers(_ctx.handleEvent, ["right"]), ["enter"]))
+  n11.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["enter"]))
+  n12.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["tab"]))
+  n13.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["delete"]))
+  n14.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["esc"]))
+  n15.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["space"]))
+  n16.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["up"]))
+  n17.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["down"]))
+  n18.$evtkeyup = _createInvoker(_withKeys(_ctx.handleEvent, ["left"]))
+  n19.$evtkeyup = _createInvoker(_withModifiers(e => _ctx.submit(e), ["middle"]))
+  n20.$evtkeyup = _createInvoker(_withModifiers(e => _ctx.submit(e), ["middle","self"]))
+  n21.$evtkeyup = _createInvoker(_withKeys(_withModifiers(_ctx.handleEvent, ["self"]), ["enter"]))
   return [n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19, n20, n21]
 }"
 `;
 
 exports[`v-on > expression with type 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  n0.$evtclick = e => _ctx.handleClick(e)
+  n0.$evtclick = _createInvoker(e => _ctx.handleClick(e))
   return n0
 }"
 `;
 
 exports[`v-on > function expression w/ prefixIdentifiers: true 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = e => _ctx.foo(e)
+  n0.$evtclick = _createInvoker(e => _ctx.foo(e))
   return n0
 }"
 `;
 
 exports[`v-on > inline statement w/ prefixIdentifiers: true 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = $event => (_ctx.foo($event))
+  n0.$evtclick = _createInvoker($event => (_ctx.foo($event)))
   return n0
 }"
 `;
 
 exports[`v-on > multiple inline statements w/ prefixIdentifiers: true 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = $event => {_ctx.foo($event);_ctx.bar()}
+  n0.$evtclick = _createInvoker($event => {_ctx.foo($event);_ctx.bar()})
   return n0
 }"
 `;
 
 exports[`v-on > should NOT add a prefix to $event if the expression is a function expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = $event => {_ctx.i++;_ctx.foo($event)}
+  n0.$evtclick = _createInvoker($event => {_ctx.i++;_ctx.foo($event)})
   return n0
 }"
 `;
 
 exports[`v-on > should NOT wrap as function if expression is already function expression (with Typescript) 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = (e: any): any => _ctx.foo(e)
+  n0.$evtclick = _createInvoker((e: any): any => _ctx.foo(e))
   return n0
 }"
 `;
 
 exports[`v-on > should NOT wrap as function if expression is already function expression (with newlines) 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = 
+  n0.$evtclick = _createInvoker(
       $event => {
         _ctx.foo($event)
       }
-    
+    )
   return n0
 }"
 `;
 
 exports[`v-on > should NOT wrap as function if expression is already function expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = $event => _ctx.foo($event)
+  n0.$evtclick = _createInvoker($event => _ctx.foo($event))
   return n0
 }"
 `;
 
 exports[`v-on > should NOT wrap as function if expression is complex member expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = e => _ctx.a['b' + _ctx.c](e)
+  n0.$evtclick = _createInvoker(e => _ctx.a['b' + _ctx.c](e))
   return n0
 }"
 `;
 
 exports[`v-on > should delegate event 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = e => _ctx.test(e)
+  n0.$evtclick = _createInvoker(e => _ctx.test(e))
   return n0
 }"
 `;
 
 exports[`v-on > should handle multi-line statement 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = () => {
+  n0.$evtclick = _createInvoker(() => {
 _ctx.foo();
 _ctx.bar()
-}
+})
   return n0
 }"
 `;
 
 exports[`v-on > should handle multiple inline statement 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = () => {_ctx.foo();_ctx.bar()}
+  n0.$evtclick = _createInvoker(() => {_ctx.foo();_ctx.bar()})
   return n0
 }"
 `;
 
 exports[`v-on > should not prefix member expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = e => _ctx.foo.bar(e)
+  n0.$evtclick = _createInvoker(e => _ctx.foo.bar(e))
   return n0
 }"
 `;
 
 exports[`v-on > should not wrap keys guard if no key modifier is present 1`] = `
-"import { withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("keyup")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtkeyup = _withModifiers(e => _ctx.test(e), ["exact"])
+  n0.$evtkeyup = _createInvoker(_withModifiers(e => _ctx.test(e), ["exact"]))
   return n0
 }"
 `;
 
 exports[`v-on > should support multiple events and modifiers options w/ prefixIdentifiers: true 1`] = `
-"import { withModifiers as _withModifiers, withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click", "keyup")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = _withModifiers(e => _ctx.test(e), ["stop"])
-  n0.$evtkeyup = _withKeys(e => _ctx.test(e), ["enter"])
+  n0.$evtclick = _createInvoker(_withModifiers(e => _ctx.test(e), ["stop"]))
+  n0.$evtkeyup = _createInvoker(_withKeys(e => _ctx.test(e), ["enter"]))
   return n0
 }"
 `;
 
 exports[`v-on > should support multiple modifiers and event options w/ prefixIdentifiers: true 1`] = `
-"import { withModifiers as _withModifiers, on as _on, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, on as _on, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
-  _on(n0, "click", _withModifiers(e => _ctx.test(e), ["stop","prevent"]), {
+  _on(n0, "click", _createInvoker(_withModifiers(e => _ctx.test(e), ["stop","prevent"])), {
     capture: true, 
     once: true
   })
@@ -341,26 +341,26 @@ export function render(_ctx) {
 `;
 
 exports[`v-on > should transform click.middle 1`] = `
-"import { withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("mouseup")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtmouseup = _withModifiers(e => _ctx.test(e), ["middle"])
+  n0.$evtmouseup = _createInvoker(_withModifiers(e => _ctx.test(e), ["middle"]))
   return n0
 }"
 `;
 
 exports[`v-on > should transform click.middle 2`] = `
-"import { withModifiers as _withModifiers, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
   _renderEffect(() => {
     
-    _on(n0, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), _withModifiers(e => _ctx.test(e), ["middle"]), {
+    _on(n0, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), _createInvoker(_withModifiers(e => _ctx.test(e), ["middle"])), {
       effect: true
     })
   })
@@ -369,26 +369,26 @@ export function render(_ctx) {
 `;
 
 exports[`v-on > should transform click.right 1`] = `
-"import { withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("contextmenu")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtcontextmenu = _withModifiers(e => _ctx.test(e), ["right"])
+  n0.$evtcontextmenu = _createInvoker(_withModifiers(e => _ctx.test(e), ["right"]))
   return n0
 }"
 `;
 
 exports[`v-on > should transform click.right 2`] = `
-"import { withModifiers as _withModifiers, withKeys as _withKeys, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, withKeys as _withKeys, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
   _renderEffect(() => {
     
-    _on(n0, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), _withKeys(_withModifiers(e => _ctx.test(e), ["right"]), ["right"]), {
+    _on(n0, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), _createInvoker(_withKeys(_withModifiers(e => _ctx.test(e), ["right"]), ["right"])), {
       effect: true
     })
   })
@@ -397,39 +397,39 @@ export function render(_ctx) {
 `;
 
 exports[`v-on > should use delegate helper when have multiple events of same name 1`] = `
-"import { delegate as _delegate, withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegate as _delegate, withModifiers as _withModifiers, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  _delegate(n0, "click", e => _ctx.test(e))
-  _delegate(n0, "click", _withModifiers(e => _ctx.test(e), ["stop"]))
+  _delegate(n0, "click", _createInvoker(e => _ctx.test(e)))
+  _delegate(n0, "click", _createInvoker(_withModifiers(e => _ctx.test(e), ["stop"])))
   return n0
 }"
 `;
 
 exports[`v-on > should wrap as function if expression is inline statement 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtclick = () => (_ctx.i++)
+  n0.$evtclick = _createInvoker(() => (_ctx.i++))
   return n0
 }"
 `;
 
 exports[`v-on > should wrap both for dynamic key event w/ left/right modifiers 1`] = `
-"import { withModifiers as _withModifiers, withKeys as _withKeys, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, withKeys as _withKeys, on as _on, renderEffect as _renderEffect, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
   _renderEffect(() => {
     
-    _on(n0, _ctx.e, _withKeys(_withModifiers(e => _ctx.test(e), ["left"]), ["left"]), {
+    _on(n0, _ctx.e, _createInvoker(_withKeys(_withModifiers(e => _ctx.test(e), ["left"]), ["left"])), {
       effect: true
     })
   })
@@ -442,20 +442,20 @@ exports[`v-on > should wrap in unref if identifier is setup-maybe-ref w/ inline:
   const n0 = t0()
   const n1 = t0()
   const n2 = t0()
-  n0.$evtclick = () => (x.value=_unref(y))
-  n1.$evtclick = () => (x.value++)
-  n2.$evtclick = () => ({ x: x.value } = _unref(y))
+  n0.$evtclick = _createInvoker(() => (x.value=_unref(y)))
+  n1.$evtclick = _createInvoker(() => (x.value++))
+  n2.$evtclick = _createInvoker(() => ({ x: x.value } = _unref(y)))
   return [n0, n1, n2]
 "
 `;
 
 exports[`v-on > should wrap keys guard for keyboard events or dynamic events 1`] = `
-"import { withModifiers as _withModifiers, withKeys as _withKeys, on as _on, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withModifiers as _withModifiers, withKeys as _withKeys, on as _on, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 
 export function render(_ctx) {
   const n0 = t0()
-  _on(n0, "keydown", _withKeys(_withModifiers(e => _ctx.test(e), ["stop","ctrl"]), ["a"]), {
+  _on(n0, "keydown", _createInvoker(_withKeys(_withModifiers(e => _ctx.test(e), ["stop","ctrl"]), ["a"])), {
     capture: true
   })
   return n0
@@ -463,25 +463,25 @@ export function render(_ctx) {
 `;
 
 exports[`v-on > should wrap keys guard for static key event w/ left/right modifiers 1`] = `
-"import { withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, withKeys as _withKeys, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("keyup")
 
 export function render(_ctx) {
   const n0 = t0()
-  n0.$evtkeyup = _withKeys(e => _ctx.test(e), ["left"])
+  n0.$evtkeyup = _createInvoker(_withKeys(e => _ctx.test(e), ["left"]))
   return n0
 }"
 `;
 
 exports[`v-on > simple expression 1`] = `
-"import { delegateEvents as _delegateEvents, template as _template } from 'vue';
+"import { createInvoker as _createInvoker, delegateEvents as _delegateEvents, template as _template } from 'vue';
 const t0 = _template("<div></div>", true)
 _delegateEvents("click")
 
 export function render(_ctx, $props, $emit, $attrs, $slots) {
   const n0 = t0()
-  n0.$evtclick = _ctx.handleClick
+  n0.$evtclick = _createInvoker(_ctx.handleClick)
   return n0
 }"
 `;
index 963f46ad2a3a8a4cdf0fea4924a7f370aa95ed2e..eab3931ca1da5e768ea659cc46c6f020a1a40e19 100644 (file)
@@ -165,7 +165,7 @@ describe('v-on', () => {
         delegate: true,
       },
     ])
-    expect(code).contains(`n0.$evtclick = () => (_ctx.i++)`)
+    expect(code).contains(`n0.$evtclick = _createInvoker(() => (_ctx.i++))`)
   })
 
   test('should wrap in unref if identifier is setup-maybe-ref w/ inline: true', () => {
@@ -182,9 +182,13 @@ describe('v-on', () => {
     )
     expect(code).matchSnapshot()
     expect(helpers).contains('unref')
-    expect(code).contains(`n0.$evtclick = () => (x.value=_unref(y))`)
-    expect(code).contains(`n1.$evtclick = () => (x.value++)`)
-    expect(code).contains(`n2.$evtclick = () => ({ x: x.value } = _unref(y))`)
+    expect(code).contains(
+      `n0.$evtclick = _createInvoker(() => (x.value=_unref(y)))`,
+    )
+    expect(code).contains(`n1.$evtclick = _createInvoker(() => (x.value++))`)
+    expect(code).contains(
+      `n2.$evtclick = _createInvoker(() => ({ x: x.value } = _unref(y)))`,
+    )
   })
 
   test('should handle multiple inline statement', () => {
@@ -200,7 +204,9 @@ describe('v-on', () => {
     // should wrap with `{` for multiple statements
     // in this case the return value is discarded and the behavior is
     // consistent with 2.x
-    expect(code).contains(`n0.$evtclick = () => {_ctx.foo();_ctx.bar()}`)
+    expect(code).contains(
+      `n0.$evtclick = _createInvoker(() => {_ctx.foo();_ctx.bar()})`,
+    )
   })
 
   test('should handle multi-line statement', () => {
@@ -216,7 +222,9 @@ describe('v-on', () => {
     // should wrap with `{` for multiple statements
     // in this case the return value is discarded and the behavior is
     // consistent with 2.x
-    expect(code).contains(`n0.$evtclick = () => {\n_ctx.foo();\n_ctx.bar()\n}`)
+    expect(code).contains(
+      `n0.$evtclick = _createInvoker(() => {\n_ctx.foo();\n_ctx.bar()\n})`,
+    )
   })
 
   test('inline statement w/ prefixIdentifiers: true', () => {
@@ -232,7 +240,9 @@ describe('v-on', () => {
       },
     ])
     // should NOT prefix $event
-    expect(code).contains(`n0.$evtclick = $event => (_ctx.foo($event))`)
+    expect(code).contains(
+      `n0.$evtclick = _createInvoker($event => (_ctx.foo($event)))`,
+    )
   })
 
   test('multiple inline statements w/ prefixIdentifiers: true', () => {
@@ -249,7 +259,7 @@ describe('v-on', () => {
     ])
     // should NOT prefix $event
     expect(code).contains(
-      `n0.$evtclick = $event => {_ctx.foo($event);_ctx.bar()}`,
+      `n0.$evtclick = _createInvoker($event => {_ctx.foo($event);_ctx.bar()})`,
     )
   })
 
@@ -263,7 +273,9 @@ describe('v-on', () => {
         value: { content: '$event => foo($event)' },
       },
     ])
-    expect(code).contains(`n0.$evtclick = $event => _ctx.foo($event)`)
+    expect(code).contains(
+      `n0.$evtclick = _createInvoker($event => _ctx.foo($event))`,
+    )
   })
 
   test('should NOT wrap as function if expression is already function expression (with Typescript)', () => {
@@ -279,7 +291,9 @@ describe('v-on', () => {
         value: { content: '(e: any): any => foo(e)' },
       },
     ])
-    expect(code).contains(`n0.$evtclick = (e: any): any => _ctx.foo(e)`)
+    expect(code).contains(
+      `n0.$evtclick = _createInvoker((e: any): any => _ctx.foo(e))`,
+    )
   })
 
   test('should NOT wrap as function if expression is already function expression (with newlines)', () => {
@@ -344,7 +358,9 @@ describe('v-on', () => {
     ])
 
     expect(code).matchSnapshot()
-    expect(code).contains(`n0.$evtclick = e => _ctx.a['b' + _ctx.c](e)`)
+    expect(code).contains(
+      `n0.$evtclick = _createInvoker(e => _ctx.a['b' + _ctx.c](e))`,
+    )
   })
 
   test('function expression w/ prefixIdentifiers: true', () => {
@@ -359,7 +375,7 @@ describe('v-on', () => {
         value: { content: `e => foo(e)` },
       },
     ])
-    expect(code).contains(`n0.$evtclick = e => _ctx.foo(e)`)
+    expect(code).contains(`n0.$evtclick = _createInvoker(e => _ctx.foo(e))`)
   })
 
   test('should error if no expression AND no modifier', () => {
@@ -414,7 +430,7 @@ describe('v-on', () => {
       },
     ])
     expect(code).contains(
-      `_on(n0, "click", _withModifiers(e => _ctx.test(e), ["stop","prevent"]), {
+      `_on(n0, "click", _createInvoker(_withModifiers(e => _ctx.test(e), ["stop","prevent"])), {
     capture: true, 
     once: true
   })`,
@@ -470,8 +486,8 @@ describe('v-on', () => {
 
     expect(code).matchSnapshot()
     expect(code).contains(
-      `n0.$evtclick = _withModifiers(e => _ctx.test(e), ["stop"])
-  n0.$evtkeyup = _withKeys(e => _ctx.test(e), ["enter"])`,
+      `n0.$evtclick = _createInvoker(_withModifiers(e => _ctx.test(e), ["stop"]))
+  n0.$evtkeyup = _createInvoker(_withKeys(e => _ctx.test(e), ["enter"]))`,
     )
   })
 
@@ -654,7 +670,7 @@ describe('v-on', () => {
     })
 
     expect(code).matchSnapshot()
-    expect(code).contains(`n0.$evtclick = e => _ctx.foo.bar(e)`)
+    expect(code).contains(`n0.$evtclick = _createInvoker(e => _ctx.foo.bar(e))`)
   })
 
   test('should delegate event', () => {
@@ -677,9 +693,11 @@ describe('v-on', () => {
     )
     expect(helpers).contains('delegate')
     expect(code).toMatchSnapshot()
-    expect(code).contains('_delegate(n0, "click", e => _ctx.test(e))')
     expect(code).contains(
-      '_delegate(n0, "click", _withModifiers(e => _ctx.test(e), ["stop"]))',
+      '_delegate(n0, "click", _createInvoker(e => _ctx.test(e)))',
+    )
+    expect(code).contains(
+      '_delegate(n0, "click", _createInvoker(_withModifiers(e => _ctx.test(e), ["stop"])))',
     )
   })
 
@@ -693,7 +711,9 @@ describe('v-on', () => {
       },
     )
     expect(code).matchSnapshot()
-    expect(code).include('n0.$evtclick = e => _ctx.handleClick(e)')
+    expect(code).include(
+      'n0.$evtclick = _createInvoker(e => _ctx.handleClick(e))',
+    )
   })
 
   test('component event with special characters', () => {
index cfb47b6118456a788a78f59478a7664a40543d37..cc2491bddfa5b17bfb4f8fafcd141330657512c0 100644 (file)
@@ -28,7 +28,11 @@ export function genSetEvent(
   const { element, key, keyOverride, value, modifiers, delegate, effect } = oper
 
   const name = genName()
-  const handler = genEventHandler(context, value, modifiers)
+  const handler = [
+    `${context.helper('createInvoker')}(`,
+    ...genEventHandler(context, value, modifiers),
+    `)`,
+  ]
   const eventOptions = genEventOptions()
 
   if (delegate) {
index 87a79614d41beffc777345cccb442937b05619f4..8935579c86a7ad6ce265a0adf6544fe8d853eed0 100644 (file)
@@ -6,7 +6,14 @@ import {
   watch,
   watchEffect,
 } from '@vue/runtime-dom'
-import { createComponent, createTemplateRefSetter, template } from '../src'
+import {
+  createComponent,
+  createInvoker,
+  createTemplateRefSetter,
+  defineVaporComponent,
+  delegateEvents,
+  template,
+} from '../src'
 import { makeRender } from './_utils'
 import type { VaporComponent } from '../src/component'
 import type { RefEl } from '../src/apiTemplateRef'
@@ -364,6 +371,38 @@ describe('error handling', () => {
     expect(fn).toHaveBeenCalledWith(err, 'watcher cleanup function')
   })
 
+  test('in dom event handler', () => {
+    const err = new Error('foo')
+    const fn = vi.fn()
+
+    const Comp = {
+      setup() {
+        onErrorCaptured((err, instance, info) => {
+          fn(err, info)
+          return false
+        })
+        return createComponent(Child)
+      },
+    }
+
+    delegateEvents('click')
+    const Child = defineVaporComponent({
+      setup() {
+        function onClick() {
+          throw err
+        }
+        const n0 = template('<button>throw Error</button>', true)() as any
+        n0.$evtclick = createInvoker(onClick)
+        return n0
+      },
+    })
+
+    const { host } = define(Comp).render()
+    const btn = host.querySelector('button') as HTMLButtonElement
+    btn.click()
+    expect(fn).toHaveBeenCalledWith(err, 'native event handler')
+  })
+
   test('in component event handler via emit', () => {
     const err = new Error('foo')
     const fn = vi.fn()
index 4987ecfc0d80fd19009bba533742aeae55d51861..90f7d60ed2262296c7c35a2bd181d56892f15db9 100644 (file)
@@ -1,5 +1,6 @@
 import { onEffectCleanup } from '@vue/reactivity'
 import { isArray } from '@vue/shared'
+import { ErrorCodes, callWithAsyncErrorHandling, currentInstance } from 'vue'
 
 export function addEventListener(
   el: Element,
@@ -107,3 +108,16 @@ export function setDynamicEvents(
     on(el, name, events[name], { effect: true })
   }
 }
+
+export function createInvoker(
+  handler: (...args: any[]) => any,
+): (...args: any[]) => any {
+  const i = currentInstance
+  return (...args: any[]) =>
+    callWithAsyncErrorHandling(
+      handler,
+      i,
+      ErrorCodes.NATIVE_EVENT_HANDLER,
+      args,
+    )
+}
index 7a8aea5a0d71778852b4eb97a8b470016c30340e..4550db497a7f344ef6adef6d1910567f297e14f9 100644 (file)
@@ -27,7 +27,13 @@ export {
   setDOMProp,
   setDynamicProps,
 } from './dom/prop'
-export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
+export {
+  on,
+  delegate,
+  delegateEvents,
+  setDynamicEvents,
+  createInvoker,
+} from './dom/event'
 export { createIf } from './apiCreateIf'
 export {
   createFor,