From c1eda75ba0012e9daf12a24a1ef4557a3aa97100 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 28 Aug 2017 11:00:53 -0400 Subject: [PATCH] wrap fallback hydration code in conditional --- src/generators/dom/visitors/Slot.ts | 2 + src/utils/CodeBuilder.ts | 49 ++++++++++++++++--- test/helpers.js | 16 +++--- .../component-slot-fallback/Nested.html | 6 +-- .../component-slot-fallback/_config.js | 6 +-- .../samples/component-slot-fallback/main.html | 4 +- 6 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/generators/dom/visitors/Slot.ts b/src/generators/dom/visitors/Slot.ts index fecf31d0fd..9a059c138e 100644 --- a/src/generators/dom/visitors/Slot.ts +++ b/src/generators/dom/visitors/Slot.ts @@ -51,6 +51,7 @@ export default function visitSlot( ); block.builders.create.pushCondition(`!${content_name}`); + block.builders.hydrate.pushCondition(`!${content_name}`); block.builders.mount.pushCondition(`!${content_name}`); block.builders.unmount.pushCondition(`!${content_name}`); block.builders.destroy.pushCondition(`!${content_name}`); @@ -60,6 +61,7 @@ export default function visitSlot( }); block.builders.create.popCondition(); + block.builders.hydrate.popCondition(); block.builders.mount.popCondition(); block.builders.unmount.popCondition(); block.builders.destroy.popCondition(); diff --git a/src/utils/CodeBuilder.ts b/src/utils/CodeBuilder.ts index 5da11b6d6f..eab930d96e 100644 --- a/src/utils/CodeBuilder.ts +++ b/src/utils/CodeBuilder.ts @@ -5,12 +5,17 @@ enum ChunkType { Block } +interface Condition { + condition: string; + used: boolean; +} + export default class CodeBuilder { result: string; first: ChunkType; last: ChunkType; lastCondition: string; - conditionStack: string[]; + conditionStack: Condition[]; indent: string; constructor(str = '') { @@ -28,6 +33,8 @@ export default class CodeBuilder { } addConditional(condition: string, body: string) { + this.reifyConditions(); + body = body.replace(/^/gm, `${this.indent}\t`); if (condition === this.lastCondition) { @@ -45,6 +52,8 @@ export default class CodeBuilder { } addLine(line: string) { + this.reifyConditions(); + if (this.lastCondition) { this.result += `\n${this.indent}}`; this.lastCondition = null; @@ -63,6 +72,8 @@ export default class CodeBuilder { } addLineAtStart(line: string) { + this.reifyConditions(); + if (this.first === ChunkType.Block) { this.result = `${line}\n\n${this.indent}${this.result}`; } else if (this.first === ChunkType.Line) { @@ -76,6 +87,8 @@ export default class CodeBuilder { } addBlock(block: string) { + this.reifyConditions(); + if (this.indent) block = block.replace(/^/gm, `${this.indent}`); if (this.lastCondition) { @@ -94,6 +107,8 @@ export default class CodeBuilder { } addBlockAtStart(block: string) { + this.reifyConditions(); + if (this.result) { this.result = `${block}\n\n${this.indent}${this.result}`; } else { @@ -109,15 +124,37 @@ export default class CodeBuilder { } pushCondition(condition: string) { - this.conditionStack.push(condition); - this.addLine(`if (${condition}) {`); - this.indent = repeat('\t', this.conditionStack.length); + this.conditionStack.push({ condition, used: false }); } popCondition() { - this.conditionStack.pop(); + const { used } = this.conditionStack.pop(); + this.indent = repeat('\t', this.conditionStack.length); - this.addLine('}'); + if (used) this.addLine('}'); + } + + reifyConditions() { + for (let i = 0; i < this.conditionStack.length; i += 1) { + const condition = this.conditionStack[i]; + if (!condition.used) { + const line = `if (${condition.condition}) {`; + + if (this.last === ChunkType.Block) { + this.result += `\n\n${this.indent}${line}`; + } else if (this.last === ChunkType.Line) { + this.result += `\n${this.indent}${line}`; + } else { + this.result += line; + } + + this.last = ChunkType.Line; + if (!this.first) this.first = ChunkType.Line; + + this.indent = repeat('\t', this.conditionStack.length); + condition.used = true; + } + } } toString() { diff --git a/test/helpers.js b/test/helpers.js index a1175991e4..6f33327292 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -120,12 +120,16 @@ function cleanChildren(node) { } export function normalizeHtml(window, html) { - const node = window.document.createElement('div'); - node.innerHTML = html - .replace(/>[\s\r\n]+<') - .trim(); - cleanChildren(node, ''); - return node.innerHTML.replace(/<\/?noscript\/?>/g, ''); + try { + const node = window.document.createElement('div'); + node.innerHTML = html + .replace(/>[\s\r\n]+<') + .trim(); + cleanChildren(node, ''); + return node.innerHTML.replace(/<\/?noscript\/?>/g, ''); + } catch (err) { + throw new Error(`Failed to normalize HTML:\n${html}`); + } } export function setupHtmlEqual() { diff --git a/test/runtime/samples/component-slot-fallback/Nested.html b/test/runtime/samples/component-slot-fallback/Nested.html index 8b6bac7ea8..dcaf46e042 100644 --- a/test/runtime/samples/component-slot-fallback/Nested.html +++ b/test/runtime/samples/component-slot-fallback/Nested.html @@ -1,5 +1,5 @@
- default fallback content - bar fallback content - foo fallback content +

default fallback content

+

bar fallback content

+

foo fallback content

\ No newline at end of file diff --git a/test/runtime/samples/component-slot-fallback/_config.js b/test/runtime/samples/component-slot-fallback/_config.js index 6f62c5e46a..14e7ad403b 100644 --- a/test/runtime/samples/component-slot-fallback/_config.js +++ b/test/runtime/samples/component-slot-fallback/_config.js @@ -1,9 +1,9 @@ export default { html: `
- default fallback content - bar fallback content - foo fallback content +

not fallback

+

bar fallback content

+

foo fallback content

` }; diff --git a/test/runtime/samples/component-slot-fallback/main.html b/test/runtime/samples/component-slot-fallback/main.html index f430c2954e..8894e86940 100644 --- a/test/runtime/samples/component-slot-fallback/main.html +++ b/test/runtime/samples/component-slot-fallback/main.html @@ -1,4 +1,6 @@ - + +

not fallback

+