fix: improve hydration of svelte head blocks (#11099)

* fix: improve hydration of svelte head blocks

* revert sandbox

* simplify
pull/11093/head
Dominic Gannaway 1 year ago committed by GitHub
parent 48549f7d00
commit 3c2f4d2d55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: improve hydration of svelte head blocks

@ -1,7 +1,16 @@
import { hydrate_anchor, hydrate_nodes, hydrating, set_hydrate_nodes } from '../hydration.js';
import { empty } from '../operations.js';
import { block } from '../../reactivity/effects.js';
import { HYDRATION_START } from '../../../../constants.js';
import { HYDRATION_END, HYDRATION_START } from '../../../../constants.js';
/**
* @type {Node | undefined}
*/
let head_anchor;
export function reset_head_anchor() {
head_anchor = undefined;
}
/**
* @param {(anchor: Node) => import('#client').Dom | void} render_fn
@ -19,12 +28,20 @@ export function head(render_fn) {
if (hydrating) {
previous_hydrate_nodes = hydrate_nodes;
let anchor = /** @type {import('#client').TemplateNode} */ (document.head.firstChild);
while (anchor.nodeType !== 8 || /** @type {Comment} */ (anchor).data !== HYDRATION_START) {
anchor = /** @type {import('#client').TemplateNode} */ (anchor.nextSibling);
// There might be multiple head blocks in our app, so we need to account for each one needing independent hydration.
if (head_anchor === undefined) {
head_anchor = /** @type {import('#client').TemplateNode} */ (document.head.firstChild);
}
while (
head_anchor.nodeType !== 8 ||
/** @type {Comment} */ (head_anchor).data !== HYDRATION_START
) {
head_anchor = /** @type {import('#client').TemplateNode} */ (head_anchor.nextSibling);
}
anchor = /** @type {import('#client').TemplateNode} */ (hydrate_anchor(anchor));
head_anchor = /** @type {import('#client').TemplateNode} */ (hydrate_anchor(head_anchor));
head_anchor = /** @type {import('#client').TemplateNode} */ (head_anchor.nextSibling);
} else {
anchor = document.head.appendChild(empty());
}

@ -18,6 +18,7 @@ import {
} from './dom/hydration.js';
import { array_from } from './utils.js';
import { handle_event_propagation } from './dom/elements/events.js';
import { reset_head_anchor } from './dom/blocks/svelte-head.js';
/** @type {Set<string>} */
export const all_registered_events = new Set();
@ -175,6 +176,7 @@ export function hydrate(component, options) {
} finally {
set_hydrating(!!previous_hydrate_nodes);
set_hydrate_nodes(previous_hydrate_nodes);
reset_head_anchor();
}
}

@ -207,10 +207,7 @@ export function render(component, options) {
on_destroy = prev_on_destroy;
return {
head:
payload.head.out || payload.head.title
? payload.head.title + BLOCK_OPEN + payload.head.out + BLOCK_CLOSE
: '',
head: payload.head.out || payload.head.title ? payload.head.out + payload.head.title : '',
html: payload.out
};
}
@ -247,7 +244,9 @@ export function escape(value, is_attr = false) {
*/
export function head(payload, fn) {
const head_payload = payload.head;
payload.head.out += BLOCK_OPEN;
fn(head_payload);
payload.head.out += BLOCK_CLOSE;
}
/**

@ -0,0 +1,9 @@
<script>
let title = $state('Hello world');
let desc = $state('Some description');
</script>
<svelte:head>
<title>{title}</title>
<meta name="description" content={desc}>
<meta name="author" content="@svelteawesome">
</svelte:head>

@ -0,0 +1,12 @@
import { test } from '../../test';
export default test({
html: `<div>Hello</div>`,
async test({ assert, target }) {
assert.htmlEqual(
target.ownerDocument.head.innerHTML,
`<script async="" src="https://www.googletagmanager.com/gtag/js?id=12345"></script><meta content="Some description" name="description"><meta content="@svelteawesome" name="author"><title>Hello world</title>`
);
}
});

@ -0,0 +1,9 @@
<script>
import MetaTag from './MetaTag.svelte'
</script>
<svelte:head>
<script async src="https://www.googletagmanager.com/gtag/js?id=12345"></script>
</svelte:head>
<MetaTag />
<div>Hello</div>

@ -1,6 +1,6 @@
<!ssr:0>
<title>Some Title</title>
<link rel="canonical" href="/">
<meta name="description" content="some description">
<meta name="keywords" content="some keywords">
<title>Some Title</title>
<!ssr:0>

Loading…
Cancel
Save