11import { UNINITIALIZED } from '../../../constants.js' ;
22import { snapshot } from '../../shared/clone.js' ;
3- import { inspect_effect , validate_effect } from '../reactivity/effects.js' ;
3+ import { inspect_effect , render_effect , validate_effect } from '../reactivity/effects.js' ;
44import { untrack } from '../runtime.js' ;
55
66/**
@@ -12,29 +12,44 @@ export function inspect(get_value, inspector = console.log) {
1212 validate_effect ( '$inspect' ) ;
1313
1414 let initial = true ;
15+ let error = /** @type {any } */ ( UNINITIALIZED ) ;
1516
17+ // Inspect effects runs synchronously so that we can capture useful
18+ // stack traces. As a consequence, reading the value might result
19+ // in an error (an `$inspect(object.property)` will run before the
20+ // `{#if object}...{/if}` that contains it)
1621 inspect_effect ( ( ) => {
17- /** @type {any } */
18- var value = UNINITIALIZED ;
19-
20- // Capturing the value might result in an exception due to the inspect effect being
21- // sync and thus operating on stale data. In the case we encounter an exception we
22- // can bail-out of reporting the value. Instead we simply console.error the error
23- // so at least it's known that an error occured, but we don't stop execution
2422 try {
25- value = get_value ( ) ;
26- } catch ( error ) {
27- // eslint-disable-next-line no-console
28- console . error ( error ) ;
23+ var value = get_value ( ) ;
24+ } catch ( e ) {
25+ error = e ;
26+ return ;
2927 }
3028
31- if ( value !== UNINITIALIZED ) {
32- var snap = snapshot ( value , true ) ;
33- untrack ( ( ) => {
34- inspector ( initial ? 'init' : 'update' , ...snap ) ;
35- } ) ;
36- }
29+ var snap = snapshot ( value , true ) ;
30+ untrack ( ( ) => {
31+ inspector ( initial ? 'init' : 'update' , ...snap ) ;
32+ } ) ;
3733
3834 initial = false ;
3935 } ) ;
36+
37+ // If an error occurs, we store it (along with its stack trace).
38+ // If the render effect subsequently runs, we log the error,
39+ // but if it doesn't run it's because the `$inspect` was
40+ // destroyed, meaning we don't need to bother
41+ render_effect ( ( ) => {
42+ try {
43+ // call `get_value` so that this runs alongside the inspect effect
44+ get_value ( ) ;
45+ } catch {
46+ // ignore
47+ }
48+
49+ if ( error !== UNINITIALIZED ) {
50+ // eslint-disable-next-line no-console
51+ console . error ( error ) ;
52+ error = UNINITIALIZED ;
53+ }
54+ } ) ;
4055}
0 commit comments