From e3112a471174f7f1366e3e69b389e99d32358694 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Wed, 16 Sep 2020 16:13:50 +0800 Subject: [PATCH] only recreate when the expression value changed --- .../compile/render_dom/wrappers/KeyBlock.ts | 96 +++++++++++-------- test/runtime/samples/key-block-2/_config.js | 14 +++ test/runtime/samples/key-block-2/main.svelte | 8 ++ .../key-block-array-immutable/_config.js | 15 +++ .../key-block-array-immutable/main.svelte | 14 +++ .../samples/key-block-array/_config.js | 15 +++ .../samples/key-block-array/main.svelte | 12 +++ .../samples/key-block-expression-2/_config.js | 18 ++++ .../key-block-expression-2/main.svelte | 17 ++++ .../samples/key-block-expression/_config.js | 28 ++++++ .../main.svelte | 2 +- .../samples/key-block-multiple/_config.js | 21 ---- test/runtime/samples/key-block/_config.js | 18 ++-- test/runtime/samples/key-block/main.svelte | 6 +- 14 files changed, 213 insertions(+), 71 deletions(-) create mode 100644 test/runtime/samples/key-block-2/_config.js create mode 100644 test/runtime/samples/key-block-2/main.svelte create mode 100644 test/runtime/samples/key-block-array-immutable/_config.js create mode 100644 test/runtime/samples/key-block-array-immutable/main.svelte create mode 100644 test/runtime/samples/key-block-array/_config.js create mode 100644 test/runtime/samples/key-block-array/main.svelte create mode 100644 test/runtime/samples/key-block-expression-2/_config.js create mode 100644 test/runtime/samples/key-block-expression-2/main.svelte create mode 100644 test/runtime/samples/key-block-expression/_config.js rename test/runtime/samples/{key-block-multiple => key-block-expression}/main.svelte (80%) delete mode 100644 test/runtime/samples/key-block-multiple/_config.js diff --git a/src/compiler/compile/render_dom/wrappers/KeyBlock.ts b/src/compiler/compile/render_dom/wrappers/KeyBlock.ts index 1f33b39196..359fb6946f 100644 --- a/src/compiler/compile/render_dom/wrappers/KeyBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/KeyBlock.ts @@ -30,12 +30,16 @@ export default class KeyBlockWrapper extends Wrapper { this.dependencies = node.expression.dynamic_dependencies(); - this.block = block.child({ - comment: create_debugging_comment(node, renderer.component), - name: renderer.component.get_unique_name("create_key_block"), - type: "key" - }); + if (this.dependencies.length) { + block = block.child({ + comment: create_debugging_comment(node, renderer.component), + name: renderer.component.get_unique_name("create_key_block"), + type: "key" + }); + renderer.blocks.push(block); + } + this.block = block; this.fragment = new FragmentWrapper( renderer, this.block, @@ -44,11 +48,21 @@ export default class KeyBlockWrapper extends Wrapper { strip_whitespace, next_sibling ); - - renderer.blocks.push(this.block); } render(block: Block, parent_node: Identifier, parent_nodes: Identifier) { + if (this.dependencies.length === 0) { + this.render_static_key(block, parent_node, parent_nodes); + } else { + this.render_dynamic_key(block, parent_node, parent_nodes); + } + } + + render_static_key(_block: Block, parent_node: Identifier, parent_nodes: Identifier) { + this.fragment.render(this.block, parent_node, parent_nodes); + } + + render_dynamic_key(block: Block, parent_node: Identifier, parent_nodes: Identifier) { this.fragment.render( this.block, null, @@ -60,6 +74,13 @@ export default class KeyBlockWrapper extends Wrapper { ); const dynamic = this.block.has_update_method; + const previous_key = block.get_unique_name('previous_key'); + const snippet = this.node.expression.manipulate(block); + block.add_variable(previous_key, snippet); + + const not_equal = this.renderer.component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`; + const condition = x`${this.renderer.dirty(this.dependencies)} && ${not_equal}(${previous_key}, ${previous_key} = ${snippet})`; + block.chunks.init.push(b` let ${this.var} = ${this.block.name}(#ctx); `); @@ -73,41 +94,36 @@ export default class KeyBlockWrapper extends Wrapper { });` ); const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes); + const body = b` + ${ + has_transitions + ? b` + @group_outros(); + @transition_out(${this.var}, 1, 1, @noop); + @check_outros(); + ` + : b`${this.var}.d(1);` + } + ${this.var} = ${this.block.name}(#ctx); + ${this.var}.c(); + ${has_transitions && b`@transition_in(${this.var})`} + ${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor}); + `; - if (this.dependencies.length) { - const body = b` - ${ - has_transitions - ? b` - @group_outros(); - @transition_out(${this.var}, 1, 1, @noop); - @check_outros(); - ` - : b`${this.var}.d(1);` + if (dynamic) { + block.chunks.update.push(b` + if (${condition}) { + ${body} + } else { + ${this.var}.p(#ctx, #dirty); } - ${this.var} = ${this.block.name}(#ctx); - ${this.var}.c(); - ${has_transitions && b`@transition_in(${this.var})`} - ${this.var}.m(${this.get_update_mount_node(anchor)}, ${anchor}); - `; - - if (dynamic) { - block.chunks.update.push(b` - if (${this.renderer.dirty(this.dependencies)}) { - ${body} - } else { - ${this.var}.p(#ctx, #dirty); - } - `); - } else { - block.chunks.update.push(b` - if (${this.renderer.dirty(this.dependencies)}) { - ${body} - } - `); - } - } else if (dynamic) { - block.chunks.update.push(b`${this.var}.p(#ctx, #dirty);`); + `); + } else { + block.chunks.update.push(b` + if (${condition}) { + ${body} + } + `); } if (has_transitions) { diff --git a/test/runtime/samples/key-block-2/_config.js b/test/runtime/samples/key-block-2/_config.js new file mode 100644 index 0000000000..a7c53bd91f --- /dev/null +++ b/test/runtime/samples/key-block-2/_config.js @@ -0,0 +1,14 @@ +// with reactive content beside `key` +export default { + html: `
00
`, + async test({ assert, component, target, window }) { + const div = target.querySelector('div'); + component.reactive = 2; + assert.htmlEqual(target.innerHTML, `
02
`); + assert.strictEqual(div, target.querySelector('div')); + + component.value = 5; + assert.htmlEqual(target.innerHTML, `
52
`); + assert.notStrictEqual(div, target.querySelector('div')); + } +}; diff --git a/test/runtime/samples/key-block-2/main.svelte b/test/runtime/samples/key-block-2/main.svelte new file mode 100644 index 0000000000..466d20b10a --- /dev/null +++ b/test/runtime/samples/key-block-2/main.svelte @@ -0,0 +1,8 @@ + + +{#key value} +
{value}{reactive}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-array-immutable/_config.js b/test/runtime/samples/key-block-array-immutable/_config.js new file mode 100644 index 0000000000..fb94556c0f --- /dev/null +++ b/test/runtime/samples/key-block-array-immutable/_config.js @@ -0,0 +1,15 @@ +export default { + html: `
1
`, + async test({ assert, component, target, window }) { + let div = target.querySelector("div"); + await component.append(2); + assert.htmlEqual(target.innerHTML, `
1
`); + assert.strictEqual(div, target.querySelector("div")); + + div = target.querySelector("div"); + + component.array = [3, 4]; + assert.htmlEqual(target.innerHTML, `
3,4
`); + assert.notStrictEqual(div, target.querySelector("div")); + } +}; diff --git a/test/runtime/samples/key-block-array-immutable/main.svelte b/test/runtime/samples/key-block-array-immutable/main.svelte new file mode 100644 index 0000000000..e666275af4 --- /dev/null +++ b/test/runtime/samples/key-block-array-immutable/main.svelte @@ -0,0 +1,14 @@ + + + + +{#key array} +
{array.join(',')}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-array/_config.js b/test/runtime/samples/key-block-array/_config.js new file mode 100644 index 0000000000..05d5fe9995 --- /dev/null +++ b/test/runtime/samples/key-block-array/_config.js @@ -0,0 +1,15 @@ +export default { + html: `
1
`, + async test({ assert, component, target, window }) { + let div = target.querySelector("div"); + await component.append(2); + assert.htmlEqual(target.innerHTML, `
1,2
`); + assert.notStrictEqual(div, target.querySelector("div")); + + div = target.querySelector("div"); + + component.array = [3, 4]; + assert.htmlEqual(target.innerHTML, `
3,4
`); + assert.notStrictEqual(div, target.querySelector("div")); + } +}; diff --git a/test/runtime/samples/key-block-array/main.svelte b/test/runtime/samples/key-block-array/main.svelte new file mode 100644 index 0000000000..5a4054b043 --- /dev/null +++ b/test/runtime/samples/key-block-array/main.svelte @@ -0,0 +1,12 @@ + + +{#key array} +
{array.join(',')}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-expression-2/_config.js b/test/runtime/samples/key-block-expression-2/_config.js new file mode 100644 index 0000000000..236c72fa3d --- /dev/null +++ b/test/runtime/samples/key-block-expression-2/_config.js @@ -0,0 +1,18 @@ +export default { + html: `
3
`, + async test({ assert, component, target, window }) { + const div = target.querySelector("div"); + + await component.mutate(); + assert.htmlEqual(target.innerHTML, `
5
`); + assert.strictEqual(div, target.querySelector("div")); + + await component.reassign(); + assert.htmlEqual(target.innerHTML, `
7
`); + assert.strictEqual(div, target.querySelector("div")); + + await component.changeKey(); + assert.htmlEqual(target.innerHTML, `
7
`); + assert.notStrictEqual(div, target.querySelector("div")); + } +}; diff --git a/test/runtime/samples/key-block-expression-2/main.svelte b/test/runtime/samples/key-block-expression-2/main.svelte new file mode 100644 index 0000000000..5525f63761 --- /dev/null +++ b/test/runtime/samples/key-block-expression-2/main.svelte @@ -0,0 +1,17 @@ + + +{#key obj.key} +
{obj.value}
+{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-expression/_config.js b/test/runtime/samples/key-block-expression/_config.js new file mode 100644 index 0000000000..78890988ea --- /dev/null +++ b/test/runtime/samples/key-block-expression/_config.js @@ -0,0 +1,28 @@ +export default { + html: `
000
`, + async test({ assert, component, target, window }) { + let div = target.querySelector("div"); + component.value = 2; + assert.htmlEqual(target.innerHTML, `
200
`); + assert.notStrictEqual(div, target.querySelector("div")); + + div = target.querySelector("div"); + + component.anotherValue = 5; + assert.htmlEqual(target.innerHTML, `
250
`); + assert.notStrictEqual(div, target.querySelector("div")); + + div = target.querySelector("div"); + + component.thirdValue = 9; + assert.htmlEqual(target.innerHTML, `
259
`); + assert.strictEqual(div, target.querySelector("div")); + + // make dirty while maintain the value of `value + anotherValue` + // should update the content, but not recreate the elements + await component.$set({ value: 4, anotherValue: 3 }); + + assert.htmlEqual(target.innerHTML, `
439
`); + assert.strictEqual(div, target.querySelector("div")); + } +}; diff --git a/test/runtime/samples/key-block-multiple/main.svelte b/test/runtime/samples/key-block-expression/main.svelte similarity index 80% rename from test/runtime/samples/key-block-multiple/main.svelte rename to test/runtime/samples/key-block-expression/main.svelte index 88c9213506..dd752e8b8f 100644 --- a/test/runtime/samples/key-block-multiple/main.svelte +++ b/test/runtime/samples/key-block-expression/main.svelte @@ -4,6 +4,6 @@ export let thirdValue = 0; -{#key [value, anotherValue]} +{#key value + anotherValue}
{value}{anotherValue}{thirdValue}
{/key} \ No newline at end of file diff --git a/test/runtime/samples/key-block-multiple/_config.js b/test/runtime/samples/key-block-multiple/_config.js deleted file mode 100644 index 7a8314d8ff..0000000000 --- a/test/runtime/samples/key-block-multiple/_config.js +++ /dev/null @@ -1,21 +0,0 @@ -export default { - html: `
000
`, - async test({ assert, component, target, window }) { - let div = target.querySelector('div'); - component.value = 2; - assert.htmlEqual(target.innerHTML, `
200
`); - assert.notStrictEqual(div, target.querySelector('div')); - - div = target.querySelector('div'); - - component.anotherValue = 5; - assert.htmlEqual(target.innerHTML, `
250
`); - assert.notStrictEqual(div, target.querySelector('div')); - - div = target.querySelector('div'); - - component.thirdValue = 9; - assert.htmlEqual(target.innerHTML, `
259
`); - assert.strictEqual(div, target.querySelector('div')); - } -}; diff --git a/test/runtime/samples/key-block/_config.js b/test/runtime/samples/key-block/_config.js index 8524117c8d..ad206c3b06 100644 --- a/test/runtime/samples/key-block/_config.js +++ b/test/runtime/samples/key-block/_config.js @@ -1,13 +1,17 @@ export default { - html: `
00
`, + html: `
0
0
`, async test({ assert, component, target, window }) { - const div = target.querySelector('div'); - component.reactive = 2; - assert.htmlEqual(target.innerHTML, `
02
`); - assert.strictEqual(div, target.querySelector('div')); + let [div1, div2] = target.querySelectorAll('div'); component.value = 5; - assert.htmlEqual(target.innerHTML, `
52
`); - assert.notStrictEqual(div, target.querySelector('div')); + assert.htmlEqual(target.innerHTML, `
5
0
`); + assert.notStrictEqual(div1, target.querySelectorAll('div')[0]); + assert.strictEqual(div2, target.querySelectorAll('div')[1]); + [div1, div2] = target.querySelectorAll('div'); + + component.reactive = 10; + assert.htmlEqual(target.innerHTML, `
5
10
`); + assert.strictEqual(div1, target.querySelectorAll('div')[0]); + assert.strictEqual(div2, target.querySelectorAll('div')[1]); } }; diff --git a/test/runtime/samples/key-block/main.svelte b/test/runtime/samples/key-block/main.svelte index 466d20b10a..ac3c340770 100644 --- a/test/runtime/samples/key-block/main.svelte +++ b/test/runtime/samples/key-block/main.svelte @@ -4,5 +4,7 @@ {#key value} -
{value}{reactive}
-{/key} \ No newline at end of file +
{value}
+{/key} + +
{reactive}
\ No newline at end of file