mirror of https://github.com/sveltejs/svelte
move template code into its own module (#10773)
Co-authored-by: Rich Harris <rich.harris@vercel.com>pull/10776/head
parent
77f39ea988
commit
d82d57e833
@ -0,0 +1,214 @@
|
|||||||
|
import { current_hydration_fragment, hydrate_block_anchor, hydrating } from '../hydration.js';
|
||||||
|
import { child, clone_node, empty } from '../operations.js';
|
||||||
|
import {
|
||||||
|
create_fragment_from_html,
|
||||||
|
create_fragment_with_script_from_html,
|
||||||
|
insert
|
||||||
|
} from '../reconciler.js';
|
||||||
|
import { current_block } from '../runtime.js';
|
||||||
|
import { is_array } from '../utils.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html
|
||||||
|
* @param {boolean} return_fragment
|
||||||
|
* @returns {() => Node}
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function template(html, return_fragment) {
|
||||||
|
/** @type {undefined | Node} */
|
||||||
|
let cached_content;
|
||||||
|
return () => {
|
||||||
|
if (cached_content === undefined) {
|
||||||
|
const content = create_fragment_from_html(html);
|
||||||
|
cached_content = return_fragment ? content : /** @type {Node} */ (child(content));
|
||||||
|
}
|
||||||
|
return cached_content;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} html
|
||||||
|
* @param {boolean} return_fragment
|
||||||
|
* @returns {() => Node}
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function template_with_script(html, return_fragment) {
|
||||||
|
/** @type {undefined | Node} */
|
||||||
|
let cached_content;
|
||||||
|
return () => {
|
||||||
|
if (cached_content === undefined) {
|
||||||
|
const content = create_fragment_with_script_from_html(html);
|
||||||
|
cached_content = return_fragment ? content : /** @type {Node} */ (child(content));
|
||||||
|
}
|
||||||
|
return cached_content;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} svg
|
||||||
|
* @param {boolean} return_fragment
|
||||||
|
* @returns {() => Node}
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function svg_template(svg, return_fragment) {
|
||||||
|
/** @type {undefined | Node} */
|
||||||
|
let cached_content;
|
||||||
|
return () => {
|
||||||
|
if (cached_content === undefined) {
|
||||||
|
const content = /** @type {Node} */ (child(create_fragment_from_html(`<svg>${svg}</svg>`)));
|
||||||
|
cached_content = return_fragment ? content : /** @type {Node} */ (child(content));
|
||||||
|
}
|
||||||
|
return cached_content;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} svg
|
||||||
|
* @param {boolean} return_fragment
|
||||||
|
* @returns {() => Node}
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function svg_template_with_script(svg, return_fragment) {
|
||||||
|
/** @type {undefined | Node} */
|
||||||
|
let cached_content;
|
||||||
|
return () => {
|
||||||
|
if (cached_content === undefined) {
|
||||||
|
const content = /** @type {Node} */ (child(create_fragment_from_html(`<svg>${svg}</svg>`)));
|
||||||
|
cached_content = return_fragment ? content : /** @type {Node} */ (child(content));
|
||||||
|
}
|
||||||
|
return cached_content;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} is_fragment
|
||||||
|
* @param {boolean} use_clone_node
|
||||||
|
* @param {null | Text | Comment | Element} anchor
|
||||||
|
* @param {() => Node} [template_element_fn]
|
||||||
|
* @returns {Element | DocumentFragment | Node[]}
|
||||||
|
*/
|
||||||
|
function open_template(is_fragment, use_clone_node, anchor, template_element_fn) {
|
||||||
|
if (hydrating) {
|
||||||
|
if (anchor !== null) {
|
||||||
|
hydrate_block_anchor(anchor, false);
|
||||||
|
}
|
||||||
|
// In ssr+hydration optimization mode, we might remove the template_element,
|
||||||
|
// so we need to is_fragment flag to properly handle hydrated content accordingly.
|
||||||
|
const fragment = current_hydration_fragment;
|
||||||
|
if (fragment !== null) {
|
||||||
|
return is_fragment ? fragment : /** @type {Element} */ (fragment[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return use_clone_node
|
||||||
|
? clone_node(/** @type {() => Element} */ (template_element_fn)(), true)
|
||||||
|
: document.importNode(/** @type {() => Element} */ (template_element_fn)(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {null | Text | Comment | Element} anchor
|
||||||
|
* @param {boolean} use_clone_node
|
||||||
|
* @param {() => Node} [template_element_fn]
|
||||||
|
* @returns {Element | DocumentFragment | Node[]}
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function open(anchor, use_clone_node, template_element_fn) {
|
||||||
|
return open_template(false, use_clone_node, anchor, template_element_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {null | Text | Comment | Element} anchor
|
||||||
|
* @param {boolean} use_clone_node
|
||||||
|
* @param {() => Node} [template_element_fn]
|
||||||
|
* @returns {Element | DocumentFragment | Node[]}
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function open_frag(anchor, use_clone_node, template_element_fn) {
|
||||||
|
return open_template(true, use_clone_node, anchor, template_element_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
const space_template = template(' ', false);
|
||||||
|
const comment_template = template('<!>', true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Text | Comment | Element | null} anchor
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function space_frag(anchor) {
|
||||||
|
/** @type {Node | null} */
|
||||||
|
var node = /** @type {any} */ (open(anchor, true, space_template));
|
||||||
|
// if an {expression} is empty during SSR, there might be no
|
||||||
|
// text node to hydrate (or an anchor comment is falsely detected instead)
|
||||||
|
// — we must therefore create one
|
||||||
|
if (hydrating && node?.nodeType !== 3) {
|
||||||
|
node = empty();
|
||||||
|
// @ts-ignore in this case the anchor should always be a comment,
|
||||||
|
// if not something more fundamental is wrong and throwing here is better to bail out early
|
||||||
|
anchor.before(node);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Text | Comment | Element} anchor
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function space(anchor) {
|
||||||
|
// if an {expression} is empty during SSR, there might be no
|
||||||
|
// text node to hydrate (or an anchor comment is falsely detected instead)
|
||||||
|
// — we must therefore create one
|
||||||
|
if (hydrating && anchor.nodeType !== 3) {
|
||||||
|
const node = empty();
|
||||||
|
anchor.before(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {null | Text | Comment | Element} anchor
|
||||||
|
*/
|
||||||
|
/*#__NO_SIDE_EFFECTS__*/
|
||||||
|
export function comment(anchor) {
|
||||||
|
return open_frag(anchor, true, comment_template);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign the created (or in hydration mode, traversed) dom elements to the current block
|
||||||
|
* and insert the elements into the dom (in client mode).
|
||||||
|
* @param {Element | Text} dom
|
||||||
|
* @param {boolean} is_fragment
|
||||||
|
* @param {null | Text | Comment | Element} anchor
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function close_template(dom, is_fragment, anchor) {
|
||||||
|
const block = /** @type {import('#client').Block} */ (current_block);
|
||||||
|
|
||||||
|
/** @type {import('#client').TemplateNode | Array<import('#client').TemplateNode>} */
|
||||||
|
const current = is_fragment
|
||||||
|
? is_array(dom)
|
||||||
|
? dom
|
||||||
|
: /** @type {import('#client').TemplateNode[]} */ (Array.from(dom.childNodes))
|
||||||
|
: dom;
|
||||||
|
if (!hydrating && anchor !== null) {
|
||||||
|
insert(current, null, anchor);
|
||||||
|
}
|
||||||
|
block.d = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {null | Text | Comment | Element} anchor
|
||||||
|
* @param {Element | Text} dom
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
export function close(anchor, dom) {
|
||||||
|
close_template(dom, false, anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {null | Text | Comment | Element} anchor
|
||||||
|
* @param {Element | Text} dom
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
export function close_frag(anchor, dom) {
|
||||||
|
close_template(dom, true, anchor);
|
||||||
|
}
|
Loading…
Reference in new issue