@vue/reactivity 3.3.7 → 3.4.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -98,117 +98,120 @@ function onScopeDispose(fn) {
98
98
  }
99
99
  }
100
100
 
101
- const createDep = (effects) => {
102
- const dep = new Set(effects);
103
- dep.w = 0;
104
- dep.n = 0;
105
- return dep;
106
- };
107
- const wasTracked = (dep) => (dep.w & trackOpBit) > 0;
108
- const newTracked = (dep) => (dep.n & trackOpBit) > 0;
109
- const initDepMarkers = ({ deps }) => {
110
- if (deps.length) {
111
- for (let i = 0; i < deps.length; i++) {
112
- deps[i].w |= trackOpBit;
113
- }
114
- }
115
- };
116
- const finalizeDepMarkers = (effect) => {
117
- const { deps } = effect;
118
- if (deps.length) {
119
- let ptr = 0;
120
- for (let i = 0; i < deps.length; i++) {
121
- const dep = deps[i];
122
- if (wasTracked(dep) && !newTracked(dep)) {
123
- dep.delete(effect);
124
- } else {
125
- deps[ptr++] = dep;
126
- }
127
- dep.w &= ~trackOpBit;
128
- dep.n &= ~trackOpBit;
129
- }
130
- deps.length = ptr;
131
- }
132
- };
133
-
134
- const targetMap = /* @__PURE__ */ new WeakMap();
135
- let effectTrackDepth = 0;
136
- let trackOpBit = 1;
137
- const maxMarkerBits = 30;
138
101
  let activeEffect;
