fast hydration

pull/4309/head
Avi Marcus 6 years ago
parent 2f81365e44
commit abd55510be

@ -250,7 +250,7 @@ export default class EachBlockWrapper extends Wrapper {
block.add_element(
update_anchor_node as Identifier,
x`@empty()`,
parent_nodes && x`@empty()`,
parent_nodes && x`@claim_text(${parent_nodes}, '')`,
parent_node
);
}
@ -366,7 +366,7 @@ export default class EachBlockWrapper extends Wrapper {
this.block.add_element(
this.block.first,
x`@empty()`,
parent_nodes && x`@empty()`,
parent_nodes && x`@claim_text(#nodes, '')`,
null
);
}

@ -8,7 +8,7 @@ import { escape_html, string_literal } from '../../../utils/stringify';
import TextWrapper from '../Text';
import TagWrapper from '../shared/Tag';
import fix_attribute_casing from './fix_attribute_casing';
import { b, x, p } from 'code-red';
import { b, x } from 'code-red';
import { namespaces } from '../../../../utils/namespaces';
import AttributeWrapper from './Attribute';
import StyleAttributeWrapper from './StyleAttribute';
@ -386,7 +386,7 @@ export default class ElementWrapper extends Wrapper {
if (nodes && this.renderer.options.hydratable && !this.void) {
block.chunks.claim.push(
b`${this.node.children.length > 0 ? nodes : children}.forEach(@detach);`
b`${this.node.children.length > 0 ? nodes : children}.children.forEach(@detach);`
);
}
@ -422,17 +422,13 @@ export default class ElementWrapper extends Wrapper {
}
get_claim_statement(nodes: Identifier) {
const attributes = this.node.attributes
.filter((attr) => attr.type === 'Attribute')
.map((attr) => p`${attr.name}: true`);
const name = this.node.namespace
? this.node.name
: this.node.name.toUpperCase();
const svg = this.node.namespace === namespaces.svg ? 1 : null;
return x`@claim_element(${nodes}, "${name}", { ${attributes} }, ${svg})`;
return x`@claim_element(${nodes}, "${name}", null, ${svg})`;
}
add_directives_in_order (block: Block) {

@ -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`${nodes}.children.forEach(@detach);`
);
}
}

@ -239,7 +239,7 @@ export default class IfBlockWrapper extends Wrapper {
block.add_element(
anchor as Identifier,
x`@empty()`,
parent_nodes && x`@empty()`,
parent_nodes && x`@claim_text(${parent_nodes}, '')/*IF242*/`,
parent_node
);
}

