vue 2.6.6 → 2.6.10

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.
Files changed (37) hide show
  1. package/README.md +24 -19
  2. package/dist/README.md +1 -1
  3. package/dist/vue.common.dev.js +169 -80
  4. package/dist/vue.common.prod.js +2 -2
  5. package/dist/vue.esm.browser.js +167 -76
  6. package/dist/vue.esm.browser.min.js +2 -2
  7. package/dist/vue.esm.js +169 -80
  8. package/dist/vue.js +169 -80
  9. package/dist/vue.min.js +2 -2
  10. package/dist/vue.runtime.common.dev.js +121 -62
  11. package/dist/vue.runtime.common.prod.js +2 -2
  12. package/dist/vue.runtime.esm.js +121 -62
  13. package/dist/vue.runtime.js +121 -62
  14. package/dist/vue.runtime.min.js +2 -2
  15. package/package.json +2 -2
  16. package/src/compiler/codeframe.js +7 -5
  17. package/src/compiler/codegen/events.js +1 -1
  18. package/src/compiler/codegen/index.js +38 -9
  19. package/src/compiler/parser/html-parser.js +3 -3
  20. package/src/compiler/parser/index.js +4 -3
  21. package/src/core/instance/lifecycle.js +5 -2
  22. package/src/core/instance/render-helpers/bind-object-props.js +5 -3
  23. package/src/core/instance/render-helpers/resolve-scoped-slots.js +7 -2
  24. package/src/core/observer/scheduler.js +17 -6
  25. package/src/core/util/error.js +24 -13
  26. package/src/core/util/lang.js +2 -2
  27. package/src/core/util/options.js +2 -2
  28. package/src/core/vdom/helpers/normalize-scoped-slots.js +14 -5
  29. package/src/core/vdom/helpers/resolve-async-component.js +25 -8
  30. package/src/platforms/web/runtime/modules/dom-props.js +15 -12
  31. package/src/platforms/web/runtime/modules/events.js +4 -2
  32. package/src/platforms/web/runtime/modules/transition.js +1 -1
  33. package/src/server/template-renderer/create-async-file-mapper.js +2 -2
  34. package/src/server/write.js +1 -1
  35. package/types/options.d.ts +3 -3
  36. package/types/vnode.d.ts +6 -2
  37. package/types/vue.d.ts +3 -3
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vue.js v2.6.6
2
+ * Vue.js v2.6.10
3
3
  * (c) 2014-2019 Evan You
4
4
  * Released under the MIT License.
5
5
  */
