From a2c68328a02790ddb024b4846f638b030a378795 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 4 Dec 2018 18:20:56 -0500 Subject: [PATCH] hoist declarations where possible --- src/compile/Component.ts | 116 +++++++++++++++++++++++++++++++- src/utils/annotateWithScopes.ts | 2 +- src/utils/remove_indentation.ts | 33 +++++++++ 3 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 src/utils/remove_indentation.ts diff --git a/src/compile/Component.ts b/src/compile/Component.ts index c0c0d321b1..de43f13646 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -19,6 +19,7 @@ import addToSet from '../utils/addToSet'; import isReference from 'is-reference'; import TemplateScope from './nodes/shared/TemplateScope'; import fuzzymatch from '../utils/fuzzymatch'; +import { remove_indentation } from '../utils/remove_indentation'; type Meta = { namespace?: string; @@ -74,6 +75,8 @@ export default class Component { props: Array<{ name: string, as: string }> = []; writable_declarations: Set = new Set(); initialised_declarations: Set = new Set(); + hoistable_names: Set = new Set(); + hoistable_nodes: Set = new Set(); node_for_declaration: Map = new Map(); module_exports: Array<{ name: string, as: string }> = []; partly_hoisted: string[] = []; @@ -479,13 +482,26 @@ export default class Component { } extract_javascript(script) { + if (script.content.body.length === this.hoistable_nodes.size) return null; + let a = script.content.start; while (/\s/.test(this.source[a])) a += 1; + let result = ''; + + script.content.body.forEach(node => { + if (this.hoistable_nodes.has(node)) { + result += `[✂${a}-${node.start}✂]/* HOISTED */`; + a = node.end; + } + }); + let b = script.content.end; while (/\s/.test(this.source[b - 1])) b -= 1; - return a !== b ? `[✂${a}-${b}✂]` : null; + if (a !== b) result += `[✂${a}-${b}✂]`; + + return result || null; } walk_module_js() { @@ -529,6 +545,7 @@ export default class Component { this.extract_imports_and_exports(script.content, this.imports, this.props); this.rewrite_props(); + this.hoist_instance_declarations(); this.javascript = this.extract_javascript(script); } @@ -637,6 +654,103 @@ export default class Component { }); } + hoist_instance_declarations() { + // we can safely hoist `const` declarations that are + // initialised to literals, and functions that don't + // reference instance variables other than other + // hoistable functions. TODO others? + + const { hoistable_names, hoistable_nodes } = this; + + const top_level_function_declarations = new Map(); + + this.instance_script.content.body.forEach(node => { + if (node.kind === 'const') { // TODO or let or var, if never reassigned in