diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 5ff5139b38..fef08b88ef 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -375,6 +375,36 @@ export default class Block { } } + if (properties.create.type === 'FunctionExpression') { + properties.create.body.body = b` + try { + ${properties.create.body.body} + } catch (e) { + @handle_error(@get_current_component(), e); + } + `; + } + + if (properties.mount.type === 'FunctionExpression') { + properties.mount.body.body = b` + try { + ${properties.mount.body.body} + } catch (e) { + @handle_error(@get_current_component(), e); + } + `; + } + + if (properties.hydrate?.type === 'FunctionExpression') { + properties.hydrate.body.body = b` + try { + ${properties.hydrate.body.body} + } catch (e) { + @handle_error(@get_current_component(), e); + } + `; + } + const return_value: any = x`{ key: ${properties.key}, first: ${properties.first}, @@ -395,6 +425,7 @@ export default class Block { const init_declarations = []; const init_statements = []; + const init_functions = []; Array.from(this.variables.values()).forEach(({ id, init }) => { init_declarations.push(b`let ${id};`); @@ -407,9 +438,12 @@ export default class Block { this.chunks.init.forEach(node => { if (Array.isArray(node)) { node.forEach((declaration: any) => { // TODO add type to this - if (declaration.declarations) { + if (declaration.type === 'FunctionDeclaration') { + init_declarations.push(b`let ${declaration.id};`); + init_functions.push(b`${declaration.id} = ${declaration}`); + } else if (declaration.type === 'VariableDeclaration') { declaration.declarations.forEach(({ id, init }) => { - init_declarations.push(b`let ${id}`); + init_declarations.push(b`let ${id}`); // TODO declaration is not always `let` init_statements.push(b`${id} = ${init}`); }); } else { @@ -426,9 +460,11 @@ export default class Block { ${init_declarations} - ${init_statements.length > 0 + ${init_statements.length > 0 || init_functions.length > 0 ? b` try { + ${init_functions} + ${init_statements} } catch (e) { @handle_error(@get_current_component(), e); @@ -490,7 +526,6 @@ export default class Block { render_listeners(chunk: string = '') { if (this.event_listeners.length > 0) { this.add_variable({ type: 'Identifier', name: '#mounted' }); - this.chunks.destroy.push(b`#mounted = false`); const dispose: Identifier = { type: 'Identifier', @@ -499,10 +534,6 @@ export default class Block { this.add_variable(dispose); - this.event_listeners.forEach((event_listener: any) => { - event_listener.arguments[2] = x`@attach_error_handler(${event_listener.arguments[0]}, @get_current_component(), ${event_listener.arguments[2]})`; - }); - if (this.event_listeners.length === 1) { this.chunks.mount.push( b` @@ -514,7 +545,11 @@ export default class Block { ); this.chunks.destroy.push( - b`${dispose}();` + b` + if (#mounted) { + ${dispose}(); + } + ` ); } else { this.chunks.mount.push(b` @@ -530,6 +565,8 @@ export default class Block { b`@run_all(${dispose});` ); } + + this.chunks.destroy.push(b`#mounted = false`); } } } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 226a0d5828..1b8760c162 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -6,7 +6,7 @@ import { walk } from 'estree-walker'; import { extract_names, Scope } from 'periscopic'; import { invalidate } from './invalidate'; import Block from './Block'; -import { ImportDeclaration, ClassDeclaration, FunctionExpression, Node, Statement, ObjectExpression, Expression, Identifier } from 'estree'; +import { ImportDeclaration, ClassDeclaration, FunctionExpression, Node, Statement, ObjectExpression, Expression } from 'estree'; import { apply_preprocessor_sourcemap } from '../../utils/mapped_code'; import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types'; import { flatten } from '../../utils/flatten'; @@ -462,16 +462,12 @@ export default function dom( instance_javascript_with_ctx.push(node); if (Array.isArray(node) && node[0].type === 'VariableDeclaration') { - walk(node[0], { - enter(declaration: Identifier) { - if (declaration.type === 'Identifier' && !initializedIdentifiers.includes(declaration.name)) { - const index = renderer.initial_context.findIndex(member => member.name === declaration.name); - - if (index >= 0) { - node.push(x`#return_values[${index}] = ${declaration}`); - initializedIdentifiers.push(declaration.name); - } - } + node[0].declarations.forEach(({ id }) => { + const index = renderer.initial_context.findIndex(member => member.name === id.name); + + if (index >= 0) { + instance_javascript_with_ctx.push(b`#return_values[${index}] = ${id};`[0]); + initializedIdentifiers.push(id.name); } }); } @@ -481,7 +477,7 @@ export default function dom( const index = renderer.initial_context.findIndex(member => member.name === node.id.name); if (index >= 0) { - instance_javascript_with_ctx.push(x`#return_values[${index}] = ${node.id.name}`); + instance_javascript_with_ctx.push(b`#return_values[${index}] = ${node.id};`[0]); initializedIdentifiers.push(node.id.name); } } @@ -492,6 +488,12 @@ export default function dom( const instance_try_block: any = b` try { + ${reactive_store_declarations} + + ${reactive_store_subscriptions} + + ${resubscribable_reactive_store_unsubscribers} + ${instance_javascript_with_ctx} ${unknown_props_check} @@ -534,12 +536,6 @@ export default function dom( ${rest} - ${reactive_store_declarations} - - ${reactive_store_subscriptions} - - ${resubscribable_reactive_store_unsubscribers} - ${component.slots.size || component.compile_options.dev || uses_slots ? b`let { $$slots: #slots = {}, $$scope } = $$props;` : null} ${component.compile_options.dev && b`@validate_slots('${component.tag}', #slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`} ${compute_slots} diff --git a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts index fc65a9aa5e..eec574478b 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts @@ -67,7 +67,7 @@ export default class EventHandlerWrapper { } block.event_listeners.push( - x`@listen(${target}, "${this.node.name}", ${snippet}, ${args})` + x`@listen(${target}, "${this.node.name}", @attach_error_handler(${target}, @get_current_component(), ${snippet}), ${args})` ); } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index db26b6673c..300695efdc 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -541,7 +541,7 @@ export default class ElementWrapper extends Wrapper { ); } else { block.event_listeners.push( - x`@listen(${this.var}, "${name}", ${callee})` + x`@listen(${this.var}, "${name}", @attach_error_handler(${this.var}, @get_current_component(), ${callee}))` ); } }); diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts index b57820beb3..a0d71c3bc1 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -40,7 +40,7 @@ export function add_action(block: Block, target: string, action: Action) { ); } else { block.event_listeners.push( - x`@action_destroyer(${id} = ${fn}.call(null, ${target}, ${snippet}))` + x`@action_destroyer(${id} = @attach_error_handler(null, @get_current_component(), ${fn}).call(null, ${target}, ${snippet}))` ); } diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index 6f85ae9830..6cfe0f061e 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -182,35 +182,25 @@ export default function ssr( return $$rendered; ` : b` - try { - ${instance_javascript} + ${reactive_declarations} - ${reactive_declarations} + ${reactive_store_unsubscriptions} + + return ${literal};`; + + const blocks = [ + ...injected.map(name => b`let ${name};`), + rest, + slots, + ...reactive_store_declarations, + ...reactive_store_subscriptions, + instance_javascript, + ...parent_bindings, + css.code && b`$$result.css.add(#css);`, + main + ].filter(Boolean); - ${reactive_store_unsubscriptions} - return ${literal}; - } catch (e) { - @handle_error(@get_current_component(), e); - }`; - - const blocks = [ - ...injected.map(name => b`let ${name};`), - rest, - slots, - ...reactive_store_declarations, - ...reactive_store_subscriptions, - // b` - // try { - // ${instance_javascript} - // } catch (e) { - // @handle_error(@get_current_component(), e); - // } - // `, - ...parent_bindings, - css.code && b`$$result.css.add(#css);`, - main - ].filter(Boolean); const js = b` ${css.code ? b` @@ -224,7 +214,11 @@ export default function ssr( ${component.fully_hoisted} const ${name} = @create_ssr_component(($$result, $$props, $$bindings, #slots) => { - ${blocks} + try { + ${blocks} + } catch (e) { + @handle_error(@get_current_component(), e); + } }); `; diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 2928947022..e9e21d4b94 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -109,7 +109,7 @@ function make_dirty(component, i) { export function attach_error_handler(that: any, component, fn) { return (...rest) => { try { - fn.call(that, ...rest); + return fn.call(that, ...rest); } catch (e) { handle_error(component, e); } diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index 8868e38ee2..9e8b2057ca 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -1,4 +1,6 @@ import { Readable } from 'svelte/store'; +import { attach_error_handler } from './Component'; +import { get_current_component } from './lifecycle'; export function noop() {} @@ -185,5 +187,5 @@ export function set_store_value(store, ret, value) { export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); export function action_destroyer(action_result) { - return action_result && is_function(action_result.destroy) ? action_result.destroy : noop; + return action_result && is_function(action_result.destroy) ? attach_error_handler(action_result, get_current_component(), action_result.destroy) : noop; }