@vue/reactivity 3.3.9 → 3.4.0-alpha.2

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.
@@ -108,117 +108,120 @@ function onScopeDispose(fn) {
108
108
  }
109
109
  }
110
110
 
111
- const createDep = (effects) => {
112
- const dep = new Set(effects);
113
- dep.w = 0;
114
- dep.n = 0;
115
- return dep;
116
- };
117
- const wasTracked = (dep) => (dep.w & trackOpBit) > 0;
118
- const newTracked = (dep) => (dep.n & trackOpBit) > 0;
119
- const initDepMarkers = ({ deps }) => {
120
- if (deps.length) {
121
- for (let i = 0; i < deps.length; i++) {
122
- deps[i].w |= trackOpBit;
123
- }
124
- }
125
- };
126
- const finalizeDepMarkers = (effect) => {
127
- const { deps } = effect;
128
- if (deps.length) {
129
- let ptr = 0;
130
- for (let i = 0; i < deps.length; i++) {
131
- const dep = deps[i];
132
- if (wasTracked(dep) && !newTracked(dep)) {
133
- dep.delete(effect);
134
- } else {
135
- deps[ptr++] = dep;
136
- }
137
- dep.w &= ~trackOpBit;
138
- dep.n &= ~trackOpBit;
139
- }
140
- deps.length = ptr;
141
- }
142
- };
143
-
144
- const targetMap = /* @__PURE__ */ new WeakMap();
145
- let effectTrackDepth = 0;
146
- let trackOpBit = 1;
147
- const maxMarkerBits = 30;
148
111
  let activeEffect;