139
- const ITERATE_KEY = Symbol("");
140
- const MAP_KEY_ITERATE_KEY = Symbol("");
141
102
  class ReactiveEffect {
142
- constructor(fn, scheduler = null, scope) {
103
+ constructor(fn, trigger, scheduler, scope) {
143
104
  this.fn = fn;
105
+ this.trigger = trigger;
144
106
  this.scheduler = scheduler;
145
107
  this.active = true;
146
108
  this.deps = [];
147
- this.parent = void 0;
109
+ /**
110
+ * @internal
111
+ */
112
+ this._dirtyLevel = 3;
113
+ /**
114
+ * @internal
115
+ */
116
+ this._trackId = 0;
117
+ /**
118
+ * @internal
119
+ */
120
+ this._runnings = 0;
121
+ /**
122
+ * @internal
123
+ */
124
+ this._queryings = 0;
125
+ /**
126
+ * @internal
127
+ */
128
+ this._depsLength = 0;
148
129
  recordEffectScope(this, scope);
149
130
  }
131
+ get dirty() {
132
+ if (this._dirtyLevel === 1) {
133
+ this._dirtyLevel = 0;
134
+ this._queryings++;
135
+ pauseTracking();
136
+ for (const dep of this.deps) {
137
+ if (dep.computed) {
138
+ triggerComputed(dep.computed);
139
+ if (this._dirtyLevel >= 2) {
140
+ break;
141
+ }
142
+ }
143
+ }
144
+ resetTracking();
145
+ this._queryings--;
146
+ }
147
+ return this._dirtyLevel >= 2;
148
+ }
149
+ set dirty(v) {
150
+ this._dirtyLevel = v ? 3 : 0;
151
+ }
150
152
  run() {
153
+ this._dirtyLevel = 0;
151
154
  if (!this.active) {
152
155
  return this.fn();
153
156
  }
154
- let parent = activeEffect;
155
157
  let lastShouldTrack = shouldTrack;
156
- while (parent) {
157
- if (parent === this) {
158
- return;
159
- }
160
- parent = parent.parent;
161
- }
158
+ let lastEffect = activeEffect;
162
159
  try {
163
- this.parent = activeEffect;
164
- activeEffect = this;
165
160
  shouldTrack = true;
166
- trackOpBit = 1 << ++effectTrackDepth;
167
- if (effectTrackDepth <= maxMarkerBits) {
168
- initDepMarkers(this);
169
- } else {
170
- cleanupEffect(this);
171
- }
161
+ activeEffect = this;
162
+ this._runnings++;
163
+ preCleanupEffect(this);
172
164
  return this.fn();
173
165
  } finally {
174
- if (effectTrackDepth <= maxMarkerBits) {
175
- finalizeDepMarkers(this);
176
- }
177
- trackOpBit = 1 << --effectTrackDepth;
178
- activeEffect = this.parent;
166
+ postCleanupEffect(this);
167
+ this._runnings--;
168
+ activeEffect = lastEffect;
179
169
  shouldTrack = lastShouldTrack;
180
- this.parent = void 0;
181
- if (this.deferStop) {
182
- this.stop();
183
- }
184
170
  }
185
171
  }
186
172
  stop() {
187
- if (activeEffect === this) {
188
- this.deferStop = true;
189
- } else if (this.active) {
190
- cleanupEffect(this);
191
- if (this.onStop) {
192
- this.onStop();
193
- }
173
+ var _a;
174
+ if (this.active) {
175
+ preCleanupEffect(this);
176
+ postCleanupEffect(this);
177
+ (_a = this.onStop) == null ? void 0 : _a.call(this);
194
178
  this.active = false;
195
179
  }
196
180
  }
197
181
  }
198
- function cleanupEffect(effect2) {
199
- const { deps } = effect2;
200
- if (deps.length) {
201
- for (let i = 0; i < deps.length; i++) {
202
- deps[i].delete(effect2);
182
+ function triggerComputed(computed) {
183
+ return computed.value;
184
+ }
185
+ function preCleanupEffect(effect2) {
186
+ effect2._trackId++;
187
+ effect2._depsLength = 0;
188
+ }
189
+ function postCleanupEffect(effect2) {
190
+ if (effect2.deps && effect2.deps.length > effect2._depsLength) {
191
+ for (let i = effect2._depsLength; i < effect2.deps.length; i++) {
192
+ cleanupDepEffect(effect2.deps[i], effect2);
193
+ }
194
+ effect2.deps.length = effect2._depsLength;
195
+ }
196
+ }
197
+ function cleanupDepEffect(dep, effect2) {
198
+ const trackId = dep.get(effect2);
199
+ if (trackId !== void 0 && effect2._trackId !== trackId) {
200
+ dep.delete(effect2);
201
+ if (dep.size === 0) {
202
+ dep.cleanup();
203
203
  }
204
- deps.length = 0;
205
204
  }
206
205
  }
207
206
  function effect(fn, options) {
208
207
  if (fn.effect instanceof ReactiveEffect) {
209
208
  fn = fn.effect.fn;
210
209
  }
211
- const _effect = new ReactiveEffect(fn);
210
+ const _effect = new ReactiveEffect(fn, shared.NOOP, () => {
211
+ if (_effect.dirty) {
212
+ _effect.run();
213
+ }
214
+ });
212
215
  if (options) {
213
216
  shared.extend(_effect, options);
214
217
  if (options.scope)
@@ -225,6 +228,7 @@ function stop(runner) {
225
228
  runner.effect.stop();
226
229
  }
227
230
  let shouldTrack = true;
231
+ let pauseScheduleStack = 0;
228
232
  const trackStack = [];
229
233
  function pauseTracking() {
230
234
  trackStack.push(shouldTrack);
@@ -238,6 +242,60 @@ function resetTracking() {
238
242
  const last = trackStack.pop();
239
243
  shouldTrack = last === void 0 ? true : last;
240
244
  }
245
+ function pauseScheduling() {
246
+ pauseScheduleStack++;
247
+ }
248
+ function resetScheduling() {
249
+ pauseScheduleStack--;
250
+ while (!pauseScheduleStack && queueEffectSchedulers.length) {
251
+ queueEffectSchedulers.shift()();
252
+ }
253
+ }
254
+ function trackEffect(effect2, dep, debuggerEventExtraInfo) {
255
+ if (dep.get(effect2) !== effect2._trackId) {
256
+ dep.set(effect2, effect2._trackId);
257
+ const oldDep = effect2.deps[effect2._depsLength];
258
+ if (oldDep !== dep) {
259
+ if (oldDep) {
260
+ cleanupDepEffect(oldDep, effect2);
261
+ }
262
+ effect2.deps[effect2._depsLength++] = dep;
263
+ } else {
264
+ effect2._depsLength++;
265
+ }
266
+ }
267
+ }
268
+ const queueEffectSchedulers = [];
269
+ function triggerEffects(dep, dirtyLevel, debuggerEventExtraInfo) {
270
+ pauseScheduling();
271
+ for (const effect2 of dep.keys()) {
272
+ if (!effect2.allowRecurse && effect2._runnings) {
273
+ continue;
274
+ }
275
+ if (effect2._dirtyLevel < dirtyLevel && (!effect2._runnings || dirtyLevel !== 2)) {
276
+ const lastDirtyLevel = effect2._dirtyLevel;
277
+ effect2._dirtyLevel = dirtyLevel;
278
+ if (lastDirtyLevel === 0 && (!effect2._queryings || dirtyLevel !== 2)) {
279
+ effect2.trigger();
280
+ if (effect2.scheduler) {
281
+ queueEffectSchedulers.push(effect2.scheduler);
282
+ }
283
+ }
284
+ }
285
+ }
286
+ resetScheduling();
287
+ }
288
+
289
+ const createDep = (cleanup, computed) => {
290
+ const dep = /* @__PURE__ */ new Map();
291
+ dep.cleanup = cleanup;
292
+ dep.computed = computed;
293
+ return dep;
294
+ };
295
+
296
+ const targetMap = /* @__PURE__ */ new WeakMap();
297
+ const ITERATE_KEY = Symbol("");
298
+ const MAP_KEY_ITERATE_KEY = Symbol("");
241
299
  function track(target, type, key) {
242
300
  if (shouldTrack && activeEffect) {
243
301
  let depsMap = targetMap.get(target);
@@ -246,24 +304,11 @@ function track(target, type, key) {
246
304
  }
247
305
  let dep = depsMap.get(key);
248
306
  if (!dep) {
249
- depsMap.set(key, dep = createDep());
250
- }
251
- trackEffects(dep);
252
- }
253
- }
254
- function trackEffects(dep, debuggerEventExtraInfo) {
255
- let shouldTrack2 = false;
256
- if (effectTrackDepth <= maxMarkerBits) {
257
- if (!newTracked(dep)) {
258
- dep.n |= trackOpBit;
259
- shouldTrack2 = !wasTracked(dep);
307
+ depsMap.set(key, dep = createDep(() => depsMap.delete(key)));
260
308
  }
261
- } else {
262
- shouldTrack2 = !dep.has(activeEffect);
263
- }
264
- if (shouldTrack2) {
265
- dep.add(activeEffect);
266
- activeEffect.deps.push(dep);
309
+ trackEffect(
310
+ activeEffect,
311
+ dep);
267
312
  }
268
313
  }
269
314
  function trigger(target, type, key, newValue, oldValue, oldTarget) {
@@ -311,45 +356,15 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) {
311
356
  break;
312
357
  }
313
358
  }
314
- if (deps.length === 1) {
315
- if (deps[0]) {
316
- {
317
- triggerEffects(deps[0]);
318
- }
319
- }
320
- } else {
321
- const effects = [];
322
- for (const dep of deps) {
323
- if (dep) {
324
- effects.push(...dep);
325
- }
326
- }
327
- {
328
- triggerEffects(createDep(effects));
329
- }
330
- }
331
- }
332
- function triggerEffects(dep, debuggerEventExtraInfo) {
333
- const effects = shared.isArray(dep) ? dep : [...dep];
334
- for (const effect2 of effects) {
335
- if (effect2.computed) {
336
- triggerEffect(effect2);
337
- }
338
- }
339
- for (const effect2 of effects) {
340
- if (!effect2.computed) {
341
- triggerEffect(effect2);
342
- }
343
- }
344
- }
345
- function triggerEffect(effect2, debuggerEventExtraInfo) {
346
- if (effect2 !== activeEffect || effect2.allowRecurse) {
347
- if (effect2.scheduler) {
348
- effect2.scheduler();
349
- } else {
350
- effect2.run();
359
+ pauseScheduling();
360
+ for (const dep of deps) {
361
+ if (dep) {
362
+ triggerEffects(
363
+ dep,
364
+ 3);
351
365
  }
352
366
  }
367
+ resetScheduling();
353
368
  }
354
369
  function getDepFromReactive(object, key) {
355
370
  var _a;
@@ -380,7 +395,9 @@ function createArrayInstrumentations() {
380
395
  ["push", "pop", "shift", "unshift", "splice"].forEach((key) => {
381
396
  instrumentations[key] = function(...args) {
382
397
  pauseTracking();
398
+ pauseScheduling();
383
399
  const res = toRaw(this)[key].apply(this, args);
400
+ resetScheduling();
384
401
  resetTracking();
385
402
  return res;
386
403
  };
@@ -883,21 +900,74 @@ function markRaw(value) {
883
900
  const toReactive = (value) => shared.isObject(value) ? reactive(value) : value;
884
901
  const toReadonly = (value) => shared.isObject(value) ? readonly(value) : value;
885
902
 
903
+ class ComputedRefImpl {
904
+ constructor(getter, _setter, isReadonly, isSSR) {
905
+ this._setter = _setter;
906
+ this.dep = void 0;
907
+ this.__v_isRef = true;
908
+ this["__v_isReadonly"] = false;
909
+ this.effect = new ReactiveEffect(getter, () => {
910
+ triggerRefValue(this, 1);
911
+ });
912
+ this.effect.computed = this;
913
+ this.effect.active = this._cacheable = !isSSR;
914
+ this["__v_isReadonly"] = isReadonly;
915
+ }
916
+ get value() {
917
+ const self = toRaw(this);
918
+ trackRefValue(self);
919
+ if (!self._cacheable || self.effect.dirty) {
920
+ if (shared.hasChanged(self._value, self._value = self.effect.run())) {
921
+ triggerRefValue(self, 2);
922
+ }
923
+ }
924
+ return self._value;
925
+ }
926
+ set value(newValue) {
927
+ this._setter(newValue);
928
+ }
929
+ // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x
930
+ get _dirty() {
931
+ return this.effect.dirty;
932
+ }
933
+ set _dirty(v) {
934
+ this.effect.dirty = v;
935
+ }
936
+ // #endregion
937
+ }
938
+ function computed(getterOrOptions, debugOptions, isSSR = false) {
939
+ let getter;
940
+ let setter;
941
+ const onlyGetter = shared.isFunction(getterOrOptions);
942
+ if (onlyGetter) {
943
+ getter = getterOrOptions;
944
+ setter = shared.NOOP;
945
+ } else {
946
+ getter = getterOrOptions.get;
947
+ setter = getterOrOptions.set;
948
+ }
949
+ const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
950
+ return cRef;
951
+ }
952
+
886
953
  function trackRefValue(ref2) {
887
954
  if (shouldTrack && activeEffect) {
888
955
  ref2 = toRaw(ref2);
889
- {
890
- trackEffects(ref2.dep || (ref2.dep = createDep()));
891
- }
956
+ trackEffect(
957
+ activeEffect,
958
+ ref2.dep || (ref2.dep = createDep(
959
+ () => ref2.dep = void 0,
960
+ ref2 instanceof ComputedRefImpl ? ref2 : void 0
961
+ )));
892
962
  }
893
963
  }
894
- function triggerRefValue(ref2, newVal) {
964
+ function triggerRefValue(ref2, dirtyLevel = 3, newVal) {
895
965
  ref2 = toRaw(ref2);
896
966
  const dep = ref2.dep;
897
967
  if (dep) {
898
- {
899
- triggerEffects(dep);
900
- }
968
+ triggerEffects(
969
+ dep,
970
+ dirtyLevel);
901
971
  }
902
972
  }
903
973
  function isRef(r) {
@@ -933,12 +1003,12 @@ class RefImpl {
933
1003
  if (shared.hasChanged(newVal, this._rawValue)) {
934
1004
  this._rawValue = newVal;
935
1005
  this._value = useDirectValue ? newVal : toReactive(newVal);
936
- triggerRefValue(this);
1006
+ triggerRefValue(this, 3);
937
1007
  }
938
1008
  }
939
1009
  }
940
1010
  function triggerRef(ref2) {
941
- triggerRefValue(ref2);
1011
+ triggerRefValue(ref2, 3);
942
1012
  }
943
1013
  function unref(ref2) {
944
1014
  return isRef(ref2) ? ref2.value : ref2;
@@ -1033,121 +1103,7 @@ function propertyToRef(source, key, defaultValue) {
1033
1103
  return isRef(val) ? val : new ObjectRefImpl(source, key, defaultValue);
1034
1104
  }
1035
1105
 
1036
- class ComputedRefImpl {
1037
- constructor(getter, _setter, isReadonly, isSSR) {
1038
- this._setter = _setter;
1039
- this.dep = void 0;
1040
- this.__v_isRef = true;
1041
- this["__v_isReadonly"] = false;
1042
- this._dirty = true;
1043
- this.effect = new ReactiveEffect(getter, () => {
1044
- if (!this._dirty) {
1045
- this._dirty = true;
1046
- triggerRefValue(this);
1047
- }
1048
- });
1049
- this.effect.computed = this;
1050
- this.effect.active = this._cacheable = !isSSR;
1051
- this["__v_isReadonly"] = isReadonly;
1052
- }
1053
- get value() {
1054
- const self = toRaw(this);
1055
- trackRefValue(self);
1056
- if (self._dirty || !self._cacheable) {
1057
- self._dirty = false;
1058
- self._value = self.effect.run();
1059
- }
1060
- return self._value;
1061
- }
1062
- set value(newValue) {
1063
- this._setter(newValue);
1064
- }
1065
- }
1066
- function computed(getterOrOptions, debugOptions, isSSR = false) {
1067
- let getter;
1068
- let setter;
1069
- const onlyGetter = shared.isFunction(getterOrOptions);
1070
- if (onlyGetter) {
1071
- getter = getterOrOptions;
1072
- setter = shared.NOOP;
1073
- } else {
1074
- getter = getterOrOptions.get;
1075
- setter = getterOrOptions.set;
1076
- }
1077
- const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
1078
- return cRef;
1079
- }
1080
-
1081
- const tick = /* @__PURE__ */ Promise.resolve();
1082
- const queue = [];
1083
- let queued = false;
1084
- const scheduler = (fn) => {
1085
- queue.push(fn);
1086
- if (!queued) {
1087
- queued = true;
1088
- tick.then(flush);
1089
- }
1090
- };
1091
- const flush = () => {
1092
- for (let i = 0; i < queue.length; i++) {
1093
- queue[i]();
1094
- }
1095
- queue.length = 0;
1096
- queued = false;
1097
- };
1098
- class DeferredComputedRefImpl {
1099
- constructor(getter) {
1100
- this.dep = void 0;
1101
- this._dirty = true;
1102
- this.__v_isRef = true;
1103
- this["__v_isReadonly"] = true;
1104
- let compareTarget;
1105
- let hasCompareTarget = false;
1106
- let scheduled = false;
1107
- this.effect = new ReactiveEffect(getter, (computedTrigger) => {
1108
- if (this.dep) {
1109
- if (computedTrigger) {
1110
- compareTarget = this._value;
1111
- hasCompareTarget = true;
1112
- } else if (!scheduled) {
1113
- const valueToCompare = hasCompareTarget ? compareTarget : this._value;
1114
- scheduled = true;
1115
- hasCompareTarget = false;
1116
- scheduler(() => {
1117
- if (this.effect.active && this._get() !== valueToCompare) {
1118
- triggerRefValue(this);
1119
- }
1120
- scheduled = false;
1121
- });
1122
- }
1123
- for (const e of this.dep) {
1124
- if (e.computed instanceof DeferredComputedRefImpl) {
1125
- e.scheduler(
1126
- true
1127
- /* computedTrigger */
1128
- );
1129
- }
1130
- }
1131
- }
1132
- this._dirty = true;
1133
- });
1134
- this.effect.computed = this;
1135
- }
1136
- _get() {
1137
- if (this._dirty) {
1138
- this._dirty = false;
1139
- return this._value = this.effect.run();
1140
- }
1141
- return this._value;
1142
- }
1143
- get value() {
1144
- trackRefValue(this);
1145
- return toRaw(this)._get();
1146
- }
1147
- }
1148
- function deferredComputed(getter) {
1149
- return new DeferredComputedRefImpl(getter);
1150
- }
1106
+ const deferredComputed = computed;
1151
1107
 
1152
1108
  exports.EffectScope = EffectScope;
1153
1109
  exports.ITERATE_KEY = ITERATE_KEY;
@@ -1166,11 +1122,13 @@ exports.isRef = isRef;
1166
1122
  exports.isShallow = isShallow;
1167
1123
  exports.markRaw = markRaw;
1168
1124
  exports.onScopeDispose = onScopeDispose;
1125
+ exports.pauseScheduling = pauseScheduling;
1169
1126
  exports.pauseTracking = pauseTracking;
1170
1127
  exports.proxyRefs = proxyRefs;
1171
1128
  exports.reactive = reactive;
1172
1129
  exports.readonly = readonly;
1173
1130
  exports.ref = ref;
1131
+ exports.resetScheduling = resetScheduling;
1174
1132
  exports.resetTracking = resetTracking;
1175
1133
  exports.shallowReactive = shallowReactive;
1176
1134
  exports.shallowReadonly = shallowReadonly;