11# Vue improvements
22
3- ## Completed tasks
4-
5- (none yet)
6-
73## Planned tasks (mirrored from React)
84
9- - [ ] ` FlareErrorBoundary ` component with ` fallback ` slot
10- - [ ] ` FlareErrorBoundary ` fallback with ` reset ` method
11- - [ ] ` FlareErrorBoundary ` fallback passes component hierarchy info
5+ - [x ] ` FlareErrorBoundary ` component with ` fallback ` slot
6+ - [x ] ` FlareErrorBoundary ` fallback with ` reset ` method
7+ - [x ] ` FlareErrorBoundary ` fallback passes component hierarchy info
128- [ ] ` FlareErrorBoundary ` supports ` beforeEvaluate ` callback
139- [ ] ` FlareErrorBoundary ` supports ` beforeSubmit ` callback
1410- [ ] ` FlareErrorBoundary ` supports ` afterSubmit ` callback
1511- [ ] ` FlareErrorBoundary ` supports ` onReset ` prop
1612- [ ] ` FlareErrorBoundary ` ` onReset ` passes previous error
1713- [ ] ` FlareErrorBoundary ` supports ` resetKeys ` prop (via watchers)
1814- [ ] Enhance ` flareVue() ` with ` beforeEvaluate ` , ` beforeSubmit ` , and ` afterSubmit ` callbacks
19- - [ ] Structured component hierarchy parsing
15+ - [ ] Structured component hierarchy parsing ( ` componentHierarchyFrames ` with file/props)
2016
2117## Planned tasks (Vue-only features)
2218
2319- [ ] Capture component props from the erroring component instance
24- - [ ] Capture lifecycle hook / origin info (where the error occurred)
25- - [ ] Component hierarchy traversal via ` $parent ` chain
20+ - [ ~ ] Capture lifecycle hook / origin info (where the error occurred) — ` info ` string is sent as ` context.vue.info ` , but
21+ normalized ` errorOrigin ` category is not yet implemented
22+ - [x] Component hierarchy traversal via ` $parent ` chain
2623- [ ] ` app.config.warnHandler ` integration for capturing Vue warnings
2724- [ ] Vue Router integration: capture current route as context
2825
@@ -70,6 +67,7 @@ default content of the `fallback` slot.
7067### Implementation notes
7168
7269Vue's ` onErrorCaptured ` hook receives ` (err, instance, info) ` :
70+
7371- ` err ` : the error object
7472- ` instance ` : the component instance that threw the error (or ` null ` )
7573- ` info ` : a string describing where the error was captured (e.g. ` "setup function" ` , ` "render function" ` ,
@@ -86,10 +84,12 @@ components, so the error boundary itself will be a `<script setup>` component ra
8684
8785### Why
8886
89- Same rationale as React. Fires before the component hierarchy context is built, letting developers attach custom context,
87+ Same rationale as React. Fires before the component hierarchy context is built, letting developers attach custom
88+ context,
9089tags, or user information to the Flare report before the error is evaluated.
9190
9291``` vue
92+
9393<FlareErrorBoundary
9494 :before-evaluate="({ error, instance, info }) => {
9595 flare.addContext('user', { id: currentUser.id });
@@ -114,6 +114,7 @@ Fires after the component hierarchy context is built but before the error is rep
114114the ` context ` and must return a (possibly modified) context object. Use this to filter or enrich the report context.
115115
116116``` vue
117+
117118<FlareErrorBoundary
118119 :before-submit="({ error, instance, info, context }) => {
119120 return {
@@ -139,6 +140,7 @@ Developers need a hook to perform side effects after an error is reported. This
139140reported to Flare.
140141
141142``` vue
143+
142144<FlareErrorBoundary
143145 :after-submit="({ error, instance, info, context }) => {
144146 console.error('Caught by FlareErrorBoundary:', error);
@@ -158,6 +160,7 @@ Same rationale as React. When the error boundary resets, developers often need t
158160allows conditional cleanup based on what went wrong.
159161
160162``` vue
163+
161164<FlareErrorBoundary
162165 :on-reset="(error) => {
163166 console.log('Recovering from:', error?.message);
@@ -182,10 +185,11 @@ and next key arrays. Vue's version uses a `watch` on the `resetKeys` prop with `
182185` Object.is ` the same way React does.
183186
184187``` vue
188+
185189<script setup>
186- import { useRoute } from 'vue-router';
190+ import { useRoute } from 'vue-router';
187191
188- const route = useRoute();
192+ const route = useRoute();
189193</script>
190194
191195<template>
@@ -289,40 +293,42 @@ structured data.
289293
290294``` json
291295{
292- "context" : {
293- "vue" : {
294- "info" : " setup function" ,
295- "componentName" : " BuggyComponent" ,
296- "componentHierarchy" : [
297- " BuggyComponent" ,
298- " ParentPage" ,
299- " AppLayout" ,
300- " App"
301- ],
302- "componentHierarchyFrames" : [
303- {
304- "component" : " BuggyComponent" ,
305- "file" : " src/components/BuggyComponent.vue" ,
306- "props" : { "userId" : 42 }
307- },
308- {
309- "component" : " ParentPage " ,
310- "file" : " src/pages/ParentPage.vue " ,
311- "props " : {}
312- } ,
313- {
314- "component" : " AppLayout " ,
315- "file" : " src/layouts/AppLayout.vue " ,
316- "props " : {}
317- } ,
318- {
319- "component" : " App " ,
320- "file" : " src/App.vue " ,
321- "props " : {}
322- }
323- ]
296+ "context" : {
297+ "vue" : {
298+ "info" : " setup function" ,
299+ "componentName" : " BuggyComponent" ,
300+ "componentHierarchy" : [
301+ " BuggyComponent" ,
302+ " ParentPage" ,
303+ " AppLayout" ,
304+ " App"
305+ ],
306+ "componentHierarchyFrames" : [
307+ {
308+ "component" : " BuggyComponent" ,
309+ "file" : " src/components/BuggyComponent.vue" ,
310+ "props" : {
311+ "userId" : 42
312+ }
313+ } ,
314+ {
315+ "component " : " ParentPage " ,
316+ "file" : " src/pages/ParentPage.vue " ,
317+ "props" : {}
318+ } ,
319+ {
320+ "component " : " AppLayout " ,
321+ "file" : " src/layouts/AppLayout.vue " ,
322+ "props" : {}
323+ } ,
324+ {
325+ "component " : " App " ,
326+ "file" : " src/App.vue " ,
327+ "props" : {}
324328 }
329+ ]
325330 }
331+ }
326332}
327333```
328334
@@ -353,9 +359,11 @@ enabled, the props of the erroring component are included in the report context.
353359
354360``` ts
355361// In FlareErrorBoundary
356- < FlareErrorBoundary :attach - props = " true" >
357- < App / >
358- < / FlareErrorBoundary >
362+ < FlareErrorBoundary
363+ :
364+ attach - props = " true" >
365+ < App / >
366+ < / FlareErrorBoundary >
359367
360368// In flareVue()
361369flareVue (app , { attachProps: true });
@@ -368,16 +376,18 @@ symbols are excluded. A configurable `propsMaxDepth` option (default 2) controls
368376
369377``` json
370378{
371- "context" : {
372- "vue" : {
373- "info" : " render function" ,
374- "componentName" : " UserProfile" ,
375- "componentProps" : {
376- "userId" : 42 ,
377- "settings" : { "theme" : " dark " }
378- }
379+ "context" : {
380+ "vue" : {
381+ "info" : " render function" ,
382+ "componentName" : " UserProfile" ,
383+ "componentProps" : {
384+ "userId" : 42 ,
385+ "settings" : {
386+ "theme" : " dark "
379387 }
388+ }
380389 }
390+ }
381391}
382392```
383393
@@ -390,6 +400,7 @@ lifecycle. This is already partially captured by the current `flareVue()` implem
390400documented.
391401
392402Vue provides values like:
403+
393404- ` "setup function" ` -- error in ` <script setup> ` or ` setup() `
394405- ` "render function" ` -- error during template rendering
395406- ` "watcher getter" ` / ` "watcher callback" ` -- error in a ` watch ` or ` watchEffect `
@@ -405,12 +416,12 @@ map it to a structured `errorOrigin` field with a normalized category (e.g. `"li
405416
406417``` json
407418{
408- "context" : {
409- "vue" : {
410- "info" : " mounted hook" ,
411- "errorOrigin" : " lifecycle"
412- }
419+ "context" : {
420+ "vue" : {
421+ "info" : " mounted hook" ,
422+ "errorOrigin" : " lifecycle"
413423 }
424+ }
414425}
415426```
416427
@@ -446,14 +457,14 @@ feature is primarily useful during development and staging, not production.
446457
447458``` json
448459{
449- "context" : {
450- "vue" : {
451- "type" : " warning" ,
452- "info" : " Invalid prop: type check failed for prop \" count\" . Expected Number, got String." ,
453- "componentName" : " Counter" ,
454- "componentTrace" : " found in\n ---> <Counter> at src/Counter.vue\n <App> at src/App.vue"
455- }
460+ "context" : {
461+ "vue" : {
462+ "type" : " warning" ,
463+ "info" : " Invalid prop: type check failed for prop \" count\" . Expected Number, got String." ,
464+ "componentName" : " Counter" ,
465+ "componentTrace" : " found in\n ---> <Counter> at src/Counter.vue\n <App> at src/App.vue"
456466 }
467+ }
457468}
458469```
459470
@@ -480,19 +491,26 @@ flareVue(app);
480491
481492``` json
482493{
483- "context" : {
484- "vue" : {
485- "route" : {
486- "name" : " user-profile" ,
487- "path" : " /users/42" ,
488- "fullPath" : " /users/42?tab=settings" ,
489- "params" : { "id" : " 42" },
490- "query" : { "tab" : " settings" },
491- "hash" : " " ,
492- "matched" : [" AppLayout" , " UserProfile" ]
493- }
494- }
494+ "context" : {
495+ "vue" : {
496+ "route" : {
497+ "name" : " user-profile" ,
498+ "path" : " /users/42" ,
499+ "fullPath" : " /users/42?tab=settings" ,
500+ "params" : {
501+ "id" : " 42"
502+ },
503+ "query" : {
504+ "tab" : " settings"
505+ },
506+ "hash" : " " ,
507+ "matched" : [
508+ " AppLayout" ,
509+ " UserProfile"
510+ ]
511+ }
495512 }
513+ }
496514}
497515```
498516
0 commit comments