delete delete delete

pull/10880/head
Rich Harris 2 years ago
parent 3ea2d51dcc
commit ee4f65f8c2

@ -10,7 +10,6 @@ import {
} from '../../runtime.js';
import { destroy_effect, pause_effect, render_effect } from '../../reactivity/effects.js';
import { DESTROYED, INERT } from '../../constants.js';
import { create_block } from './utils.js';
/**
* @template V
@ -22,8 +21,6 @@ import { create_block } from './utils.js';
* @returns {void}
*/
export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) {
const block = create_block();
const component_context = current_component_context;
hydrate_block_anchor(anchor);
@ -48,7 +45,7 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) {
set_current_effect(branch);
set_current_reaction(branch); // TODO do we need both?
set_current_component_context(component_context);
var effect = render_effect(() => fn(anchor, value), {}, true);
var effect = render_effect(() => fn(anchor, value), true);
set_current_component_context(null);
set_current_reaction(null);
set_current_effect(null);
@ -83,7 +80,7 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) {
destroy_effect(pending_effect);
}
pending_effect = render_effect(() => pending_fn(anchor), {}, true);
pending_effect = render_effect(() => pending_fn(anchor), true);
}
if (then_effect) pause(then_effect);
@ -117,10 +114,10 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) {
destroy_effect(then_effect);
}
then_effect = render_effect(() => then_fn(anchor, input), {}, true);
then_effect = render_effect(() => then_fn(anchor, input), true);
}
}
}, block);
});
branch.ondestroy = () => {
// TODO this sucks, tidy it up

@ -27,7 +27,6 @@ import {
import { source, mutable_source, set } from '../../reactivity/sources.js';
import { is_array, is_frozen, map_get, map_set } from '../../utils.js';
import { STATE_SYMBOL } from '../../constants.js';
import { create_block } from './utils.js';
var NEW_ITEM = -1;
var LIS_ITEM = -2;
@ -56,8 +55,6 @@ export function set_current_each_item(item) {
* @returns {void}
*/
function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, reconcile_fn) {
var block = create_block();
/** @type {import('#client').EachState} */
var state = { flags, items: [] };
@ -72,124 +69,116 @@ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, re
/** @type {import('#client').Effect | null} */
var fallback = null;
var effect = render_effect(
() => {
var collection = get_collection();
var effect = render_effect(() => {
var collection = get_collection();
var array = is_array(collection)
? collection
: collection == null
? []
: Array.from(collection);
var array = is_array(collection)
? collection
: collection == null
? []
: Array.from(collection);
var keys = get_key === null ? array : array.map(get_key);
var keys = get_key === null ? array : array.map(get_key);
var length = array.length;
var length = array.length;
// If we are working with an array that isn't proxied or frozen, then remove strict equality and ensure the items
// are treated as reactive, so they get wrapped in a signal.
var flags = state.flags;
if ((flags & EACH_IS_STRICT_EQUALS) !== 0 && !is_frozen(array) && !(STATE_SYMBOL in array)) {
flags ^= EACH_IS_STRICT_EQUALS;
// If we are working with an array that isn't proxied or frozen, then remove strict equality and ensure the items
// are treated as reactive, so they get wrapped in a signal.
var flags = state.flags;
if ((flags & EACH_IS_STRICT_EQUALS) !== 0 && !is_frozen(array) && !(STATE_SYMBOL in array)) {
flags ^= EACH_IS_STRICT_EQUALS;
// Additionally if we're in an keyed each block, we'll need ensure the items are all wrapped in signals.
if ((flags & EACH_KEYED) !== 0 && (flags & EACH_ITEM_REACTIVE) === 0) {
flags ^= EACH_ITEM_REACTIVE;
}
// Additionally if we're in an keyed each block, we'll need ensure the items are all wrapped in signals.
if ((flags & EACH_KEYED) !== 0 && (flags & EACH_ITEM_REACTIVE) === 0) {
flags ^= EACH_ITEM_REACTIVE;
}
}
/** `true` if there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
let mismatch = false;
if (hydrating) {
var is_else =
/** @type {Comment} */ (current_hydration_fragment?.[0])?.data === 'ssr:each_else';
/** `true` if there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
let mismatch = false;
if (hydrating) {
var is_else =
/** @type {Comment} */ (current_hydration_fragment?.[0])?.data === 'ssr:each_else';
if (is_else !== (length === 0)) {
// hydration mismatch — remove the server-rendered DOM and start over
remove(current_hydration_fragment);
set_current_hydration_fragment(null);
mismatch = true;
} else if (is_else) {
// Remove the each_else comment node or else it will confuse the subsequent hydration algorithm
/** @type {import('#client').TemplateNode[]} */ (current_hydration_fragment).shift();
}
}
if (is_else !== (length === 0)) {
// hydration mismatch — remove the server-rendered DOM and start over
remove(current_hydration_fragment);
set_current_hydration_fragment(null);
// this is separate to the previous block because `hydrating` might change
if (hydrating) {
var b_items = [];
// Hydrate block
var hydration_list = /** @type {import('#client').TemplateNode[]} */ (
current_hydration_fragment
);
var hydrating_node = hydration_list[0];
for (var i = 0; i < length; i++) {
var fragment = get_hydration_fragment(hydrating_node);
set_current_hydration_fragment(fragment);
if (!fragment) {
// If fragment is null, then that means that the server rendered less items than what
// the client code specifies -> break out and continue with client-side node creation
mismatch = true;
} else if (is_else) {
// Remove the each_else comment node or else it will confuse the subsequent hydration algorithm
/** @type {import('#client').TemplateNode[]} */ (current_hydration_fragment).shift();
break;
}
}
// this is separate to the previous block because `hydrating` might change
if (hydrating) {
var b_items = [];
b_items[i] = create_item(array[i], keys?.[i], i, render_fn, flags);
// Hydrate block
var hydration_list = /** @type {import('#client').TemplateNode[]} */ (
current_hydration_fragment
// TODO helperise this
hydrating_node = /** @type {import('#client').TemplateNode} */ (
/** @type {Node} */ (
/** @type {Node} */ (fragment[fragment.length - 1] || hydrating_node).nextSibling
).nextSibling
);
var hydrating_node = hydration_list[0];
for (var i = 0; i < length; i++) {
var fragment = get_hydration_fragment(hydrating_node);
set_current_hydration_fragment(fragment);
if (!fragment) {
// If fragment is null, then that means that the server rendered less items than what
// the client code specifies -> break out and continue with client-side node creation
mismatch = true;
break;
}
b_items[i] = create_item(array[i], keys?.[i], i, render_fn, flags);
// TODO helperise this
hydrating_node = /** @type {import('#client').TemplateNode} */ (
/** @type {Node} */ (
/** @type {Node} */ (fragment[fragment.length - 1] || hydrating_node).nextSibling
).nextSibling
);
}
}
remove_excess_hydration_nodes(hydration_list, hydrating_node);
remove_excess_hydration_nodes(hydration_list, hydrating_node);
state.items = b_items;
}
state.items = b_items;
}
if (!hydrating) {
// TODO add 'empty controlled block' optimisation here
reconcile_fn(array, state, anchor, render_fn, flags, keys);
}
if (!hydrating) {
// TODO add 'empty controlled block' optimisation here
reconcile_fn(array, state, anchor, render_fn, flags, keys);
}
if (fallback_fn !== null) {
if (length === 0) {
if (fallback) {
resume_effect(fallback);
} else {
fallback = render_effect(
() => {
var dom = fallback_fn(anchor);
return () => {
if (dom !== undefined) {
remove(dom);
}
};
},
block,
true
);
}
} else if (fallback !== null) {
pause_effect(fallback, () => {
fallback = null;
});
if (fallback_fn !== null) {
if (length === 0) {
if (fallback) {
resume_effect(fallback);
} else {
fallback = render_effect(() => {
var dom = fallback_fn(anchor);
return () => {
if (dom !== undefined) {
remove(dom);
}
};
}, true);
}
} else if (fallback !== null) {
pause_effect(fallback, () => {
fallback = null;
});
}
}
if (mismatch) {
// Set a fragment so that Svelte continues to operate in hydration mode
set_current_hydration_fragment([]);
}
},
block,
false
);
if (mismatch) {
// Set a fragment so that Svelte continues to operate in hydration mode
set_current_hydration_fragment([]);
}
});
effect.ondestroy = () => {
for (var item of state.items) {
@ -618,19 +607,15 @@ function create_item(value, key, index, render_fn, flags) {
try {
current_each_item = item;
item.e = render_effect(
() => {
var dom = render_fn(null, item.v, item.i);
item.e = render_effect(() => {
var dom = render_fn(null, item.v, item.i);
return () => {
if (dom !== undefined) {
remove(dom);
}
};
},
item,
true
);
return () => {
if (dom !== undefined) {
remove(dom);
}
};
}, true);
return item;
} finally {

@ -12,7 +12,6 @@ import {
render_effect,
resume_effect
} from '../../reactivity/effects.js';
import { create_block } from './utils.js';
/**
* @param {Comment} anchor
@ -23,8 +22,6 @@ import { create_block } from './utils.js';
* @returns {void}
*/
export function if_block(anchor, get_condition, consequent_fn, alternate_fn, elseif = false) {
const block = create_block();
hydrate_block_anchor(anchor);
/** @type {undefined | import('#client').Dom} */
@ -71,22 +68,18 @@ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, els
if (consequent_effect) {
resume_effect(consequent_effect);
} else {
consequent_effect = render_effect(
() => {
consequent_dom = consequent_fn(anchor);
return () => {
// TODO make this unnecessary by linking the dom to the effect,
// and removing automatically on teardown
if (consequent_dom !== undefined) {
remove(consequent_dom);
consequent_dom = undefined;
}
};
},
block,
true
);
consequent_effect = render_effect(() => {
consequent_dom = consequent_fn(anchor);
return () => {
// TODO make this unnecessary by linking the dom to the effect,
// and removing automatically on teardown
if (consequent_dom !== undefined) {
remove(consequent_dom);
consequent_dom = undefined;
}
};
}, true);
}
if (alternate_effect) {
@ -99,22 +92,18 @@ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, els
if (alternate_effect) {
resume_effect(alternate_effect);
} else if (alternate_fn) {
alternate_effect = render_effect(
() => {
alternate_dom = alternate_fn(anchor);
return () => {
// TODO make this unnecessary by linking the dom to the effect,
// and removing automatically on teardown
if (alternate_dom !== undefined) {
remove(alternate_dom);
alternate_dom = undefined;
}
};
},
block,
true
);
alternate_effect = render_effect(() => {
alternate_dom = alternate_fn(anchor);
return () => {
// TODO make this unnecessary by linking the dom to the effect,
// and removing automatically on teardown
if (alternate_dom !== undefined) {
remove(alternate_dom);
alternate_dom = undefined;
}
};
}, true);
}
if (consequent_effect) {
@ -129,7 +118,7 @@ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, els
// Set fragment so that Svelte continues to operate in hydration mode
set_current_hydration_fragment([]);
}
}, block);
});
if (elseif) {
if_effect.f |= IS_ELSEIF;

@ -3,7 +3,6 @@ import { hydrate_block_anchor } from '../hydration.js';
import { remove } from '../reconciler.js';
import { pause_effect, render_effect } from '../../reactivity/effects.js';
import { safe_not_equal } from '../../reactivity/equality.js';
import { create_block } from './utils.js';
/**
* @template V
@ -13,8 +12,6 @@ import { create_block } from './utils.js';
* @returns {void}
*/
export function key_block(anchor, get_key, render_fn) {
const block = create_block();
hydrate_block_anchor(anchor);
/** @type {V | typeof UNINITIALIZED} */
@ -30,37 +27,32 @@ export function key_block(anchor, get_key, render_fn) {
*/
let effects = new Set();
const key_effect = render_effect(
() => {
if (safe_not_equal(key, (key = get_key()))) {
if (effect) {
var e = effect;
pause_effect(e, () => {
effects.delete(e);
});
}
effect = render_effect(
() => {
const dom = render_fn(anchor);
return () => {
if (dom !== undefined) {
remove(dom);
}
};
},
block,
true,
true
);
effects.add(effect);
const key_effect = render_effect(() => {
if (safe_not_equal(key, (key = get_key()))) {
if (effect) {
var e = effect;
pause_effect(e, () => {
effects.delete(e);
});
}
},
block,
false
);
effect = render_effect(
() => {
const dom = render_fn(anchor);
return () => {
if (dom !== undefined) {
remove(dom);
}
};
},
true,
true
);
effects.add(effect);
}
});
key_effect.ondestroy = () => {
for (const e of effects) {

@ -1,7 +1,6 @@
import { render_effect } from '../../reactivity/effects.js';
import { remove } from '../reconciler.js';
import { untrack } from '../../runtime.js';
import { create_block } from './utils.js';
/**
* @template {(node: import('#client').TemplateNode, ...args: any[]) => import('#client').Dom} SnippetFn
@ -11,8 +10,6 @@ import { create_block } from './utils.js';
* @returns {void}
*/
export function snippet(get_snippet, node, ...args) {
const block = create_block();
/** @type {SnippetFn | null | undefined} */
var snippet_fn;
@ -30,5 +27,5 @@ export function snippet(get_snippet, node, ...args) {
remove(dom);
}
};
}, block);
});
}

@ -1,7 +1,6 @@
import { hydrate_block_anchor } from '../hydration.js';
import { pause_effect, render_effect } from '../../reactivity/effects.js';
import { remove } from '../reconciler.js';
import { create_block } from './utils.js';
import { current_effect } from '../../runtime.js';
// TODO this is very similar to `key`, can we deduplicate?
@ -15,8 +14,6 @@ import { current_effect } from '../../runtime.js';
* @returns {void}
*/
export function component(anchor, get_component, render_fn) {
const block = create_block();
hydrate_block_anchor(anchor);
/** @type {C} */
@ -32,40 +29,32 @@ export function component(anchor, get_component, render_fn) {
*/
let effects = new Set();
const component_effect = render_effect(
() => {
if (component === (component = get_component())) return;
const component_effect = render_effect(() => {
if (component === (component = get_component())) return;
if (effect) {
var e = effect;
pause_effect(e, () => {
effects.delete(e);
});
}
if (effect) {
var e = effect;
pause_effect(e, () => {
effects.delete(e);
});
}
if (component) {
effect = render_effect(
() => {
render_fn(component);
if (component) {
effect = render_effect(() => {
render_fn(component);
// `render_fn` doesn't return anything, and we can't reference `effect`
// yet, so we reference it indirectly as `current_effect`
const dom = /** @type {import('#client').Effect} */ (current_effect).dom;
// `render_fn` doesn't return anything, and we can't reference `effect`
// yet, so we reference it indirectly as `current_effect`
const dom = /** @type {import('#client').Effect} */ (current_effect).dom;
return () => {
if (dom !== null) remove(dom);
};
},
block,
true
);
return () => {
if (dom !== null) remove(dom);
};
}, true);
effects.add(effect);
}
},
block,
false
);
effects.add(effect);
}
});
component_effect.ondestroy = () => {
for (const e of effects) {

@ -11,7 +11,6 @@ import { remove } from '../reconciler.js';
import { is_array } from '../../utils.js';
import { set_should_intro } from '../../render.js';
import { current_each_item, set_current_each_item } from './each.js';
import { create_block } from './utils.js';
import { current_effect } from '../../runtime.js';
/**
@ -44,7 +43,6 @@ function swap_block_dom(effect, from, to) {
*/
export function element(anchor, get_tag, is_svg, render_fn) {
const parent_effect = /** @type {import('#client').Effect} */ (current_effect);
const block = create_block();
hydrate_block_anchor(anchor);
@ -72,7 +70,7 @@ export function element(anchor, get_tag, is_svg, render_fn) {
if (next_tag === tag) return;
// See explanation of `each_item_block` above
var previous_each_item_block = current_each_item;
var previous_each_item = current_each_item;
set_current_each_item(each_item_block);
// We try our best infering the namespace in case it's not possible to determine statically,
@ -104,46 +102,42 @@ export function element(anchor, get_tag, is_svg, render_fn) {
}
if (next_tag && next_tag !== current_tag) {
effect = render_effect(
() => {
const prev_element = element;
element = hydrating
? /** @type {Element} */ (current_hydration_fragment[0])
: ns
? document.createElementNS(ns, next_tag)
: document.createElement(next_tag);
if (render_fn) {
let anchor;
if (hydrating) {
// Use the existing ssr comment as the anchor so that the inner open and close
// methods can pick up the existing nodes correctly
anchor = /** @type {Comment} */ (element.firstChild);
} else {
anchor = empty();
element.appendChild(anchor);
}
render_fn(element, anchor);
effect = render_effect(() => {
const prev_element = element;
element = hydrating
? /** @type {Element} */ (current_hydration_fragment[0])
: ns
? document.createElementNS(ns, next_tag)
: document.createElement(next_tag);
if (render_fn) {
let anchor;
if (hydrating) {
// Use the existing ssr comment as the anchor so that the inner open and close
// methods can pick up the existing nodes correctly
anchor = /** @type {Comment} */ (element.firstChild);
} else {
anchor = empty();
element.appendChild(anchor);
}
render_fn(element, anchor);
}
anchor.before(element);
anchor.before(element);
if (prev_element) {
swap_block_dom(parent_effect, prev_element, element);
prev_element.remove();
}
},
block,
true
);
if (prev_element) {
swap_block_dom(parent_effect, prev_element, element);
prev_element.remove();
}
}, true);
}
tag = next_tag;
if (tag) current_tag = tag;
set_should_intro(true);
set_current_each_item(previous_each_item_block);
}, block);
set_current_each_item(previous_each_item);
});
wrapper.ondestroy = () => {
if (element !== null) {

@ -7,15 +7,12 @@ import {
import { empty } from '../operations.js';
import { render_effect } from '../../reactivity/effects.js';
import { remove } from '../reconciler.js';
import { create_block } from './utils.js';
/**
* @param {(anchor: Node | null) => import('#client').Dom | void} render_fn
* @returns {void}
*/
export function head(render_fn) {
const block = create_block();
// The head function may be called after the first hydration pass and ssr comment nodes may still be present,
// therefore we need to skip that when we detect that we're not in hydration mode.
let hydration_fragment = null;
@ -32,24 +29,20 @@ export function head(render_fn) {
/** @type {import('#client').Dom | null} */
var dom = null;
const head_effect = render_effect(
() => {
if (dom !== null) {
remove(dom);
head_effect.dom = dom = null;
}
const head_effect = render_effect(() => {
if (dom !== null) {
remove(dom);
head_effect.dom = dom = null;
}
let anchor = null;
if (!hydrating) {
anchor = empty();
document.head.appendChild(anchor);
}
let anchor = null;
if (!hydrating) {
anchor = empty();
document.head.appendChild(anchor);
}
dom = render_fn(anchor) ?? null;
},
block,
false
);
dom = render_fn(anchor) ?? null;
});
head_effect.ondestroy = () => {
if (dom !== null) {

@ -1,4 +0,0 @@
/** @returns {import('#client').Block} */
export function create_block() {
return {};
}

@ -16,7 +16,6 @@ export function autofocus(dom, value) {
dom.focus();
}
},
null,
true,
false
);

@ -29,11 +29,10 @@ import { noop } from '../../common.js';
* @param {import('./types.js').EffectType} type
* @param {(() => void | (() => void))} fn
* @param {boolean} sync
* @param {null | import('#client').Block} block
* @param {boolean} init
* @returns {import('#client').Effect}
*/
function create_effect(type, fn, sync, block = null, init = true) {
function create_effect(type, fn, sync, init = true) {
/** @type {import('#client').Effect} */
const signal = {
parent: current_effect,
@ -98,7 +97,7 @@ export function user_effect(fn) {
current_component_context !== null &&
!current_component_context.m;
const effect = create_effect(EFFECT, fn, false, null, !defer);
const effect = create_effect(EFFECT, fn, false, !defer);
if (defer) {
const context = /** @type {import('#client').ComponentContext} */ (current_component_context);
@ -114,7 +113,7 @@ export function user_effect(fn) {
* @returns {() => void}
*/
export function user_root_effect(fn) {
const effect = render_effect(fn, null, true);
const effect = render_effect(fn, true);
return () => {
destroy_effect(effect);
};
@ -215,17 +214,15 @@ export function invalidate_effect(fn) {
/**
* @param {(() => void)} fn
* @param {any} block
* @param {any} managed
* @param {any} sync
* @param {boolean} managed
* @param {boolean} sync
* @returns {import('#client').Effect}
*/
export function render_effect(fn, block = null, managed = false, sync = true) {
export function render_effect(fn, managed = false, sync = true) {
let flags = RENDER_EFFECT;
if (managed) {
flags |= MANAGED;
}
return create_effect(flags, /** @type {any} */ (fn), sync, block);
if (managed) flags |= MANAGED;
return create_effect(flags, /** @type {any} */ (fn), sync);
}
/**

@ -211,37 +211,30 @@ function _mount(Component, options) {
should_intro = options.intro ?? false;
/** @type {import('#client').Block} */
const block = {};
/** @type {Exports} */
// @ts-expect-error will be defined because the render effect runs synchronously
let component = undefined;
const effect = render_effect(
() => {
if (options.context) {
push({});
/** @type {import('../client/types.js').ComponentContext} */ (current_component_context).c =
options.context;
}
if (!options.props) {
options.props = /** @type {Props} */ ({});
}
if (options.events) {
// We can't spread the object or else we'd lose the state proxy stuff, if it is one
/** @type {any} */ (options.props).$$events = options.events;
}
component =
// @ts-expect-error the public typings are not what the actual function looks like
Component(options.anchor, options.props) || {};
if (options.context) {
pop();
}
},
block,
true
);
const effect = render_effect(() => {
if (options.context) {
push({});
/** @type {import('../client/types.js').ComponentContext} */ (current_component_context).c =
options.context;
}
if (!options.props) {
options.props = /** @type {Props} */ ({});
}
if (options.events) {
// We can't spread the object or else we'd lose the state proxy stuff, if it is one
/** @type {any} */ (options.props).$$events = options.events;
}
component =
// @ts-expect-error the public typings are not what the actual function looks like
Component(options.anchor, options.props) || {};
if (options.context) {
pop();
}
}, true);
const bound_event_listener = handle_event_propagation.bind(null, container);
const bound_document_event_listener = handle_event_propagation.bind(null, document);

@ -26,7 +26,6 @@ function run_test(runes: boolean, fn: (runes: boolean) => () => void) {
() => {
execute = fn(runes);
},
null,
true,
true
);

Loading…
Cancel
Save