149
- const ITERATE_KEY = Symbol("iterate" );
150
- const MAP_KEY_ITERATE_KEY = Symbol("Map key iterate" );
151
112
  class ReactiveEffect {
152
- constructor(fn, scheduler = null, scope) {
113
+ constructor(fn, trigger, scheduler, scope) {
153
114
  this.fn = fn;
115
+ this.trigger = trigger;
154
116
  this.scheduler = scheduler;
155
117
  this.active = true;
156
118
  this.deps = [];
157
- this.parent = void 0;
119
+ /**
120
+ * @internal
121
+ */
122
+ this._dirtyLevel = 3;
123
+ /**
124
+ * @internal
125
+ */
126
+ this._trackId = 0;
127
+ /**
128
+ * @internal
129
+ */
130
+ this._runnings = 0;
131
+ /**
132
+ * @internal
133
+ */
134
+ this._queryings = 0;
135
+ /**
136
+ * @internal
137
+ */
138
+ this._depsLength = 0;
158
139
  recordEffectScope(this, scope);
159
140
  }
141
+ get dirty() {
142
+ if (this._dirtyLevel === 1) {
143
+ this._dirtyLevel = 0;
144
+ this._queryings++;
145
+ pauseTracking();
146
+ for (const dep of this.deps) {
147
+ if (dep.computed) {
148
+ triggerComputed(dep.computed);
149
+ if (this._dirtyLevel >= 2) {
150
+ break;
151
+ }
152
+ }
153
+ }
154
+ resetTracking();
155
+ this._queryings--;
156
+ }
157
+ return this._dirtyLevel >= 2;
158
+ }
159
+ set dirty(v) {
160
+ this._dirtyLevel = v ? 3 : 0;
161
+ }
160
162
  run() {
163
+ this._dirtyLevel = 0;
161
164
  if (!this.active) {
162
165
  return this.fn();
163
166
  }
164
- let parent = activeEffect;
165
167
  let lastShouldTrack = shouldTrack;
166
- while (parent) {
167
- if (parent === this) {
168
- return;
169
- }
170
- parent = parent.parent;
171
- }
168
+ let lastEffect = activeEffect;
172
169
  try {
173
- this.parent = activeEffect;
174
- activeEffect = this;
175
170
  shouldTrack = true;
176
- trackOpBit = 1 << ++effectTrackDepth;
177
- if (effectTrackDepth <= maxMarkerBits) {
178
- initDepMarkers(this);
179
- } else {
180
- cleanupEffect(this);
181
- }
171
+ activeEffect = this;
172
+ this._runnings++;
173
+ preCleanupEffect(this);
182
174
  return this.fn();
183
175
  } finally {
184
- if (effectTrackDepth <= maxMarkerBits) {
185
- finalizeDepMarkers(this);
186
- }
187
- trackOpBit = 1 << --effectTrackDepth;
188
- activeEffect = this.parent;
176
+ postCleanupEffect(this);
177
+ this._runnings--;
178
+ activeEffect = lastEffect;
189
179
  shouldTrack = lastShouldTrack;
190
- this.parent = void 0;
191
- if (this.deferStop) {
192
- this.stop();
193
- }
194
180
  }
195
181
  }
196
182
  stop() {
197
- if (activeEffect === this) {
198
- this.deferStop = true;
199
- } else if (this.active) {
200
- cleanupEffect(this);
201
- if (this.onStop) {
202
- this.onStop();
203
- }
183
+ var _a;
184
+ if (this.active) {
185
+ preCleanupEffect(this);
186
+ postCleanupEffect(this);
187
+ (_a = this.onStop) == null ? void 0 : _a.call(this);
204
188
  this.active = false;
205
189
  }
206
190
  }
207
191
  }
208
- function cleanupEffect(effect2) {
209
- const { deps } = effect2;
210
- if (deps.length) {
211
- for (let i = 0; i < deps.length; i++) {
212
- deps[i].delete(effect2);
192
+ function triggerComputed(computed) {
193
+ return computed.value;
194
+ }
195
+ function preCleanupEffect(effect2) {
196
+ effect2._trackId++;
197
+ effect2._depsLength = 0;
198
+ }
199
+ function postCleanupEffect(effect2) {
200
+ if (effect2.deps && effect2.deps.length > effect2._depsLength) {
201
+ for (let i = effect2._depsLength; i < effect2.deps.length; i++) {
202
+ cleanupDepEffect(effect2.deps[i], effect2);
203
+ }
204
+ effect2.deps.length = effect2._depsLength;
205
+ }
206
+ }
207
+ function cleanupDepEffect(dep, effect2) {
208
+ const trackId = dep.get(effect2);
209
+ if (trackId !== void 0 && effect2._trackId !== trackId) {
210
+ dep.delete(effect2);
211
+ if (dep.size === 0) {
212
+ dep.cleanup();
213
213
  }
214
- deps.length = 0;
215
214
  }
216
215
  }
217
216
  function effect(fn, options) {
218
217
  if (fn.effect instanceof ReactiveEffect) {
219
218
  fn = fn.effect.fn;
220
219
  }
221
- const _effect = new ReactiveEffect(fn);
220
+ const _effect = new ReactiveEffect(fn, shared.NOOP, () => {
221
+ if (_effect.dirty) {
222
+ _effect.run();
223
+ }
224
+ });
222
225
  if (options) {
223
226
  shared.extend(_effect, options);
224
227
  if (options.scope)
@@ -235,6 +238,7 @@ function stop(runner) {
235
238
  runner.effect.stop();
236
239
  }
237
240
  let shouldTrack = true;
241
+ let pauseScheduleStack = 0;
238
242
  const trackStack = [];
239
243
  function pauseTracking() {
240
244
  trackStack.push(shouldTrack);
@@ -248,6 +252,68 @@ function resetTracking() {
248
252
  const last = trackStack.pop();
249
253
  shouldTrack = last === void 0 ? true : last;
250
254
  }
255
+ function pauseScheduling() {
256
+ pauseScheduleStack++;
257
+ }
258
+ function resetScheduling() {
259
+ pauseScheduleStack--;
260
+ while (!pauseScheduleStack && queueEffectSchedulers.length) {
261
+ queueEffectSchedulers.shift()();
262
+ }
263
+ }
264
+ function trackEffect(effect2, dep, debuggerEventExtraInfo) {
265
+ var _a;
266
+ if (dep.get(effect2) !== effect2._trackId) {
267
+ dep.set(effect2, effect2._trackId);
268
+ const oldDep = effect2.deps[effect2._depsLength];
269
+ if (oldDep !== dep) {
270
+ if (oldDep) {
271
+ cleanupDepEffect(oldDep, effect2);
272
+ }
273
+ effect2.deps[effect2._depsLength++] = dep;
274
+ } else {
275
+ effect2._depsLength++;
276
+ }
277
+ {
278
+ (_a = effect2.onTrack) == null ? void 0 : _a.call(effect2, shared.extend({ effect: effect2 }, debuggerEventExtraInfo));
279
+ }
280
+ }
281
+ }
282
+ const queueEffectSchedulers = [];
283
+ function triggerEffects(dep, dirtyLevel, debuggerEventExtraInfo) {
284
+ var _a;
285
+ pauseScheduling();
286
+ for (const effect2 of dep.keys()) {
287
+ if (!effect2.allowRecurse && effect2._runnings) {
288
+ continue;
289
+ }
290
+ if (effect2._dirtyLevel < dirtyLevel && (!effect2._runnings || dirtyLevel !== 2)) {
291
+ const lastDirtyLevel = effect2._dirtyLevel;
292
+ effect2._dirtyLevel = dirtyLevel;
293
+ if (lastDirtyLevel === 0 && (!effect2._queryings || dirtyLevel !== 2)) {
294
+ {
295
+ (_a = effect2.onTrigger) == null ? void 0 : _a.call(effect2, shared.extend({ effect: effect2 }, debuggerEventExtraInfo));
296
+ }
297
+ effect2.trigger();
298
+ if (effect2.scheduler) {
299
+ queueEffectSchedulers.push(effect2.scheduler);
300
+ }
301
+ }
302
+ }
303
+ }
304
+ resetScheduling();
305
+ }
306
+
307
+ const createDep = (cleanup, computed) => {
308
+ const dep = /* @__PURE__ */ new Map();
309
+ dep.cleanup = cleanup;
310
+ dep.computed = computed;
311
+ return dep;
312
+ };
313
+
314
+ const targetMap = /* @__PURE__ */ new WeakMap();
315
+ const ITERATE_KEY = Symbol("iterate" );
316
+ const MAP_KEY_ITERATE_KEY = Symbol("Map key iterate" );
251
317
  function track(target, type, key) {
252
318
  if (shouldTrack && activeEffect) {
253
319
  let depsMap = targetMap.get(target);
@@ -256,35 +322,17 @@ function track(target, type, key) {
256
322
  }
257
323
  let dep = depsMap.get(key);
258
324
  if (!dep) {
259
- depsMap.set(key, dep = createDep());
260
- }
261
- const eventInfo = { effect: activeEffect, target, type, key } ;
262
- trackEffects(dep, eventInfo);
263
- }
264
- }
265
- function trackEffects(dep, debuggerEventExtraInfo) {
266
- let shouldTrack2 = false;
267
- if (effectTrackDepth <= maxMarkerBits) {
268
- if (!newTracked(dep)) {
269
- dep.n |= trackOpBit;
270
- shouldTrack2 = !wasTracked(dep);
271
- }
272
- } else {
273
- shouldTrack2 = !dep.has(activeEffect);
274
- }
275
- if (shouldTrack2) {
276
- dep.add(activeEffect);
277
- activeEffect.deps.push(dep);
278
- if (activeEffect.onTrack) {
279
- activeEffect.onTrack(
280
- shared.extend(
281
- {
282
- effect: activeEffect
283
- },
284
- debuggerEventExtraInfo
285
- )
286
- );
325
+ depsMap.set(key, dep = createDep(() => depsMap.delete(key)));
287
326
  }
327
+ trackEffect(
328
+ activeEffect,
329
+ dep,
330
+ {
331
+ target,
332
+ type,
333
+ key
334
+ }
335
+ );
288
336
  }
289
337
  }
290
338
  function trigger(target, type, key, newValue, oldValue, oldTarget) {
@@ -332,49 +380,24 @@ function trigger(target, type, key, newValue, oldValue, oldTarget) {
332
380
  break;
333
381
  }
334
382
  }
335
- const eventInfo = { target, type, key, newValue, oldValue, oldTarget } ;
336
- if (deps.length === 1) {
337
- if (deps[0]) {
338
- {
339
- triggerEffects(deps[0], eventInfo);
340
- }
341
- }
342
- } else {
343
- const effects = [];
344
- for (const dep of deps) {
345
- if (dep) {
346
- effects.push(...dep);
347
- }
348
- }
349
- {
350
- triggerEffects(createDep(effects), eventInfo);
351
- }
352
- }
353
- }
354
- function triggerEffects(dep, debuggerEventExtraInfo) {
355
- const effects = shared.isArray(dep) ? dep : [...dep];
356
- for (const effect2 of effects) {
357
- if (effect2.computed) {
358
- triggerEffect(effect2, debuggerEventExtraInfo);
359
- }
360
- }
361
- for (const effect2 of effects) {
362
- if (!effect2.computed) {
363
- triggerEffect(effect2, debuggerEventExtraInfo);
364
- }
365
- }
366
- }
367
- function triggerEffect(effect2, debuggerEventExtraInfo) {
368
- if (effect2 !== activeEffect || effect2.allowRecurse) {
369
- if (effect2.onTrigger) {
370
- effect2.onTrigger(shared.extend({ effect: effect2 }, debuggerEventExtraInfo));
371
- }
372
- if (effect2.scheduler) {
373
- effect2.scheduler();
374
- } else {
375
- effect2.run();
383
+ pauseScheduling();
384
+ for (const dep of deps) {
385
+ if (dep) {
386
+ triggerEffects(
387
+ dep,
388
+ 3,
389
+ {
390
+ target,
391
+ type,
392
+ key,
393
+ newValue,
394
+ oldValue,
395
+ oldTarget
396
+ }
397
+ );
376
398
  }
377
399
  }
400
+ resetScheduling();
378
401
  }
379
402
  function getDepFromReactive(object, key) {
380
403
  var _a;
@@ -405,7 +428,9 @@ function createArrayInstrumentations() {
405
428
  ["push", "pop", "shift", "unshift", "splice"].forEach((key) => {
406
429
  instrumentations[key] = function(...args) {
407
430
  pauseTracking();
431
+ pauseScheduling();
408
432
  const res = toRaw(this)[key].apply(this, args);
433
+ resetScheduling();
409
434
  resetTracking();
410
435
  return res;
411
436
  };
@@ -944,30 +969,94 @@ function markRaw(value) {
944
969
  const toReactive = (value) => shared.isObject(value) ? reactive(value) : value;
945
970
  const toReadonly = (value) => shared.isObject(value) ? readonly(value) : value;
946
971
 
972
+ class ComputedRefImpl {
973
+ constructor(getter, _setter, isReadonly, isSSR) {
974
+ this._setter = _setter;
975
+ this.dep = void 0;
976
+ this.__v_isRef = true;
977
+ this["__v_isReadonly"] = false;
978
+ this.effect = new ReactiveEffect(
979
+ () => getter(this._value),
980
+ () => triggerRefValue(this, 1)
981
+ );
982
+ this.effect.computed = this;
983
+ this.effect.active = this._cacheable = !isSSR;
984
+ this["__v_isReadonly"] = isReadonly;
985
+ }
986
+ get value() {
987
+ const self = toRaw(this);
988
+ trackRefValue(self);
989
+ if (!self._cacheable || self.effect.dirty) {
990
+ if (shared.hasChanged(self._value, self._value = self.effect.run())) {
991
+ triggerRefValue(self, 2);
992
+ }
993
+ }
994
+ return self._value;
995
+ }
996
+ set value(newValue) {
997
+ this._setter(newValue);
998
+ }
999
+ // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x
1000
+ get _dirty() {
1001
+ return this.effect.dirty;
1002
+ }
1003
+ set _dirty(v) {
1004
+ this.effect.dirty = v;
1005
+ }
1006
+ // #endregion
1007
+ }
1008
+ function computed(getterOrOptions, debugOptions, isSSR = false) {
1009
+ let getter;
1010
+ let setter;
1011
+ const onlyGetter = shared.isFunction(getterOrOptions);
1012
+ if (onlyGetter) {
1013
+ getter = getterOrOptions;
1014
+ setter = () => {
1015
+ console.warn("Write operation failed: computed value is readonly");
1016
+ } ;
1017
+ } else {
1018
+ getter = getterOrOptions.get;
1019
+ setter = getterOrOptions.set;
1020
+ }
1021
+ const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
1022
+ if (debugOptions && !isSSR) {
1023
+ cRef.effect.onTrack = debugOptions.onTrack;
1024
+ cRef.effect.onTrigger = debugOptions.onTrigger;
1025
+ }
1026
+ return cRef;
1027
+ }
1028
+
947
1029
  function trackRefValue(ref2) {
948
1030
  if (shouldTrack && activeEffect) {
949
1031
  ref2 = toRaw(ref2);
950
- {
951
- trackEffects(ref2.dep || (ref2.dep = createDep()), {
1032
+ trackEffect(
1033
+ activeEffect,
1034
+ ref2.dep || (ref2.dep = createDep(
1035
+ () => ref2.dep = void 0,
1036
+ ref2 instanceof ComputedRefImpl ? ref2 : void 0
1037
+ )),
1038
+ {
952
1039
  target: ref2,
953
1040
  type: "get",
954
1041
  key: "value"
955
- });
956
- }
1042
+ }
1043
+ );
957
1044
  }
958
1045
  }
959
- function triggerRefValue(ref2, newVal) {
1046
+ function triggerRefValue(ref2, dirtyLevel = 3, newVal) {
960
1047
  ref2 = toRaw(ref2);
961
1048
  const dep = ref2.dep;
962
1049
  if (dep) {
963
- {
964
- triggerEffects(dep, {
1050
+ triggerEffects(
1051
+ dep,
1052
+ dirtyLevel,
1053
+ {
965
1054
  target: ref2,
966
1055
  type: "set",
967
1056
  key: "value",
968
1057
  newValue: newVal
969
- });
970
- }
1058
+ }
1059
+ );
971
1060
  }
972
1061
  }
973
1062
  function isRef(r) {
@@ -1003,12 +1092,12 @@ class RefImpl {
1003
1092
  if (shared.hasChanged(newVal, this._rawValue)) {
1004
1093
  this._rawValue = newVal;
1005
1094
  this._value = useDirectValue ? newVal : toReactive(newVal);
1006
- triggerRefValue(this, newVal);
1095
+ triggerRefValue(this, 3, newVal);
1007
1096
  }
1008
1097
  }
1009
1098
  }
1010
1099
  function triggerRef(ref2) {
1011
- triggerRefValue(ref2, ref2.value );
1100
+ triggerRefValue(ref2, 3, ref2.value );
1012
1101
  }
1013
1102
  function unref(ref2) {
1014
1103
  return isRef(ref2) ? ref2.value : ref2;
@@ -1106,127 +1195,7 @@ function propertyToRef(source, key, defaultValue) {
1106
1195
  return isRef(val) ? val : new ObjectRefImpl(source, key, defaultValue);
1107
1196
  }
1108
1197
 
1109
- class ComputedRefImpl {
1110
- constructor(getter, _setter, isReadonly, isSSR) {
1111
- this._setter = _setter;
1112
- this.dep = void 0;
1113
- this.__v_isRef = true;
1114
- this["__v_isReadonly"] = false;
1115
- this._dirty = true;
1116
- this.effect = new ReactiveEffect(getter, () => {
1117
- if (!this._dirty) {
1118
- this._dirty = true;
1119
- triggerRefValue(this);
1120
- }
1121
- });
1122
- this.effect.computed = this;
1123
- this.effect.active = this._cacheable = !isSSR;
1124
- this["__v_isReadonly"] = isReadonly;
1125
- }
1126
- get value() {
1127
- const self = toRaw(this);
1128
- trackRefValue(self);
1129
- if (self._dirty || !self._cacheable) {
1130
- self._dirty = false;
1131
- self._value = self.effect.run();
1132
- }
1133
- return self._value;
1134
- }
1135
- set value(newValue) {
1136
- this._setter(newValue);
1137
- }
1138
- }
1139
- function computed(getterOrOptions, debugOptions, isSSR = false) {
1140
- let getter;
1141
- let setter;
1142
- const onlyGetter = shared.isFunction(getterOrOptions);
1143
- if (onlyGetter) {
1144
- getter = getterOrOptions;
1145
- setter = () => {
1146
- console.warn("Write operation failed: computed value is readonly");
1147
- } ;
1148
- } else {
1149
- getter = getterOrOptions.get;
1150
- setter = getterOrOptions.set;
1151
- }
1152
- const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
1153
- if (debugOptions && !isSSR) {
1154
- cRef.effect.onTrack = debugOptions.onTrack;
1155
- cRef.effect.onTrigger = debugOptions.onTrigger;
1156
- }
1157
- return cRef;
1158
- }
1159
-
1160
- const tick = /* @__PURE__ */ Promise.resolve();
1161
- const queue = [];
1162
- let queued = false;
1163
- const scheduler = (fn) => {
1164
- queue.push(fn);
1165
- if (!queued) {
1166
- queued = true;
1167
- tick.then(flush);
1168
- }
1169
- };
1170
- const flush = () => {
1171
- for (let i = 0; i < queue.length; i++) {
1172
- queue[i]();
1173
- }
1174
- queue.length = 0;
1175
- queued = false;
1176
- };
1177
- class DeferredComputedRefImpl {
1178
- constructor(getter) {
1179
- this.dep = void 0;
1180
- this._dirty = true;
1181
- this.__v_isRef = true;
1182
- this["__v_isReadonly"] = true;
1183
- let compareTarget;
1184
- let hasCompareTarget = false;
1185
- let scheduled = false;
1186
- this.effect = new ReactiveEffect(getter, (computedTrigger) => {
1187
- if (this.dep) {
1188
- if (computedTrigger) {
1189
- compareTarget = this._value;
1190
- hasCompareTarget = true;
1191
- } else if (!scheduled) {
1192
- const valueToCompare = hasCompareTarget ? compareTarget : this._value;
1193
- scheduled = true;
1194
- hasCompareTarget = false;
1195
- scheduler(() => {
1196
- if (this.effect.active && this._get() !== valueToCompare) {
1197
- triggerRefValue(this);
1198
- }
1199
- scheduled = false;
1200
- });
1201
- }
1202
- for (const e of this.dep) {
1203
- if (e.computed instanceof DeferredComputedRefImpl) {
1204
- e.scheduler(
1205
- true
1206
- /* computedTrigger */
1207
- );
1208
- }
1209
- }
1210
- }
1211
- this._dirty = true;
1212
- });
1213
- this.effect.computed = this;
1214
- }
1215
- _get() {
1216
- if (this._dirty) {
1217
- this._dirty = false;
1218
- return this._value = this.effect.run();
1219
- }
1220
- return this._value;
1221
- }
1222
- get value() {
1223
- trackRefValue(this);
1224
- return toRaw(this)._get();
1225
- }
1226
- }
1227
- function deferredComputed(getter) {
1228
- return new DeferredComputedRefImpl(getter);
1229
- }
1198
+ const deferredComputed = computed;
1230
1199
 
1231
1200
  exports.EffectScope = EffectScope;
1232
1201
  exports.ITERATE_KEY = ITERATE_KEY;
@@ -1245,11 +1214,13 @@ exports.isRef = isRef;
1245
1214
  exports.isShallow = isShallow;
1246
1215
  exports.markRaw = markRaw;
1247
1216
  exports.onScopeDispose = onScopeDispose;
1217
+ exports.pauseScheduling = pauseScheduling;
1248
1218
  exports.pauseTracking = pauseTracking;
1249
1219
  exports.proxyRefs = proxyRefs;
1250
1220
  exports.reactive = reactive;
1251
1221
  exports.readonly = readonly;
1252
1222
  exports.ref = ref;
1223
+ exports.resetScheduling = resetScheduling;
1253
1224
  exports.resetTracking = resetTracking;
1254
1225
  exports.shallowReactive = shallowReactive;
1255
1226
  exports.shallowReadonly = shallowReadonly;