pull/10948/head
Rich Harris 2 years ago
parent dc011bd25f
commit 18efffac33

@ -389,7 +389,7 @@ export const javascript_visitors_runes = {
const args = /** @type {import('estree').Expression[]} */ (
node.arguments.map((arg) => context.visit(arg))
);
return b.call('$.user_root_effect', ...args);
return b.call('$.effect_root', ...args);
}
if (rune === '$inspect' || rune === '$inspect().with') {

@ -2,7 +2,7 @@ export const DERIVED = 1 << 1;
export const EFFECT = 1 << 2;
export const PRE_EFFECT = 1 << 3;
export const RENDER_EFFECT = 1 << 4;
export const BLOCK_EFFECT = 1 << 4;
export const BLOCK_EFFECT = 1 << 5;
export const MANAGED = 1 << 6;
export const UNOWNED = 1 << 7;
export const CLEAN = 1 << 8;
@ -12,6 +12,7 @@ export const INERT = 1 << 11;
export const DESTROYED = 1 << 12;
export const IS_ELSEIF = 1 << 13;
export const EFFECT_RAN = 1 << 14;
export const ROOT_EFFECT = 1 << 15;
export const UNINITIALIZED = Symbol();
export const STATE_SYMBOL = Symbol('$state');

@ -24,7 +24,8 @@ import {
INERT,
IS_ELSEIF,
EFFECT_RAN,
BLOCK_EFFECT
BLOCK_EFFECT,
ROOT_EFFECT
} from '../constants.js';
import { set } from './sources.js';
import { noop } from '../../common.js';
@ -90,7 +91,7 @@ function create_effect(type, fn, sync, init = true) {
* @returns {boolean}
*/
export function effect_active() {
return current_effect ? (current_effect.f & MANAGED) === 0 : false;
return current_effect ? (current_effect.f & (MANAGED | ROOT_EFFECT)) === 0 : false;
}
/**
@ -147,13 +148,21 @@ export function user_pre_effect(fn) {
* @param {() => void | (() => void)} fn
* @returns {() => void}
*/
export function user_root_effect(fn) {
const effect = render_effect(fn, true);
export function effect_root(fn) {
const effect = create_effect(ROOT_EFFECT, () => untrack(fn), true);
return () => {
destroy_effect(effect);
};
}
/**
* TODO this is placeholder, just so we can get all the tests passing. eventually `_mount` should just create an effect root
* @param {() => void | (() => void)} fn
*/
export function fake_effect_root(fn) {
return create_effect(RENDER_EFFECT | ROOT_EFFECT, () => untrack(fn), true);
}
/**
* @param {() => void | (() => void)} fn
* @returns {import('#client').Effect}
@ -207,24 +216,20 @@ export function pre_effect(fn) {
/**
* @param {(() => void)} fn
* @param {boolean} managed
* @returns {import('#client').Effect}
*/
export function render_effect(fn, managed = false) {
let flags = RENDER_EFFECT;
if (managed) flags |= MANAGED;
return create_effect(flags, fn, true);
export function render_effect(fn) {
return create_effect(RENDER_EFFECT, fn, true);
}
/** @param {(() => void)} fn */
export function block(fn) {
return create_effect(BLOCK_EFFECT, fn, true);
return create_effect(RENDER_EFFECT | BLOCK_EFFECT, fn, true);
}
/** @param {(() => void)} fn */
export function branch(fn) {
return create_effect(EFFECT | RENDER_EFFECT | MANAGED, fn, true);
return create_effect(RENDER_EFFECT | MANAGED, fn, true);
}
/**

@ -8,8 +8,8 @@ import {
} from './dom/operations.js';
import { PassiveDelegatedEvents } from '../../constants.js';
import { remove } from './dom/reconciler.js';
import { flush_sync, push, pop, current_component_context } from './runtime.js';
import { render_effect, destroy_effect } from './reactivity/effects.js';
import { flush_sync, push, pop, current_component_context, untrack } from './runtime.js';
import { render_effect, destroy_effect, fake_effect_root } from './reactivity/effects.js';
import {
hydrate_anchor,
hydrate_nodes,
@ -19,6 +19,7 @@ import {
} from './dom/hydration.js';
import { array_from } from './utils.js';
import { handle_event_propagation } from './dom/elements/events.js';
import { ROOT_EFFECT } from './constants.js';
/** @type {Set<string>} */
export const all_registered_events = new Set();
@ -205,26 +206,28 @@ function _mount(Component, options) {
// @ts-expect-error will be defined because the render effect runs synchronously
let component = undefined;
const effect = render_effect(() => {
// TODO should this just be a root effect, rather than having the destroy logic live separately?
const effect = fake_effect_root(() => {
if (options.context) {
push({});
/** @type {import('../client/types.js').ComponentContext} */ (current_component_context).c =
options.context;
}
if (!options.props) {
options.props = /** @type {Props} */ ({});
var ctx = /** @type {import('#client').ComponentContext} */ (current_component_context);
ctx.c = options.context;
}
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) || {};
component = 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);

@ -22,7 +22,8 @@ import {
INERT,
MANAGED,
STATE_SYMBOL,
BLOCK_EFFECT
BLOCK_EFFECT,
ROOT_EFFECT
} from './constants.js';
import { flush_tasks } from './dom/task.js';
import { add_owner } from './dev/ownership.js';
@ -366,7 +367,7 @@ export function destroy_children(signal) {
// we don't want to destroy root effects when their parent effects are
// updated? seems leaky), but it looks like there are other managed
// effects aside from the immediate children of blocks
if ((effect.f & MANAGED) === 0) {
if ((effect.f & ROOT_EFFECT) === 0) {
destroy_effect(effect);
}
}

@ -1,4 +1,4 @@
import { pre_effect, user_root_effect } from '../internal/client/reactivity/effects.js';
import { pre_effect, effect_root } from '../internal/client/reactivity/effects.js';
import { flushSync } from '../main/main-client.js';
import { ReactiveMap } from './map.js';
import { assert, test } from 'vitest';
@ -14,7 +14,7 @@ test('map.values()', () => {
const log: any = [];
const cleanup = user_root_effect(() => {
const cleanup = effect_root(() => {
pre_effect(() => {
log.push(map.size);
});
@ -50,7 +50,7 @@ test('map.get(...)', () => {
const log: any = [];
const cleanup = user_root_effect(() => {
const cleanup = effect_root(() => {
pre_effect(() => {
log.push('get 1', map.get(1));
});
@ -86,7 +86,7 @@ test('map.has(...)', () => {
const log: any = [];
const cleanup = user_root_effect(() => {
const cleanup = effect_root(() => {
pre_effect(() => {
log.push('has 1', map.has(1));
});
@ -129,7 +129,7 @@ test('map handling of undefined values', () => {
const log: any = [];
const cleanup = user_root_effect(() => {
const cleanup = effect_root(() => {
map.set(1, undefined);
pre_effect(() => {

@ -1,4 +1,4 @@
import { pre_effect, user_root_effect } from '../internal/client/reactivity/effects.js';
import { pre_effect, effect_root } from '../internal/client/reactivity/effects.js';
import { flushSync } from '../main/main-client.js';
import { ReactiveSet } from './set.js';
import { assert, test } from 'vitest';
@ -8,7 +8,7 @@ test('set.values()', () => {
const log: any = [];
const cleanup = user_root_effect(() => {
const cleanup = effect_root(() => {
pre_effect(() => {
log.push(set.size);
});
@ -40,7 +40,7 @@ test('set.has(...)', () => {
const log: any = [];
const cleanup = user_root_effect(() => {
const cleanup = effect_root(() => {
pre_effect(() => {
log.push('has 1', set.has(1));
});

@ -24,7 +24,7 @@ function run_test(runes: boolean, fn: (runes: boolean) => () => void) {
let execute: any;
const signal = render_effect(() => {
execute = fn(runes);
}, true);
});
$.pop();
execute();
destroy_effect(signal);

Loading…
Cancel
Save