@@ -475,7 +475,7 @@ var config = ({
475
475
  * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname
476
476
  * skipping \u10000-\uEFFFF due to it freezing up PhantomJS
477
477
  */
478
- const unicodeLetters = 'a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD';
478
+ const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/;
479
479
 
480
480
  /**
481
481
  * Check if a string starts with $ or _
@@ -500,7 +500,7 @@ function def (obj, key, val, enumerable) {
500
500
  /**
501
501
  * Parse simple path.
502
502
  */
503
- const bailRE = new RegExp(`[^${unicodeLetters}.$_\\d]`);
503
+ const bailRE = new RegExp(`[^${unicodeRegExp.source}.$_\\d]`);
504
504
  function parsePath (path) {
505
505
  if (bailRE.test(path)) {
506
506
  return
@@ -1440,7 +1440,7 @@ function checkComponents (options) {
1440
1440
  }
1441
1441
 
1442
1442
  function validateComponentName (name) {
1443
- if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_${unicodeLetters}]*$`).test(name)) {
1443
+ if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_${unicodeRegExp.source}]*$`).test(name)) {
1444
1444
  warn(
1445
1445
  'Invalid component name: "' + name + '". Component names ' +
1446
1446
  'should conform to valid custom element name in html5 specification.'
@@ -1852,23 +1852,30 @@ function isBoolean (...args) {
1852
1852
  /* */
1853
1853
 
1854
1854
  function handleError (err, vm, info) {
1855
- if (vm) {
1856
- let cur = vm;
1857
- while ((cur = cur.$parent)) {
1858
- const hooks = cur.$options.errorCaptured;
1859
- if (hooks) {
1860
- for (let i = 0; i < hooks.length; i++) {
1861
- try {
1862
- const capture = hooks[i].call(cur, err, vm, info) === false;
1863
- if (capture) return
1864
- } catch (e) {
1865
- globalHandleError(e, cur, 'errorCaptured hook');
1855
+ // Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
1856
+ // See: https://github.com/vuejs/vuex/issues/1505
1857
+ pushTarget();
1858
+ try {
1859
+ if (vm) {
1860
+ let cur = vm;
1861
+ while ((cur = cur.$parent)) {
1862
+ const hooks = cur.$options.errorCaptured;
1863
+ if (hooks) {
1864
+ for (let i = 0; i < hooks.length; i++) {
1865
+ try {
1866
+ const capture = hooks[i].call(cur, err, vm, info) === false;
1867
+ if (capture) return
1868
+ } catch (e) {
1869
+ globalHandleError(e, cur, 'errorCaptured hook');
1870
+ }
1866
1871
  }
1867
1872
  }
1868
1873
  }
1869
1874
  }
1875
+ globalHandleError(err, vm, info);
1876
+ } finally {
1877
+ popTarget();
1870
1878
  }
1871
- globalHandleError(err, vm, info);
1872
1879
  }
1873
1880
 
1874
1881
  function invokeWithErrorHandling (
@@ -1881,8 +1888,11 @@ function invokeWithErrorHandling (
1881
1888
  let res;
1882
1889
  try {
1883
1890
  res = args ? handler.apply(context, args) : handler.call(context);
1884
- if (res && !res._isVue && isPromise(res)) {
1891
+ if (res && !res._isVue && isPromise(res) && !res._handled) {
1885
1892
  res.catch(e => handleError(e, vm, info + ` (Promise/async)`));
1893
+ // issue #9511
1894
+ // avoid catch triggering multiple times when nested calls
1895
+ res._handled = true;
1886
1896
  }
1887
1897
  } catch (e) {
1888
1898
  handleError(e, vm, info);
@@ -2562,16 +2572,21 @@ function normalizeScopedSlots (
2562
2572
  prevSlots
2563
2573
  ) {
2564
2574
  let res;
2575
+ const hasNormalSlots = Object.keys(normalSlots).length > 0;
2576
+ const isStable = slots ? !!slots.$stable : !hasNormalSlots;
2577
+ const key = slots && slots.$key;
2565
2578
  if (!slots) {
2566
2579
  res = {};
2567
2580
  } else if (slots._normalized) {
2568
2581
  // fast path 1: child component re-render only, parent did not change
2569
2582
  return slots._normalized
2570
2583
  } else if (
2571
- slots.$stable &&
2584
+ isStable &&
2572
2585
  prevSlots &&
2573
2586
  prevSlots !== emptyObject &&
2574
- Object.keys(normalSlots).length === 0
2587
+ key === prevSlots.$key &&
2588
+ !hasNormalSlots &&
2589
+ !prevSlots.$hasNormal
2575
2590
  ) {
2576
2591
  // fast path 2: stable scoped slots w/ no normal slots to proxy,
2577
2592
  // only need to normalize once
@@ -2595,7 +2610,9 @@ function normalizeScopedSlots (
2595
2610
  if (slots && Object.isExtensible(slots)) {
2596
2611
  (slots)._normalized = res;
2597
2612
  }
2598
- def(res, '$stable', slots ? !!slots.$stable : true);
2613
+ def(res, '$stable', isStable);
2614
+ def(res, '$key', key);
2615
+ def(res, '$hasNormal', hasNormalSlots);
2599
2616
  return res
2600
2617
  }
2601
2618
 
@@ -2605,8 +2622,10 @@ function normalizeScopedSlot(normalSlots, key, fn) {
2605
2622
  res = res && typeof res === 'object' && !Array.isArray(res)
2606
2623
  ? [res] // single vnode
2607
2624
  : normalizeChildren(res);
2608
- return res && res.length === 0
2609
- ? undefined
2625
+ return res && (
2626
+ res.length === 0 ||
2627
+ (res.length === 1 && res[0].isComment) // #9658
2628
+ ) ? undefined
2610
2629
  : res
2611
2630
  };
2612
2631
  // this is a slot using the new v-slot syntax without scope. although it is
@@ -2786,12 +2805,13 @@ function bindObjectProps (
2786
2805
  : data.attrs || (data.attrs = {});
2787
2806
  }
2788
2807
  const camelizedKey = camelize(key);
2789
- if (!(key in hash) && !(camelizedKey in hash)) {
2808
+ const hyphenatedKey = hyphenate(key);
2809
+ if (!(camelizedKey in hash) && !(hyphenatedKey in hash)) {
2790
2810
  hash[key] = value[key];
2791
2811
 
2792
2812
  if (isSync) {
2793
2813
  const on = data.on || (data.on = {});
2794
- on[`update:${camelizedKey}`] = function ($event) {
2814
+ on[`update:${key}`] = function ($event) {
2795
2815
  value[key] = $event;
2796
2816
  };
2797
2817
  }
@@ -2888,14 +2908,16 @@ function bindObjectListeners (data, value) {
2888
2908
 
2889
2909
  function resolveScopedSlots (
2890
2910
  fns, // see flow/vnode
2911
+ res,
2912
+ // the following are added in 2.6
2891
2913
  hasDynamicKeys,
2892
- res
2914
+ contentHashKey
2893
2915
  ) {
2894
2916
  res = res || { $stable: !hasDynamicKeys };
2895
2917
  for (let i = 0; i < fns.length; i++) {
2896
2918
  const slot = fns[i];
2897
2919
  if (Array.isArray(slot)) {
2898
- resolveScopedSlots(slot, hasDynamicKeys, res);
2920
+ resolveScopedSlots(slot, res, hasDynamicKeys);
2899
2921
  } else if (slot) {
2900
2922
  // marker for reverse proxying v-slot without scope on this.$slots
2901
2923
  if (slot.proxy) {
@@ -2904,6 +2926,9 @@ function resolveScopedSlots (
2904
2926
  res[slot.key] = slot.fn;
2905
2927
  }
2906
2928
  }
2929
+ if (contentHashKey) {
2930
+ (res).$key = contentHashKey;
2931
+ }
2907
2932
  return res
2908
2933
  }
2909
2934
 
@@ -3613,17 +3638,23 @@ function resolveAsyncComponent (
3613
3638
  return factory.resolved
3614
3639
  }
3615
3640
 
3641
+ const owner = currentRenderingInstance;
3642
+ if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
3643
+ // already pending
3644
+ factory.owners.push(owner);
3645
+ }
3646
+
3616
3647
  if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
3617
3648
  return factory.loadingComp
3618
3649
  }
3619
3650
 
3620
- const owner = currentRenderingInstance;
3621
- if (isDef(factory.owners)) {
3622
- // already pending
3623
- factory.owners.push(owner);
3624
- } else {
3651
+ if (owner && !isDef(factory.owners)) {
3625
3652
  const owners = factory.owners = [owner];
3626
3653
  let sync = true;
3654
+ let timerLoading = null;
3655
+ let timerTimeout = null
3656
+
3657
+ ;(owner).$on('hook:destroyed', () => remove(owners, owner));
3627
3658
 
3628
3659
  const forceRender = (renderCompleted) => {
3629
3660
  for (let i = 0, l = owners.length; i < l; i++) {
@@ -3632,6 +3663,14 @@ function resolveAsyncComponent (
3632
3663
 
3633
3664
  if (renderCompleted) {
3634
3665
  owners.length = 0;
3666
+ if (timerLoading !== null) {
3667
+ clearTimeout(timerLoading);
3668
+ timerLoading = null;
3669
+ }
3670
+ if (timerTimeout !== null) {
3671
+ clearTimeout(timerTimeout);
3672
+ timerTimeout = null;
3673
+ }
3635
3674
  }
3636
3675
  };
3637
3676
 
@@ -3678,7 +3717,8 @@ function resolveAsyncComponent (
3678
3717
  if (res.delay === 0) {
3679
3718
  factory.loading = true;
3680
3719
  } else {
3681
- setTimeout(() => {
3720
+ timerLoading = setTimeout(() => {
3721
+ timerLoading = null;
3682
3722
  if (isUndef(factory.resolved) && isUndef(factory.error)) {
3683
3723
  factory.loading = true;
3684
3724
  forceRender(false);
@@ -3688,7 +3728,8 @@ function resolveAsyncComponent (
3688
3728
  }
3689
3729
 
3690
3730
  if (isDef(res.timeout)) {
3691
- setTimeout(() => {
3731
+ timerTimeout = setTimeout(() => {
3732
+ timerTimeout = null;
3692
3733
  if (isUndef(factory.resolved)) {
3693
3734
  reject(
3694
3735
  `timeout (${res.timeout}ms)`
@@ -4076,9 +4117,12 @@ function updateChildComponent (
4076
4117
  // check if there are dynamic scopedSlots (hand-written or compiled but with
4077
4118
  // dynamic slot names). Static scoped slots compiled from template has the
4078
4119
  // "$stable" marker.
4120
+ const newScopedSlots = parentVnode.data.scopedSlots;
4121
+ const oldScopedSlots = vm.$scopedSlots;
4079
4122
  const hasDynamicScopedSlot = !!(
4080
- (parentVnode.data.scopedSlots && !parentVnode.data.scopedSlots.$stable) ||
4081
- (vm.$scopedSlots !== emptyObject && !vm.$scopedSlots.$stable)
4123
+ (newScopedSlots && !newScopedSlots.$stable) ||
4124
+ (oldScopedSlots !== emptyObject && !oldScopedSlots.$stable) ||
4125
+ (newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key)
4082
4126
  );
4083
4127
 
4084
4128
  // Any static slot children from the parent may have changed during parent's
@@ -4231,11 +4275,21 @@ let getNow = Date.now;
4231
4275
  // timestamp can either be hi-res (relative to page load) or low-res
4232
4276
  // (relative to UNIX epoch), so in order to compare time we have to use the
4233
4277
  // same timestamp type when saving the flush timestamp.
4234
- if (inBrowser && getNow() > document.createEvent('Event').timeStamp) {
4235
- // if the low-res timestamp which is bigger than the event timestamp
4236
- // (which is evaluated AFTER) it means the event is using a hi-res timestamp,
4237
- // and we need to use the hi-res version for event listeners as well.
4238
- getNow = () => performance.now();
4278
+ // All IE versions use low-res event timestamps, and have problematic clock
4279
+ // implementations (#9632)
4280
+ if (inBrowser && !isIE) {
4281
+ const performance = window.performance;
4282
+ if (
4283
+ performance &&
4284
+ typeof performance.now === 'function' &&
4285
+ getNow() > document.createEvent('Event').timeStamp
4286
+ ) {
4287
+ // if the event timestamp, although evaluated AFTER the Date.now(), is
4288
+ // smaller than it, it means the event is using a hi-res timestamp,
4289
+ // and we need to use the hi-res version for event listener timestamps as
4290
+ // well.
4291
+ getNow = () => performance.now();
4292
+ }
4239
4293
  }
4240
4294
 
4241
4295
  /**
@@ -5410,7 +5464,7 @@ Object.defineProperty(Vue, 'FunctionalRenderContext', {
5410
5464
  value: FunctionalRenderContext
5411
5465
  });
5412
5466
 
5413
- Vue.version = '2.6.6';
5467
+ Vue.version = '2.6.10';
5414
5468
 
5415
5469
  /* */
5416
5470
 
@@ -7494,8 +7548,10 @@ function add$1 (
7494
7548
  e.target === e.currentTarget ||
7495
7549
  // event is fired after handler attachment
7496
7550
  e.timeStamp >= attachedTimestamp ||
7497
- // #9462 bail for iOS 9 bug: event.timeStamp is 0 after history.pushState
7498
- e.timeStamp === 0 ||
7551
+ // bail for environments that have buggy event.timeStamp implementations
7552
+ // #9462 iOS 9 bug: event.timeStamp is 0 after history.pushState
7553
+ // #9681 QtWebEngine event.timeStamp is negative value
7554
+ e.timeStamp <= 0 ||
7499
7555
  // #9448 bail if event is fired in another document in a multi-page
7500
7556
  // electron/nw.js app, since event.timeStamp will be using a different
7501
7557
  // starting reference
@@ -7562,10 +7618,11 @@ function updateDOMProps (oldVnode, vnode) {
7562
7618
  }
7563
7619
 
7564
7620
  for (key in oldProps) {
7565
- if (isUndef(props[key])) {
7621
+ if (!(key in props)) {
7566
7622
  elm[key] = '';
7567
7623
  }
7568
7624
  }
7625
+
7569
7626
  for (key in props) {
7570
7627
  cur = props[key];
7571
7628
  // ignore children if the node has textContent or innerHTML,
@@ -7581,15 +7638,7 @@ function updateDOMProps (oldVnode, vnode) {
7581
7638
  }
7582
7639
  }
7583
7640
 
7584
- // skip the update if old and new VDOM state is the same.
7585
- // the only exception is `value` where the DOM value may be temporarily
7586
- // out of sync with VDOM state due to focus, composition and modifiers.
7587
- // This also covers #4521 by skipping the unnecesarry `checked` update.
7588
- if (key !== 'value' && cur === oldProps[key]) {
7589
- continue
7590
- }
7591
-
7592
- if (key === 'value') {
7641
+ if (key === 'value' && elm.tagName !== 'PROGRESS') {
7593
7642
  // store value as _value as well since
7594
7643
  // non-string values will be stringified
7595
7644
  elm._value = cur;
@@ -7609,8 +7658,18 @@ function updateDOMProps (oldVnode, vnode) {
7609
7658
  while (svg.firstChild) {
7610
7659
  elm.appendChild(svg.firstChild);
7611
7660
  }
7612
- } else {
7613
- elm[key] = cur;
7661
+ } else if (
7662
+ // skip the update if old and new VDOM state is the same.
7663
+ // `value` is handled separately because the DOM value may be temporarily
7664
+ // out of sync with VDOM state due to focus, composition and modifiers.
7665
+ // This #4521 by skipping the unnecesarry `checked` update.
7666
+ cur !== oldProps[key]
7667
+ ) {
7668
+ // some property updates can throw
7669
+ // e.g. `value` on <progress> w/ non-finite value
7670
+ try {
7671
+ elm[key] = cur;
7672
+ } catch (e) {}
7614
7673
  }
7615
7674
  }
7616
7675
  }
@@ -8110,8 +8169,8 @@ function enter (vnode, toggleDisplay) {
8110
8169
  let context = activeInstance;
8111
8170
  let transitionNode = activeInstance.$vnode;
8112
8171
  while (transitionNode && transitionNode.parent) {
8113
- transitionNode = transitionNode.parent;
8114
8172
  context = transitionNode.context;
8173
+ transitionNode = transitionNode.parent;
8115
8174
  }
8116
8175
 
8117
8176
  const isAppear = !context._isMounted || !vnode.isRootInsert;
@@ -9196,7 +9255,7 @@ const isNonPhrasingTag = makeMap(
9196
9255
  // Regular Expressions for parsing tags and attributes
9197
9256
  const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
9198
9257
  const dynamicArgAttribute = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
9199
- const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeLetters}]*`;
9258
+ const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeRegExp.source}]*`;
9200
9259
  const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
9201
9260
  const startTagOpen = new RegExp(`^<${qnameCapture}`);
9202
9261
  const startTagClose = /^\s*(\/?)>/;
@@ -9458,7 +9517,7 @@ function parseHTML (html, options) {
9458
9517
  ) {
9459
9518
  options.warn(
9460
9519
  `tag <${stack[i].tag}> has no matching end tag.`,
9461
- { start: stack[i].start }
9520
+ { start: stack[i].start, end: stack[i].end }
9462
9521
  );
9463
9522
  }
9464
9523
  if (options.end) {
@@ -9495,7 +9554,7 @@ const dynamicArgRE = /^\[.*\]$/;
9495
9554
 
9496
9555
  const argRE = /:(.*)$/;
9497
9556
  const bindRE = /^:|^\.|^v-bind:/;
9498
- const modifierRE = /\.[^.]+/g;
9557
+ const modifierRE = /\.[^.\]]+(?=[^\]]*$)/g;
9499
9558
 
9500
9559
  const slotRE = /^v-slot(:|$)|^#/;
9501
9560
 
@@ -9672,7 +9731,7 @@ function parse (
9672
9731
  shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,
9673
9732
  shouldKeepComment: options.comments,
9674
9733
  outputSourceRange: options.outputSourceRange,
9675
- start (tag, attrs, unary, start) {
9734
+ start (tag, attrs, unary, start, end) {
9676
9735
  // check namespace.
9677
9736
  // inherit parent ns if there is one
9678
9737
  const ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag);
@@ -9691,6 +9750,7 @@ function parse (
9691
9750
  {
9692
9751
  if (options.outputSourceRange) {
9693
9752
  element.start = start;
9753
+ element.end = end;
9694
9754
  element.rawAttrsMap = element.attrsList.reduce((cumulated, attr) => {
9695
9755
  cumulated[attr.name] = attr;
9696
9756
  return cumulated
@@ -9812,7 +9872,7 @@ function parse (
9812
9872
  text = preserveWhitespace ? ' ' : '';
9813
9873
  }
9814
9874
  if (text) {
9815
- if (whitespaceOption === 'condense') {
9875
+ if (!inPre && whitespaceOption === 'condense') {
9816
9876
  // condense consecutive whitespaces into single space
9817
9877
  text = text.replace(whitespaceRE$1, ' ');
9818
9878
  }
@@ -10669,7 +10729,7 @@ function isDirectChildOfTemplateFor (node) {
10669
10729
 
10670
10730
  /* */
10671
10731
 
10672
- const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/;
10732
+ const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function\s*(?:[\w$]+)?\s*\(/;
10673
10733
  const fnInvokeRE = /\([^)]*?\);*$/;
10674
10734
  const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/;
10675
10735
 
@@ -11217,7 +11277,7 @@ function genScopedSlots (
11217
11277
  // components with only scoped slots to skip forced updates from parent.
11218
11278
  // but in some cases we have to bail-out of this optimization
11219
11279
  // for example if the slot contains dynamic names, has v-if or v-for on them...
11220
- let needsForceUpdate = Object.keys(slots).some(key => {
11280
+ let needsForceUpdate = el.for || Object.keys(slots).some(key => {
11221
11281
  const slot = slots[key];
11222
11282
  return (
11223
11283
  slot.slotTargetDynamic ||
@@ -11226,24 +11286,53 @@ function genScopedSlots (
11226
11286
  containsSlotChild(slot) // is passing down slot from parent which may be dynamic
11227
11287
  )
11228
11288
  });
11229
- // OR when it is inside another scoped slot (the reactivity is disconnected)
11230
- // #9438
11289
+
11290
+ // #9534: if a component with scoped slots is inside a conditional branch,
11291
+ // it's possible for the same component to be reused but with different
11292
+ // compiled slot content. To avoid that, we generate a unique key based on
11293
+ // the generated code of all the slot contents.
11294
+ let needsKey = !!el.if;
11295
+
11296
+ // OR when it is inside another scoped slot or v-for (the reactivity may be
11297
+ // disconnected due to the intermediate scope variable)
11298
+ // #9438, #9506
11299
+ // TODO: this can be further optimized by properly analyzing in-scope bindings
11300
+ // and skip force updating ones that do not actually use scope variables.
11231
11301
  if (!needsForceUpdate) {
11232
11302
  let parent = el.parent;
11233
11303
  while (parent) {
11234
- if (parent.slotScope && parent.slotScope !== emptySlotScopeToken) {
11304
+ if (
11305
+ (parent.slotScope && parent.slotScope !== emptySlotScopeToken) ||
11306
+ parent.for
11307
+ ) {
11235
11308
  needsForceUpdate = true;
11236
11309
  break
11237
11310
  }
11311
+ if (parent.if) {
11312
+ needsKey = true;
11313
+ }
11238
11314
  parent = parent.parent;
11239
11315
  }
11240
11316
  }
11241
11317
 
11242
- return `scopedSlots:_u([${
11243
- Object.keys(slots).map(key => {
11244
- return genScopedSlot(slots[key], state)
11245
- }).join(',')
11246
- }]${needsForceUpdate ? `,true` : ``})`
11318
+ const generatedSlots = Object.keys(slots)
11319
+ .map(key => genScopedSlot(slots[key], state))
11320
+ .join(',');
11321
+
11322
+ return `scopedSlots:_u([${generatedSlots}]${
11323
+ needsForceUpdate ? `,null,true` : ``
11324
+ }${
11325
+ !needsForceUpdate && needsKey ? `,null,false,${hash(generatedSlots)}` : ``
11326
+ })`
11327
+ }
11328
+
11329
+ function hash(str) {
11330
+ let hash = 5381;
11331
+ let i = str.length;
11332
+ while(i) {
11333
+ hash = (hash * 33) ^ str.charCodeAt(--i);
11334
+ }
11335
+ return hash >>> 0
11247
11336
  }
11248
11337
 
11249
11338
  function containsSlotChild (el) {
@@ -11581,11 +11670,13 @@ function generateCodeFrame (
11581
11670
 
11582
11671
  function repeat (str, n) {
11583
11672
  let result = '';
11584
- while (true) { // eslint-disable-line
11585
- if (n & 1) result += str;
11586
- n >>>= 1;
11587
- if (n <= 0) break
11588
- str += str;
11673
+ if (n > 0) {
11674
+ while (true) { // eslint-disable-line
11675
+ if (n & 1) result += str;
11676
+ n >>>= 1;
11677
+ if (n <= 0) break
11678
+ str += str;
11679
+ }
11589
11680
  }
11590
11681
  return result
11591
11682
  }