@ -22,7 +22,7 @@ export default class RawMustacheTagWrapper extends Tag {
this.not_static_content();
}
render(block: Block, parent_node: Identifier, _parent_nodes: Identifier) {
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
const in_head = is_head(parent_node);
const can_use_innerhtml = !in_head && parent_node && !this.prev && !this.next;
@ -53,11 +53,20 @@ export default class RawMustacheTagWrapper extends Tag {
const update_anchor = in_head ? 'null' : needs_anchor ? html_anchor : this.next ? this.next.var : 'null';
block.chunks.hydrate.push(b`${html_tag} = new @HtmlTag(${init}, ${update_anchor});`);
block.chunks.hydrate.push(b`${html_tag}.a = ${update_anchor};`);
block.chunks.mount.push(b`${html_tag}.m(${parent_node || '#target'}, ${parent_node ? null : 'anchor'});`);
block.chunks.create.push(b`${html_tag} = new @HtmlTag(${init});`);
if (this.renderer.options.hydratable) {
block.chunks.claim.push(b`${html_tag} = new @HtmlTag(${init});`);
block.chunks.claim.push(
b`${html_tag}.l(${parent_nodes});`
);
}
if (needs_anchor) {
block.add_element(html_anchor, x`@empty()`, x`@empty()`, parent_node);
block.add_element(html_anchor, x`@empty()`, x`@claim_text(${parent_nodes}, '')`, parent_node);
}
if (!parent_node || in_head) {

@ -63,7 +63,7 @@ export default class Wrapper {
block.add_element(
anchor,
x`@empty()`,
parent_nodes && x`@empty()`,
parent_nodes && x`@claim_text(${parent_nodes}, '')`,
parent_node as Identifier
);
}

@ -1,7 +1,7 @@
import { add_render_callback, flush, schedule_update, dirty_components } from './scheduler';
import { current_component, set_current_component } from './lifecycle';
import { blank_object, is_function, run, run_all, noop } from './utils';
import { children } from './dom';
import { children, update_hydrating } from './dom';
import { transition_in } from './transitions';
interface Fragment {
@ -146,6 +146,7 @@ export function init(component, options, instance, create_fragment, not_equal, p
if (options.target) {
if (options.hydrate) {
update_hydrating(true);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
$$.fragment && $$.fragment!.l(children(options.target));
} else {
@ -155,6 +156,7 @@ export function init(component, options, instance, create_fragment, not_equal, p
if (options.intro) transition_in(component.$$.fragment);
mount_component(component, options.target, options.anchor);
update_hydrating(false);
flush();
}

@ -1,11 +1,21 @@
import { has_prop } from "./utils";
let is_hydrating = false;
export function update_hydrating(val: boolean) {
is_hydrating = val;
}
export function append(target: Node, node: Node) {
target.appendChild(node);
if (!is_hydrating || node.parentNode !== target) {
target.appendChild(node);
}
}
export function insert(target: Node, node: Node, anchor?: Node) {
target.insertBefore(node, anchor || null);
if (!is_hydrating || node.parentNode !== target) {
target.insertBefore(node, anchor || null);
}
}
export function detach(node: Node) {
@ -144,35 +154,48 @@ export function time_ranges_to_array(ranges) {
return array;
}
export function children(element) {
return Array.from(element.childNodes);
export function children(element: HTMLElement) {
const children = Array.from(element.childNodes);
return {
children,
element,
next: children[0] || null,
last: children.length ? children[children.length - 1].nextSibling : null,
};
}
export function claim_element(nodes, name, attributes, svg) {
for (let i = 0; i < nodes.length; i += 1) {
const node = nodes[i];
if (node.nodeName === name) {
for (let j = 0; j < node.attributes.length; j += 1) {
const attribute = node.attributes[j];
if (!attributes[attribute.name]) node.removeAttribute(attribute.name);
export function claim_element(nodes, name, fallback, svg) {
for (let i = 0; i < nodes.children.length; i += 1) {
const node = nodes.children[i];
if (node.nodeType !== 3) {
if (node.nodeName === name) {
nodes.children.splice(0,i + 1);
nodes.next = nodes.children[0];
return node;
} else {
nodes.next = nodes.last;
nodes.children.forEach(detach);
nodes.children.length = 0;
break;
}
return nodes.splice(i, 1)[0]; // TODO strip unwanted attributes
}
}
return svg ? svg_element(name) : element(name);
const node = fallback || (svg ? svg_element(name) : element(name));
insert(nodes.element, node, nodes.next);
return node;
}
export function claim_text(nodes, data) {
for (let i = 0; i < nodes.length; i += 1) {
const node = nodes[i];
if (node.nodeType === 3) {
node.data = '' + data;
return nodes.splice(i, 1)[0];
}
if (nodes.children.length && nodes.children[0].nodeType === 3) {
const node = nodes.children.shift();
node.data = '' + data;
nodes.next = nodes.children[0];
return node;
} else {
const node = text(data);
insert(nodes.element, node, nodes.next);
return node;
}
return text(data);
}
export function claim_space(nodes) {
@ -274,7 +297,13 @@ export function custom_event<T=any>(type: string, detail?: T) {
}
export function query_selector_all(selector: string, parent: HTMLElement = document.body) {
return Array.from(parent.querySelectorAll(selector));
const children = Array.from(parent.querySelectorAll(selector));
return {
children,
element: parent,
next: children[0] || null,
last: children.length ? children[children.length - 1].nextSibling : null
};
}
export class HtmlTag {
@ -283,9 +312,8 @@ export class HtmlTag {
t: HTMLElement;
a: HTMLElement;
constructor(html: string, anchor: HTMLElement = null) {
constructor(html: string) {
this.e = element('div');
this.a = anchor;
this.u(html);
}
@ -302,6 +330,16 @@ export class HtmlTag {
this.n = Array.from(this.e.childNodes);
}
l(nodes: any) {
this.n = this.n.map(n => {
if (n.nodeType === 3) {
return claim_text(nodes, (n as Text).data);
} else {
return claim_element(nodes, n.nodeName, n, n.namespaceURI !== 'http://www.w3.org/1999/xhtml');
}
});
}
p(html: string) {
this.d();
this.u(html);

@ -1,4 +1,4 @@
<title>Some Title</title>
<link href="/" rel="canonical">
<meta content="some description" name="description">
<meta content="some keywords" name="keywords">
<link rel="canonical" href="/"><meta name="description" content="some description"><meta name="keywords" content="some keywords"><title>Some Title</title>

@ -52,8 +52,9 @@ function create_each_block(ctx) {
t4 = text(t4_value);
t5 = text(" ago:");
t6 = space();
html_tag = new HtmlTag(raw_value);
attr(span, "class", "meta");
html_tag = new HtmlTag(raw_value, null);
html_tag.a = null;
attr(div, "class", "comment");
},
m(target, anchor) {

@ -28,10 +28,10 @@ function create_fragment(ctx) {
this.h();
},
l(nodes) {
img = claim_element(nodes, "IMG", { src: true, alt: true });
img = claim_element(nodes, "IMG", null);
t = claim_space(nodes);
div = claim_element(nodes, "DIV", {});
children(div).forEach(detach);
div = claim_element(nodes, "DIV", null);
children(div).children.forEach(detach);
this.h();
},
h() {

@ -28,9 +28,9 @@ function create_fragment(ctx) {
this.h();
},
l(nodes) {
img0 = claim_element(nodes, "IMG", { alt: true, src: true });
img0 = claim_element(nodes, "IMG", null);
t = claim_space(nodes);
img1 = claim_element(nodes, "IMG", { alt: true, src: true });
img1 = claim_element(nodes, "IMG", null);
this.h();
},
h() {

Loading…
Cancel
Save