diff --git a/package.json b/package.json index 6dd8df2856..0b5d4cac7e 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "eslint": "^8.56.0", "eslint-plugin-lube": "^0.4.3", "jsdom": "22.0.0", - "playwright": "^1.35.1", + "playwright": "^1.41.1", "prettier": "^3.2.4", "prettier-plugin-svelte": "^3.1.2", "typescript": "^5.3.3", diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index f118d77761..e54a2c14d2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -33,6 +33,8 @@ import { EACH_IS_STRICT_EQUALS, EACH_ITEM_REACTIVE, EACH_KEYED, + TEMPLATE_FRAGMENT, + TEMPLATE_USE_IMPORT_NODE, TRANSITION_GLOBAL, TRANSITION_IN, TRANSITION_OUT @@ -929,9 +931,9 @@ function serialize_bind_this(bind_this, context, node) { * const block_name = $.template(`...`); * * // for the main block: - * const id = $.open(block_name); + * const id = block_name(); * // init stuff and possibly render effect - * $.close(id); + * $.append($$anchor, id); * ``` * Adds the hoisted parts to `context.state.hoisted` and returns the statements of the main block. * @param {import('#compiler').SvelteNode} parent @@ -1001,25 +1003,19 @@ function create_block(parent, name, nodes, context) { node: id }); - context.state.hoisted.push( - b.var( - template_name, - b.call( - get_template_function(namespace, state), - b.template([b.quasi(state.template.join(''), true)], []) - ) - ) - ); - /** @type {import('estree').Expression[]} */ - const args = [template_name]; + const args = [b.template([b.quasi(state.template.join(''), true)], [])]; if (state.metadata.context.template_needs_import_node) { - args.push(b.false); + args.push(b.literal(TEMPLATE_USE_IMPORT_NODE)); } - body.push(b.var(id, b.call('$.open', ...args)), ...state.before_init, ...state.init); - close = b.stmt(b.call('$.close', b.id('$$anchor'), id)); + context.state.hoisted.push( + b.var(template_name, b.call(get_template_function(namespace, state), ...args)) + ); + + body.push(b.var(id, b.call(template_name)), ...state.before_init, ...state.init); + close = b.stmt(b.call('$.append', b.id('$$anchor'), id)); } else if (is_single_child_not_needing_template) { context.visit(trimmed[0], state); body.push(...state.before_init, ...state.init); @@ -1040,7 +1036,7 @@ function create_block(parent, name, nodes, context) { }); body.push(b.var(id, b.call('$.text', b.id('$$anchor'))), ...state.before_init, ...state.init); - close = b.stmt(b.call('$.close', b.id('$$anchor'), id)); + close = b.stmt(b.call('$.append', b.id('$$anchor'), id)); } else { /** @type {(is_text: boolean) => import('estree').Expression} */ const expression = (is_text) => @@ -1054,30 +1050,29 @@ function create_block(parent, name, nodes, context) { // special case — we can use `$.comment` instead of creating a unique template body.push(b.var(id, b.call('$.comment'))); } else { + let flags = TEMPLATE_FRAGMENT; + + if (state.metadata.context.template_needs_import_node) { + flags |= TEMPLATE_USE_IMPORT_NODE; + } + state.hoisted.push( b.var( template_name, b.call( get_template_function(namespace, state), b.template([b.quasi(state.template.join(''), true)], []), - b.true + b.literal(flags) ) ) ); - /** @type {import('estree').Expression[]} */ - const args = [template_name]; - - if (state.metadata.context.template_needs_import_node) { - args.push(b.false); - } - - body.push(b.var(id, b.call('$.open_frag', ...args))); + body.push(b.var(id, b.call(template_name))); } body.push(...state.before_init, ...state.init); - close = b.stmt(b.call('$.close_frag', b.id('$$anchor'), id)); + close = b.stmt(b.call('$.append', b.id('$$anchor'), id)); } } else { body.push(...state.before_init, ...state.init); @@ -1093,12 +1088,6 @@ function create_block(parent, name, nodes, context) { // It's important that close is the last statement in the block, as any previous statements // could contain element insertions into the template, which the close statement needs to // know of when constructing the list of current inner elements. - - if (context.path.length > 0) { - // this is a block — return DOM so it can be attached directly to the effect - close = b.return(close.expression); - } - body.push(close); } @@ -1566,7 +1555,7 @@ function serialize_template_literal(values, visit) { /** @type {import('../types').ComponentVisitors} */ export const template_visitors = { Fragment(node, context) { - const body = create_block(node, 'frag', node.nodes, context); + const body = create_block(node, 'root', node.nodes, context); return b.block(body); }, Comment(node, context) { diff --git a/packages/svelte/src/constants.js b/packages/svelte/src/constants.js index f26a567506..0015524532 100644 --- a/packages/svelte/src/constants.js +++ b/packages/svelte/src/constants.js @@ -16,6 +16,9 @@ export const TRANSITION_IN = 1; export const TRANSITION_OUT = 1 << 1; export const TRANSITION_GLOBAL = 1 << 2; +export const TEMPLATE_FRAGMENT = 1; +export const TEMPLATE_USE_IMPORT_NODE = 1 << 1; + /** List of Element events that will be delegated */ export const DelegatedEvents = [ 'beforeinput', diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index e9db779e20..cbb5ed1ab5 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -8,7 +8,7 @@ import { } from '../../../../constants.js'; import { hydrate_anchor, hydrate_nodes, hydrating, set_hydrating } from '../hydration.js'; import { empty } from '../operations.js'; -import { insert, remove } from '../reconciler.js'; +import { remove } from '../reconciler.js'; import { untrack } from '../../runtime.js'; import { block, @@ -389,7 +389,7 @@ function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) { if (moved && index !== LIS_ITEM) { if (last_item !== undefined) anchor = get_first_child(last_item); - insert(/** @type {import('#client').Dom} */ (item.e.dom), anchor); + move(/** @type {import('#client').Dom} */ (item.e.dom), anchor); } } @@ -560,3 +560,17 @@ function create_item(anchor, value, key, index, render_fn, flags) { current_each_item = previous_each_item; } } + +/** + * @param {import('#client').Dom} current + * @param {Text | Element | Comment} anchor + */ +function move(current, anchor) { + if (is_array(current)) { + for (var i = 0; i < current.length; i++) { + anchor.before(current[i]); + } + } else { + anchor.before(current); + } +} diff --git a/packages/svelte/src/internal/client/dom/blocks/snippet.js b/packages/svelte/src/internal/client/dom/blocks/snippet.js index 7bfcc92005..9d494c4598 100644 --- a/packages/svelte/src/internal/client/dom/blocks/snippet.js +++ b/packages/svelte/src/internal/client/dom/blocks/snippet.js @@ -1,6 +1,4 @@ -import { render_effect } from '../../reactivity/effects.js'; -import { remove } from '../reconciler.js'; -import { untrack } from '../../runtime.js'; +import { branch, render_effect } from '../../reactivity/effects.js'; /** * @template {(node: import('#client').TemplateNode, ...args: any[]) => import('#client').Dom} SnippetFn @@ -11,19 +9,13 @@ import { untrack } from '../../runtime.js'; */ export function snippet(get_snippet, node, ...args) { /** @type {SnippetFn | null | undefined} */ - var snippet_fn; + var snippet; render_effect(() => { - if (snippet_fn === (snippet_fn = get_snippet())) return; + if (snippet === (snippet = get_snippet())) return; - if (snippet_fn) { - // Untrack so we only rerender when the snippet function itself changes, - // not when an eagerly-read prop inside the snippet function changes - var dom = untrack(() => /** @type {SnippetFn} */ (snippet_fn)(node, ...args)); - - if (dom !== undefined) { - return () => remove(dom); - } + if (snippet) { + branch(() => /** @type {SnippetFn} */ (snippet)(node, ...args)); } }); } diff --git a/packages/svelte/src/internal/client/dom/elements/custom-element.js b/packages/svelte/src/internal/client/dom/elements/custom-element.js index 0f6cb7dc67..c5b45d03c6 100644 --- a/packages/svelte/src/internal/client/dom/elements/custom-element.js +++ b/packages/svelte/src/internal/client/dom/elements/custom-element.js @@ -1,6 +1,6 @@ import { createClassComponent } from '../../../../legacy/legacy-client.js'; import { destroy_effect, render_effect } from '../../reactivity/effects.js'; -import { open, close } from '../template.js'; +import { append } from '../template.js'; import { define_property } from '../../utils.js'; /** @@ -98,14 +98,10 @@ if (typeof HTMLElement === 'function') { * @param {Element} anchor */ return (anchor) => { - const node = open(() => { - const slot = document.createElement('slot'); - if (name !== 'default') { - slot.name = name; - } - return slot; - }); - close(anchor, /** @type {Element} */ (node)); + const slot = document.createElement('slot'); + if (name !== 'default') slot.name = name; + + append(anchor, slot); }; } /** @type {Record} */ diff --git a/packages/svelte/src/internal/client/dom/reconciler.js b/packages/svelte/src/internal/client/dom/reconciler.js index 780a7afe0c..18fac51f96 100644 --- a/packages/svelte/src/internal/client/dom/reconciler.js +++ b/packages/svelte/src/internal/client/dom/reconciler.js @@ -8,41 +8,6 @@ export function create_fragment_from_html(html) { return elem.content; } -/** - * Creating a document fragment from HTML that contains script tags will not execute - * the scripts. We need to replace the script tags with new ones so that they are executed. - * @param {string} html - */ -export function create_fragment_with_script_from_html(html) { - var content = create_fragment_from_html(html); - var scripts = content.querySelectorAll('script'); - for (const script of scripts) { - var new_script = document.createElement('script'); - for (var i = 0; i < script.attributes.length; i++) { - new_script.setAttribute(script.attributes[i].name, script.attributes[i].value); - } - new_script.textContent = script.textContent; - /** @type {Node} */ (script.parentNode).replaceChild(new_script, script); - } - return content; -} - -/** - * @param {import('#client').Dom} current - * @param {Text | Element | Comment} sibling - */ -export function insert(current, sibling) { - if (!current) return sibling; - - if (is_array(current)) { - for (var i = 0; i < current.length; i++) { - sibling.before(/** @type {Node} */ (current[i])); - } - } else { - sibling.before(/** @type {Node} */ (current)); - } -} - /** * @param {import('#client').Dom} current */ diff --git a/packages/svelte/src/internal/client/dom/template.js b/packages/svelte/src/internal/client/dom/template.js index cfe365f570..9e1f8e55e1 100644 --- a/packages/svelte/src/internal/client/dom/template.js +++ b/packages/svelte/src/internal/client/dom/template.js @@ -1,121 +1,135 @@ import { hydrate_nodes, 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 { clone_node, empty } from './operations.js'; +import { create_fragment_from_html } from './reconciler.js'; import { current_effect } from '../runtime.js'; -import { is_array } from '../utils.js'; +import { TEMPLATE_FRAGMENT, TEMPLATE_USE_IMPORT_NODE } from '../../../constants.js'; /** - * @param {string} html - * @param {boolean} return_fragment - * @returns {() => Node} + * @param {string} content + * @param {number} flags + * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -export function template(html, return_fragment) { - /** @type {undefined | Node} */ - let cached_content; +export function template(content, flags) { + var is_fragment = (flags & TEMPLATE_FRAGMENT) !== 0; + var use_import_node = (flags & TEMPLATE_USE_IMPORT_NODE) !== 0; + + /** @type {Node} */ + var node; + return () => { - if (cached_content === undefined) { - const content = create_fragment_from_html(html); - cached_content = return_fragment ? content : /** @type {Node} */ (child(content)); + if (hydrating) { + return is_fragment ? hydrate_nodes : /** @type {Node} */ (hydrate_nodes[0]); } - 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)); + if (!node) { + node = create_fragment_from_html(content); + if (!is_fragment) node = /** @type {Node} */ (node.firstChild); } - return cached_content; + + return use_import_node ? document.importNode(node, true) : clone_node(node, true); }; } /** - * @param {string} svg - * @param {boolean} return_fragment - * @returns {() => Node} + * @param {string} content + * @param {number} flags + * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -export function svg_template(svg, return_fragment) { - /** @type {undefined | Node} */ - let cached_content; +export function template_with_script(content, flags) { + var first = true; + var fn = template(content, flags); + return () => { - if (cached_content === undefined) { - const content = /** @type {Node} */ (child(create_fragment_from_html(`${svg}`))); - cached_content = return_fragment ? content : /** @type {Node} */ (child(content)); + if (hydrating) return fn(); + + var node = /** @type {Element | DocumentFragment} */ (fn()); + + if (first) { + first = false; + run_scripts(node); } - return cached_content; + + return node; }; } /** - * @param {string} svg - * @param {boolean} return_fragment - * @returns {() => Node} + * @param {string} content + * @param {number} flags + * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -export function svg_template_with_script(svg, return_fragment) { - /** @type {undefined | Node} */ - let cached_content; +export function svg_template(content, flags) { + var is_fragment = (flags & TEMPLATE_FRAGMENT) !== 0; + var fn = template(`${content}`, 0); // we don't need to worry about using importNode for SVGs + + /** @type {Element | DocumentFragment} */ + var node; + return () => { - if (cached_content === undefined) { - const content = /** @type {Node} */ (child(create_fragment_from_html(`${svg}`))); - cached_content = return_fragment ? content : /** @type {Node} */ (child(content)); + if (hydrating) { + return is_fragment ? hydrate_nodes : /** @type {Node} */ (hydrate_nodes[0]); } - return cached_content; + + if (!node) { + var svg = /** @type {Element} */ (fn()); + + if ((flags & TEMPLATE_FRAGMENT) === 0) { + node = /** @type {Element} */ (svg.firstChild); + } else { + node = document.createDocumentFragment(); + while (svg.firstChild) { + node.appendChild(svg.firstChild); + } + } + } + + return clone_node(node, true); }; } /** - * @param {boolean} is_fragment - * @param {boolean} use_clone_node - * @param {() => Node} [template_element_fn] - * @returns {Element | DocumentFragment | Node[]} + * @param {string} content + * @param {number} flags + * @returns {() => Node | Node[]} */ /*#__NO_SIDE_EFFECTS__*/ -function open_template(is_fragment, use_clone_node, template_element_fn) { - if (hydrating) { - return is_fragment ? hydrate_nodes : /** @type {Element} */ (hydrate_nodes[0]); - } +export function svg_template_with_script(content, flags) { + var first = true; + var fn = svg_template(content, flags); - return use_clone_node - ? clone_node(/** @type {() => Element} */ (template_element_fn)(), true) - : document.importNode(/** @type {() => Element} */ (template_element_fn)(), true); -} + return () => { + if (hydrating) return fn(); -/** - * @param {() => Node} template_element_fn - * @param {boolean} [use_clone_node] - * @returns {Element} - */ -export function open(template_element_fn, use_clone_node = true) { - return /** @type {Element} */ (open_template(false, use_clone_node, template_element_fn)); + var node = /** @type {Element | DocumentFragment} */ (fn()); + + if (first) { + first = false; + run_scripts(node); + } + + return node; + }; } /** - * @param {() => Node} template_element_fn - * @param {boolean} [use_clone_node] - * @returns {Element | DocumentFragment | Node[]} + * Creating a document fragment from HTML that contains script tags will not execute + * the scripts. We need to replace the script tags with new ones so that they are executed. + * @param {Element | DocumentFragment} node */ -export function open_frag(template_element_fn, use_clone_node = true) { - return open_template(true, use_clone_node, template_element_fn); -} +function run_scripts(node) { + for (const script of node.querySelectorAll('script')) { + var clone = document.createElement('script'); + for (var attribute of script.attributes) { + clone.setAttribute(attribute.name, attribute.value); + } -const comment_template = template('', true); + clone.textContent = script.textContent; + script.replaceWith(clone); + } +} /** * @param {Text | Comment | Element} anchor @@ -136,49 +150,28 @@ export function text(anchor) { } /*#__NO_SIDE_EFFECTS__*/ -export function comment() { - return open_frag(comment_template); -} +export const comment = template('', TEMPLATE_FRAGMENT); /** * 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 {import('#client').Dom} dom - * @param {boolean} is_fragment * @param {Text | Comment | Element} anchor - * @returns {import('#client').Dom} + * @param {import('#client').Dom} dom */ -function close_template(dom, is_fragment, anchor) { +export function append(anchor, dom) { var current = dom; if (!hydrating) { - if (is_fragment) { + var node = /** @type {Node} */ (dom); + + if (node.nodeType === 11) { // if hydrating, `dom` is already an array of nodes, but if not then // we need to create an array to store it on the current effect - current = /** @type {import('#client').Dom} */ ([.../** @type {Node} */ (dom).childNodes]); + current = /** @type {import('#client').Dom} */ ([...node.childNodes]); } - // TODO ideally we'd do `anchor.before(dom)`, but that fails because `dom` can be an array of nodes in the SVG case - insert(current, anchor); + anchor.before(node); } /** @type {import('#client').Effect} */ (current_effect).dom = current; - - return current; -} - -/** - * @param {Text | Comment | Element} anchor - * @param {Element | Text} dom - */ -export function close(anchor, dom) { - return close_template(dom, false, anchor); -} - -/** - * @param {Text | Comment | Element} anchor - * @param {Element | Text} dom - */ -export function close_frag(anchor, dom) { - return close_template(dom, true, anchor); } diff --git a/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js index c5a68bdb8c..c6b1ce9ead 100644 --- a/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js @@ -11,6 +11,6 @@ export default function Bind_this($$anchor, $$props) { var node = $.first_child(fragment); $.bind_this(Foo(node, {}), ($$value) => foo = $$value, () => foo); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js index 946778169a..6112527db1 100644 --- a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js +++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js @@ -3,7 +3,7 @@ import "svelte/internal/disclose-version"; import * as $ from "svelte/internal"; -var frag = $.template(`
`, true); +var root = $.template(`
`, 3); export default function Main($$anchor, $$props) { $.push($$props, true); @@ -11,7 +11,7 @@ export default function Main($$anchor, $$props) { // needs to be a snapshot test because jsdom does auto-correct the attribute casing let x = 'test'; let y = () => 'test'; - var fragment = $.open_frag(frag, false); + var fragment = root(); var div = $.first_child(fragment); var svg = $.sibling($.sibling(div, true)); var custom_element = $.sibling($.sibling(svg, true)); @@ -33,6 +33,6 @@ export default function Main($$anchor, $$props) { $.set_custom_element_data(custom_element, "fooBar", x); }); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js index 8d59f478ec..a01456fc48 100644 --- a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js @@ -14,9 +14,9 @@ export default function Each_string_template($$anchor, $$props) { var text = $.text($$anchor); $.render_effect(() => $.set_text(text, `${$.stringify($.unwrap(thing))}, `)); - return $.close($$anchor, text); + $.append($$anchor, text); }); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js index 0ea4acb988..5174c1183e 100644 --- a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js @@ -24,10 +24,10 @@ export default function Function_prop_no_getter($$anchor, $$props) { var text = $.text($$anchor); $.render_effect(() => $.set_text(text, `clicks: ${$.stringify($.get(count))}`)); - return $.close($$anchor, text); + $.append($$anchor, text); } }); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js index 0587fc3988..aa18876ec7 100644 --- a/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js @@ -3,14 +3,14 @@ import "svelte/internal/disclose-version"; import * as $ from "svelte/internal"; -var frag = $.template(`

hello world

`); +var root = $.template(`

hello world

`); export default function Hello_world($$anchor, $$props) { $.push($$props, false); $.init(); - var h1 = $.open(frag); + var h1 = root(); - $.close($$anchor, h1); + $.append($$anchor, h1); $.pop(); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js index a714d84f8d..18371d51d0 100644 --- a/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js @@ -10,14 +10,14 @@ function reset(_, str, tpl) { $.set(tpl, ``); } -var frag = $.template(` `, true); +var root = $.template(` `, 1); export default function State_proxy_literal($$anchor, $$props) { $.push($$props, true); let str = $.source(''); let tpl = $.source(``); - var fragment = $.open_frag(frag); + var fragment = root(); var input = $.first_child(fragment); $.remove_input_attr_defaults(input); @@ -31,7 +31,7 @@ export default function State_proxy_literal($$anchor, $$props) { button.__click = [reset, str, tpl]; $.bind_value(input, () => $.get(str), ($$value) => $.set(str, $$value)); $.bind_value(input_1, () => $.get(tpl), ($$value) => $.set(tpl, $$value)); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js index cf329f7148..85888fa82e 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js @@ -11,6 +11,6 @@ export default function Svelte_element($$anchor, $$props) { var node = $.first_child(fragment); $.element(node, tag, false); - $.close_frag($$anchor, fragment); + $.append($$anchor, fragment); $.pop(); } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 17cddea1d0..78bdcaf159 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,7 +45,7 @@ importers: specifier: 22.0.0 version: 22.0.0 playwright: - specifier: ^1.35.1 + specifier: ^1.41.1 version: 1.41.1 prettier: specifier: ^3.2.4