Skip to content

Commit

Permalink
better hydration for only html tag
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau committed Apr 15, 2022
1 parent 5466925 commit 3b1064b
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 13 deletions.
12 changes: 7 additions & 5 deletions src/compiler/compile/render_dom/wrappers/Element/index.ts
Expand Up @@ -363,13 +363,15 @@ export default class ElementWrapper extends Wrapper {

const { can_use_textcontent, can_optimise_to_html_string } = this.node;

const to_optimise_hydration = can_optimise_to_html_string || (!is_head(parent_node) && this.node.children.length === 1 && this.node.children[0].type === 'RawMustacheTag');

if (hydratable) {
if (parent_nodes) {
block.chunks.claim.push(b`
${node} = ${this.get_claim_statement(block, parent_nodes, can_optimise_to_html_string)};
${node} = ${this.get_claim_statement(block, parent_nodes, to_optimise_hydration)};
`);

if (!can_optimise_to_html_string && !this.void && this.node.children.length > 0) {
if (!to_optimise_hydration && !this.void && this.node.children.length > 0) {
block.chunks.claim.push(b`
var ${nodes} = ${children};
`);
Expand Down Expand Up @@ -477,7 +479,7 @@ export default class ElementWrapper extends Wrapper {
this.add_styles(block);
this.add_manual_style_scoping(block);

if (nodes && hydratable && !this.void && !can_optimise_to_html_string) {
if (nodes && hydratable && !this.void && !to_optimise_hydration) {
block.chunks.claim.push(
b`${this.node.children.length > 0 ? nodes : children}.forEach(@detach);`
);
Expand Down Expand Up @@ -513,7 +515,7 @@ export default class ElementWrapper extends Wrapper {
return x`@element(${reference})`;
}

get_claim_statement(block: Block, nodes: Identifier, can_optimise_to_html_string: boolean) {
get_claim_statement(block: Block, nodes: Identifier, to_optimise_hydration: boolean) {
const attributes = this.attributes
.filter((attr) => !(attr instanceof SpreadAttributeWrapper) && !attr.property_name)
.map((attr) => p`${(attr as StyleAttributeWrapper | AttributeWrapper).name}: true`);
Expand All @@ -531,7 +533,7 @@ export default class ElementWrapper extends Wrapper {
reference = x`(${this.node.tag_expr.manipulate(block)} || 'null').toUpperCase()`;
}

if (can_optimise_to_html_string) {
if (to_optimise_hydration) {
attributes.push(p`["data-svelte"]: true`);
}

Expand Down
3 changes: 2 additions & 1 deletion src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts
Expand Up @@ -7,6 +7,7 @@ import MustacheTag from '../../nodes/MustacheTag';
import RawMustacheTag from '../../nodes/RawMustacheTag';
import { is_head } from './shared/is_head';
import { Identifier } from 'estree';
import hash from '../../utils/hash';

export default class RawMustacheTagWrapper extends Tag {
var: Identifier = { type: 'Identifier', name: 'raw' };
Expand All @@ -33,7 +34,7 @@ export default class RawMustacheTagWrapper extends Tag {
content => insert(content)
);

block.chunks.mount.push(insert(init));
block.chunks.mount.push(b`if (${parent_node}.getAttribute("data-svelte") !== "${hash(JSON.stringify(this.node.expression.node))}") ${insert(init)}`);
} else {
const needs_anchor = in_head || (this.next ? !this.next.is_dom_node() : (!this.parent || !this.parent.is_dom_node()));

Expand Down
1 change: 1 addition & 0 deletions src/compiler/compile/render_ssr/Renderer.ts
Expand Up @@ -47,6 +47,7 @@ export interface RenderOptions extends CompileOptions{
locate: (c: number) => { line: number; column: number };
head_id?: string;
has_added_svelte_hash?: boolean;
optimised_html_hydration?: boolean;
}

export default class Renderer {
Expand Down
8 changes: 5 additions & 3 deletions src/compiler/compile/render_ssr/handlers/Element.ts
Expand Up @@ -10,6 +10,7 @@ import fix_attribute_casing from '../../render_dom/wrappers/Element/fix_attribut
import { namespaces } from '../../../utils/namespaces';
import { start_newline } from '../../../utils/patterns';
import { Expression as ESExpression } from 'estree';
import hash from '../../utils/hash';

export default function (node: Element, renderer: Renderer, options: RenderOptions) {

Expand Down Expand Up @@ -156,9 +157,10 @@ export default function (node: Element, renderer: Renderer, options: RenderOptio
if (options.hydratable) {
if (options.head_id) {
renderer.add_string(` data-svelte="${options.head_id}"`);
}

if (node.can_optimise_to_html_string && !options.has_added_svelte_hash) {
} else if (node.children.length === 1 && node.children[0].type === 'RawMustacheTag') {
renderer.add_string(` data-svelte="${hash(JSON.stringify(node.children[0].expression.node))}"`);
options = { ...options, optimised_html_hydration: true };
} else if (node.can_optimise_to_html_string && !options.has_added_svelte_hash) {
renderer.add_string(` data-svelte="${node.hash()}"`);
options = { ...options, has_added_svelte_hash: true };
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/compile/render_ssr/handlers/HtmlTag.ts
Expand Up @@ -3,7 +3,7 @@ import RawMustacheTag from '../../nodes/RawMustacheTag';
import { Expression } from 'estree';

export default function(node: RawMustacheTag, renderer: Renderer, options: RenderOptions) {
if (options.hydratable) renderer.add_string('<!-- HTML_TAG_START -->');
if (options.hydratable && !options.optimised_html_hydration) renderer.add_string('<!-- HTML_TAG_START -->');
renderer.add_expression(node.expression.node as Expression);
if (options.hydratable) renderer.add_string('<!-- HTML_TAG_END -->');
if (options.hydratable && !options.optimised_html_hydration) renderer.add_string('<!-- HTML_TAG_END -->');
}
7 changes: 7 additions & 0 deletions test/runtime/index.ts
Expand Up @@ -154,6 +154,7 @@ describe('runtime', () => {
window.SvelteComponent = SvelteComponent;

const target = window.document.querySelector('main');
let snapshot = undefined;

if (hydrate && from_ssr_html) {
// ssr into target
Expand All @@ -163,6 +164,11 @@ describe('runtime', () => {
const SsrSvelteComponent = require(`./samples/${dir}/main.svelte`).default;
const { html } = SsrSvelteComponent.render(config.props);
target.innerHTML = html;

if (config.snapshot) {
snapshot = config.snapshot(target);
}

delete compileOptions.generate;
if (config.after_test) config.after_test();
} else {
Expand Down Expand Up @@ -212,6 +218,7 @@ describe('runtime', () => {
component,
mod,
target,
snapshot,
window,
raf,
compileOptions
Expand Down
15 changes: 14 additions & 1 deletion test/runtime/samples/raw-anchor-first-last-child/_config.js
Expand Up @@ -3,11 +3,24 @@ export default {
raw: '<span>foo</span>'
},

test({ assert, component, target }) {
snapshot(target) {
const span = target.querySelector('span');

return {
span
};
},

test({ assert, component, target, snapshot }) {
const span = target.querySelector('span');
assert.ok(!span.previousSibling);
assert.ok(!span.nextSibling);

if (snapshot) {
assert.equal(span, snapshot.span);
}

component.raw = '<span>bar</span>';
assert.htmlEqual(target.innerHTML, '<div><span>bar</span></div>');
}
};
2 changes: 1 addition & 1 deletion test/runtime/samples/raw-mustaches-preserved/_config.js
Expand Up @@ -11,7 +11,7 @@ export default {
const p = target.querySelector('p');

component.raw = '<p>does not change</p>';
assert.equal(target.innerHTML, '<div><p>does not change</p></div>');
assert.htmlEqual(target.innerHTML, '<div><p>does not change</p></div>');
assert.strictEqual(target.querySelector('p'), p);
}
};

0 comments on commit 3b1064b

Please sign in to comment.