chore: make DOM operations lazily init (#9468)

* chore: make DOM operations lazyily init

* cleanup types

* cleanup types

* cleanup types

* Update packages/svelte/src/internal/client/operations.js

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>

* single line annotations

* remove unnecessary coercion

* group statements by type

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/9472/head
Dominic Gannaway 1 year ago committed by GitHub
parent 640dd48705
commit 73e8820fe7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
chore: make operations lazy

@ -1,46 +1,109 @@
import { current_hydration_fragment, get_hydration_fragment } from './hydration.js';
import { get_descriptor } from './utils.js';
/** This file is also loaded in server environments, so we need guard against eagerly accessing browser globals */
const has_browser_globals = typeof window !== 'undefined';
// We cache the Node and Element prototype methods, so that subsequent calls-sites are monomorphic rather
// than megamorphic.
const node_prototype = /** @type {Node} */ (has_browser_globals ? Node.prototype : {});
const element_prototype = /** @type {Element} */ (has_browser_globals ? Element.prototype : {});
const text_prototype = /** @type {Text} */ (has_browser_globals ? Text.prototype : {});
const map_prototype = Map.prototype;
const append_child_method = node_prototype.appendChild;
const clone_node_method = node_prototype.cloneNode;
const map_set_method = map_prototype.set;
const map_get_method = map_prototype.get;
const map_delete_method = map_prototype.delete;
// @ts-expect-error improve perf of expando on DOM events
element_prototype.__click = undefined;
// @ts-expect-error improve perf of expando on DOM text updates
text_prototype.__nodeValue = ' ';
// @ts-expect-error improve perf of expando on DOM className updates
element_prototype.__className = '';
const first_child_get = /** @type {(this: Node) => ChildNode | null} */ (
// We cache the Node and Element prototype methods, so that we can avoid doing
// expensive prototype chain lookups.
/** @type {Node} */
var node_prototype;
/** @type {Element} */
var element_prototype;
/** @type {Text} */
var text_prototype;
/** @type {Map<any, any>} */
var map_prototype;
/** @type {typeof Node.prototype.appendChild} */
var append_child_method;
/** @type {typeof Node.prototype.cloneNode} */
var clone_node_method;
/** @type {typeof Map.prototype.set} */
var map_set_method;
/** @type {typeof Map.prototype.get} */
var map_get_method;
/** @type {typeof Map.prototype.delete} */
var map_delete_method;
/** @type {(this: Node) => ChildNode | null} */
var first_child_get;
/** @type {(this: Node) => ChildNode | null} */
var next_sibling_get;
/** @type {(this: Node, text: string ) => void} */
var text_content_set;
/** @type {(this: Element, class_name: string) => void} */
var class_name_set;
// export these for reference in the compiled code, making global name deduplication unnecessary
/**
* @type {Window}
*/
export var $window;
/**
* @type {Document}
*/
export var $document;
/**
* Initialize these lazily to avoid issues when using the runtime in a server context
* where these globals are not available while avoiding a separate server entry point
*/
export function init_operations() {
if (node_prototype !== undefined) {
return;
}
node_prototype = Node.prototype;
element_prototype = Element.prototype;
text_prototype = Text.prototype;
map_prototype = Map.prototype;
append_child_method = node_prototype.appendChild;
clone_node_method = node_prototype.cloneNode;
map_set_method = map_prototype.set;
map_get_method = map_prototype.get;
map_delete_method = map_prototype.delete;
$window = window;
$document = document;
// the following assignments improve perf of lookups on DOM nodes
// @ts-expect-error
element_prototype.__click = undefined;
// @ts-expect-error
text_prototype.__nodeValue = ' ';
// @ts-expect-error
element_prototype.__className = '';
first_child_get = /** @type {(this: Node) => ChildNode | null} */ (
// @ts-ignore
has_browser_globals ? get_descriptor(node_prototype, 'firstChild').get : null
);
get_descriptor(node_prototype, 'firstChild').get
);
const next_sibling_get = /** @type {(this: Node) => ChildNode | null} */ (
next_sibling_get = /** @type {(this: Node) => ChildNode | null} */ (
// @ts-ignore
has_browser_globals ? get_descriptor(node_prototype, 'nextSibling').get : null
);
get_descriptor(node_prototype, 'nextSibling').get
);
const text_content_set = /** @type {(this: Node, text: string ) => void} */ (
text_content_set = /** @type {(this: Node, text: string ) => void} */ (
// @ts-ignore
has_browser_globals ? get_descriptor(node_prototype, 'textContent').set : null
);
get_descriptor(node_prototype, 'textContent').set
);
const class_name_set = /** @type {(this: Element, class_name: string) => void} */ (
class_name_set = /** @type {(this: Element, class_name: string) => void} */ (
// @ts-ignore
has_browser_globals ? get_descriptor(element_prototype, 'className').set : null
);
get_descriptor(element_prototype, 'className').set
);
}
/**
* @template {Element} E
@ -191,7 +254,3 @@ function capture_fragment_from_node(node) {
}
return node;
}
// export these for reference in the compiled code, making global name deduplication unnecessary
export const $window = has_browser_globals ? window : undefined;
export const $document = has_browser_globals ? document : undefined;

@ -4,6 +4,7 @@ import {
child,
clone_node,
create_element,
init_operations,
map_get,
map_set,
set_class_name
@ -3173,6 +3174,7 @@ export function createRoot(component, options) {
* @returns {[Exports, () => void]}
*/
export function mount(component, options) {
init_operations();
const registered_events = new Set();
const container = options.target;
const block = create_root_block(container, options.intro || false);

Loading…
Cancel
Save