From 1135336e88922e5c16053d9a8c7817d20ea6727e Mon Sep 17 00:00:00 2001 From: Chris Pfohl Date: Wed, 18 Sep 2019 11:36:40 -0400 Subject: [PATCH] Failing test for onError handler. Rather than _always_ adding a try/catch this adds a try/catch only when on_error is present. Doesn't currently work because apparently updates and initial renders go through different paths. Also because I need maintainer support to figure this out... --- src/runtime/index.ts | 1 + src/runtime/internal/Component.ts | 2 ++ src/runtime/internal/lifecycle.ts | 4 +++ src/runtime/internal/scheduler.ts | 36 +++++++++++++++---- src/runtime/internal/ssr.ts | 1 + .../onerror-fires-when-error/_config.js | 7 ++++ .../onerror-fires-when-error/container.js | 1 + .../onerror-fires-when-error/main.svelte | 16 +++++++++ 8 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 test/runtime/samples/onerror-fires-when-error/_config.js create mode 100644 test/runtime/samples/onerror-fires-when-error/container.js create mode 100644 test/runtime/samples/onerror-fires-when-error/main.svelte diff --git a/src/runtime/index.ts b/src/runtime/index.ts index 0973b93f1ee7..339cfee39fc4 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -3,6 +3,7 @@ import './ambient'; export { onMount, onDestroy, + onError, beforeUpdate, afterUpdate, setContext, diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index ae80ae38c1f3..74facf5b450d 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -19,6 +19,7 @@ interface T$$ { context: Map; on_mount: any[]; on_destroy: any[]; + on_error: any[]; } export function bind(component, name, callback) { @@ -88,6 +89,7 @@ export function init(component, options, instance, create_fragment, not_equal, p // lifecycle on_mount: [], + on_error: [], on_destroy: [], before_update: [], after_update: [], diff --git a/src/runtime/internal/lifecycle.ts b/src/runtime/internal/lifecycle.ts index 0ca3e4306d1e..5157c90fbb41 100644 --- a/src/runtime/internal/lifecycle.ts +++ b/src/runtime/internal/lifecycle.ts @@ -27,6 +27,10 @@ export function onDestroy(fn) { get_current_component().$$.on_destroy.push(fn); } +export function onError(fn) { + get_current_component().$$.on_error.push(fn); +} + export function createEventDispatcher() { const component = current_component; diff --git a/src/runtime/internal/scheduler.ts b/src/runtime/internal/scheduler.ts index e3d7181fcbec..14dc9bac253c 100644 --- a/src/runtime/internal/scheduler.ts +++ b/src/runtime/internal/scheduler.ts @@ -71,11 +71,35 @@ export function flush() { function update($$) { if ($$.fragment) { - $$.update($$.dirty); - run_all($$.before_update); - $$.fragment.p($$.dirty, $$.ctx); - $$.dirty = null; - - $$.after_update.forEach(add_render_callback); + if ($$.on_error.length == 0) { + exec_update($$); + } else { + try_exec_update($$); + } } } + +function exec_update($$) { + $$.update($$.dirty); + run_all($$.before_update); + $$.fragment.p($$.dirty, $$.ctx); + $$.dirty = null; + + $$.after_update.forEach(add_render_callback); +} + +function try_exec_update($$) { + try { + exec_update($$); + } catch (e) { + let handled = false; + for (let i = 0; i < $$.on_error.length; i += 1) { + const callback = $$.on_error[i]; + const result = callback(e); + if (result !== false) { + handled = true; + } + } + if (!handled) throw e; + } +} \ No newline at end of file diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index d8fbf15f0a3f..7fe07e2c7ddd 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -77,6 +77,7 @@ export function create_ssr_component(fn) { // these will be immediately discarded on_mount: [], + on_error: [], before_update: [], after_update: [], callbacks: blank_object() diff --git a/test/runtime/samples/onerror-fires-when-error/_config.js b/test/runtime/samples/onerror-fires-when-error/_config.js new file mode 100644 index 000000000000..85b0acdd26f7 --- /dev/null +++ b/test/runtime/samples/onerror-fires-when-error/_config.js @@ -0,0 +1,7 @@ +export default { + test({ assert, target }) { + const div = target.querySelector('div'); + + assert.equal('error', div.className); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/onerror-fires-when-error/container.js b/test/runtime/samples/onerror-fires-when-error/container.js new file mode 100644 index 000000000000..7c645e42fb75 --- /dev/null +++ b/test/runtime/samples/onerror-fires-when-error/container.js @@ -0,0 +1 @@ +export default {}; \ No newline at end of file diff --git a/test/runtime/samples/onerror-fires-when-error/main.svelte b/test/runtime/samples/onerror-fires-when-error/main.svelte new file mode 100644 index 000000000000..638f43091f62 --- /dev/null +++ b/test/runtime/samples/onerror-fires-when-error/main.svelte @@ -0,0 +1,16 @@ + + +{#if error} +
{error.message}
+{:else} +
{getWidget()}
+{/if}