diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 3f485f82e1..9e42432d73 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -1,7 +1,7 @@ import Renderer from './Renderer'; import Wrapper from './wrappers/shared/Wrapper'; import { b, x } from 'code-red'; -import { Node, Identifier, ArrayPattern } from 'estree'; +import { Node, Identifier, ArrayPattern, Literal, CallExpression } from 'estree'; import { is_head } from './wrappers/shared/is_head'; export interface BlockOptions { @@ -450,45 +450,51 @@ export default class Block { : fn; } - 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', - name: `#dispose${chunk}` - }; - - this.add_variable(dispose); - - if (this.event_listeners.length === 1) { - this.chunks.mount.push( - b` - if (!#mounted) { - ${dispose} = ${this.event_listeners[0]}; - #mounted = true; - } - ` - ); - - this.chunks.destroy.push( - b`${dispose}();` - ); + render_listeners() { + if (!this.event_listeners.length) return; + const mounted = this.alias(`mounted`); + this.add_variable(mounted, x`false`); + + const mount = []; + const destroy = []; + + this.event_listeners.forEach((node) => { + if ( + isCallExpression(node) && + node.callee.type === "Identifier" && + node.callee.name === "@listen" + ) { + // b`@listen(ref, "type", args);` + const listener = this.get_unique_name(`${(node.arguments[1] as Literal).value}_listener`); + this.add_variable(listener); + mount.push(b`${listener} = ${node};`); + destroy.push(b`${listener}();`) + } else if ( + node.type === "AssignmentExpression" && + node.left.type === "Identifier" && + node.left.name.endsWith("_action") + ) { + // b`identifier = use_action(args);` + mount.push(node); + destroy.push(b`if (${node.left} && typeof ${node.left}.destroy === "function") ${node.left}.destroy();`) } else { - this.chunks.mount.push(b` - if (!#mounted) { - ${dispose} = [ - ${this.event_listeners} - ]; - #mounted = true; - } - `); - - this.chunks.destroy.push( - b`${dispose}.forEach((#v) => #v());` - ); + throw new Error(`Forgot to specify logic for event_listener handling`); } - } + }); + + this.chunks.mount.push(b` + if (!${mounted}) { + ${mount} + ${mounted} = true; + } + `); + this.chunks.destroy.push( + b` + ${destroy} + ${mounted} = false; + ` + ); } -} \ No newline at end of file +} + +const isCallExpression = (node): node is CallExpression => node.type === "CallExpression" \ No newline at end of file diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index b66c34a6b4..7bcc6eada7 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -111,7 +111,7 @@ export default function dom( }` : null; - const k = set ? b`let #k;` : null + const k = uses_$$ ? b`let #k;` : null const accessors = []; const not_equal = component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`; diff --git a/src/compiler/compile/render_dom/wrappers/Head.ts b/src/compiler/compile/render_dom/wrappers/Head.ts index 9dccb54269..d70aefdbff 100644 --- a/src/compiler/compile/render_dom/wrappers/Head.ts +++ b/src/compiler/compile/render_dom/wrappers/Head.ts @@ -43,7 +43,7 @@ export default class HeadWrapper extends Wrapper { if (nodes && this.renderer.options.hydratable) { block.chunks.claim.push( - b`${nodes}.forEach(@detach);` + b`for(let #i = 0;#i < ${nodes}.length; #i++) @detach(${nodes}[#i]);` ); } } 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 c3172631db..43730a7a2a 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -1,7 +1,6 @@ import { b, x } from 'code-red'; import Block from '../../Block'; import Action from '../../../nodes/Action'; - export default function add_actions( block: Block, target: string, @@ -9,7 +8,6 @@ export default function add_actions( ) { actions.forEach(action => add_action(block, target, action)); } - export function add_action(block: Block, target: string, action: Action) { const { expression } = action; let snippet; @@ -20,27 +18,24 @@ export function add_action(block: Block, target: string, action: Action) { dependencies = expression.dynamic_dependencies(); } - const id = block.get_unique_name( - `${action.name.replace(/[^a-zA-Z0-9_$]/g, '_')}_action` - ); - + const id = block.get_unique_name(`${action.name.replace(/[^a-zA-Z0-9_$]/g, '_')}_action`); block.add_variable(id); const fn = block.renderer.reference(action.name); - block.event_listeners.push( - x`(${id} = ${fn}.call(null, ${target}, ${snippet})) && 'function' === typeof ${id}.destroy ? ${id}.destroy : @noop` - ); + const subscriber = x`${id} = ${fn}.call(null, ${target}, ${snippet})`; + + block.event_listeners.push(subscriber); if (dependencies && dependencies.length > 0) { let condition = x`${id} && "function" === typeof ${id}.update`; if (dependencies.length > 0) { - condition = x`${condition} && ${block.renderer.dirty(dependencies)}`; + condition = x`${block.renderer.dirty(dependencies)} && ${condition}`; } block.chunks.update.push( b`if (${condition}) ${id}.update.call(null, ${snippet});` ); } -} +} \ No newline at end of file