diff --git a/src/runtime/index.ts b/src/runtime/index.ts index 0973b93f1e..339cfee39f 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 ae80ae38c1..74facf5b45 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 0ca3e4306d..5157c90fbb 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 e3d7181fcb..14dc9bac25 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 d8fbf15f0a..7fe07e2c7d 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 0000000000..85b0acdd26 --- /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 0000000000..7c645e42fb --- /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 0000000000..638f43091f --- /dev/null +++ b/test/runtime/samples/onerror-fires-when-error/main.svelte @@ -0,0 +1,16 @@ + + +{#if error} +
{error.message}
+{:else} +
{getWidget()}
+{/if}