@lwc/engine-core 2.31.6 → 2.31.8

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.
@@ -2497,6 +2497,93 @@ const BaseBridgeElement = HTMLBridgeElementFactory(HTMLElementConstructor, share
2497
2497
  shared.freeze(BaseBridgeElement);
2498
2498
  shared.seal(BaseBridgeElement.prototype);
2499
2499
 
2500
+ /*
2501
+ * Copyright (c) 2023, salesforce.com, inc.
2502
+ * All rights reserved.
2503
+ * SPDX-License-Identifier: MIT
2504
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
2505
+ */
2506
+ const supportsWeakRefs = typeof WeakRef === 'function' && typeof FinalizationRegistry === 'function';
2507
+ // In browsers that doesn't support WeakRefs, the values will still leak, but at least the keys won't
2508
+ class LegacyWeakMultiMap {
2509
+ constructor() {
2510
+ this._map = new WeakMap();
2511
+ }
2512
+ _getValues(key) {
2513
+ let values = this._map.get(key);
2514
+ if (shared.isUndefined(values)) {
2515
+ values = new Set();
2516
+ this._map.set(key, values);
2517
+ }
2518
+ return values;
2519
+ }
2520
+ get(key) {
2521
+ return this._getValues(key);
2522
+ }
2523
+ add(key, vm) {
2524
+ const set = this._getValues(key);
2525
+ set.add(vm);
2526
+ }
2527
+ delete(key) {
2528
+ this._map.delete(key);
2529
+ }
2530
+ }
2531
+ // This implementation relies on the WeakRef/FinalizationRegistry proposal.
2532
+ // For some background, see: https://github.com/tc39/proposal-weakrefs
2533
+ class ModernWeakMultiMap {
2534
+ constructor() {
2535
+ this._map = new WeakMap();
2536
+ this._registry = new FinalizationRegistry((weakRefs) => {
2537
+ // This should be considered an optional cleanup method to remove GC'ed values from their respective arrays.
2538
+ // JS VMs are not obligated to call FinalizationRegistry callbacks.
2539
+ // Work backwards, removing stale VMs
2540
+ for (let i = weakRefs.length - 1; i >= 0; i--) {
2541
+ const vm = weakRefs[i].deref();
2542
+ if (shared.isUndefined(vm)) {
2543
+ shared.ArraySplice.call(weakRefs, i, 1); // remove
2544
+ }
2545
+ }
2546
+ });
2547
+ }
2548
+ _getWeakRefs(key) {
2549
+ let weakRefs = this._map.get(key);
2550
+ if (shared.isUndefined(weakRefs)) {
2551
+ weakRefs = [];
2552
+ this._map.set(key, weakRefs);
2553
+ }
2554
+ return weakRefs;
2555
+ }
2556
+ get(key) {
2557
+ const weakRefs = this._getWeakRefs(key);
2558
+ const result = new Set();
2559
+ for (const weakRef of weakRefs) {
2560
+ const vm = weakRef.deref();
2561
+ if (!shared.isUndefined(vm)) {
2562
+ result.add(vm);
2563
+ }
2564
+ }
2565
+ return result;
2566
+ }
2567
+ add(key, value) {
2568
+ const weakRefs = this._getWeakRefs(key);
2569
+ // We could check for duplicate values here, but it doesn't seem worth it.
2570
+ // We transform the output into a Set anyway
2571
+ shared.ArrayPush.call(weakRefs, new WeakRef(value));
2572
+ // It's important here not to leak the second argument, which is the "held value." The FinalizationRegistry
2573
+ // effectively creates a strong reference between the first argument (the "target") and the held value. When
2574
+ // the target is GC'ed, the callback is called, and then the held value is GC'ed.
2575
+ // Putting the key here would mean the key is not GC'ed until the value is GC'ed, which defeats the purpose
2576
+ // of the WeakMap. Whereas putting the weakRefs array here is fine, because it doesn't have a strong reference
2577
+ // to anything. See also this example:
2578
+ // https://gist.github.com/nolanlawson/79a3d36e8e6cc25c5048bb17c1795aea
2579
+ this._registry.register(value, weakRefs);
2580
+ }
2581
+ delete(key) {
2582
+ this._map.delete(key);
2583
+ }
2584
+ }
2585
+ const WeakMultiMap = supportsWeakRefs ? ModernWeakMultiMap : LegacyWeakMultiMap;
2586
+
2500
2587
  /*
2501
2588
  * Copyright (c) 2020, salesforce.com, inc.
2502
2589
  * All rights reserved.
@@ -2506,67 +2593,62 @@ shared.seal(BaseBridgeElement.prototype);
2506
2593
  const swappedTemplateMap = new WeakMap();
2507
2594
  const swappedComponentMap = new WeakMap();
2508
2595
  const swappedStyleMap = new WeakMap();
2509
- const activeTemplates = new WeakMap();
2510
- const activeComponents = new WeakMap();
2511
- const activeStyles = new WeakMap();
2596
+ // The important thing here is the weak values – VMs are transient (one per component instance) and should be GC'ed,
2597
+ // so we don't want to create strong references to them.
2598
+ // The weak keys are kind of useless, because Templates, LightningElementConstructors, and StylesheetFactories are
2599
+ // never GC'ed. But maybe they will be someday, so we may as well use weak keys too.
2600
+ const activeTemplates = new WeakMultiMap();
2601
+ const activeComponents = new WeakMultiMap();
2602
+ const activeStyles = new WeakMultiMap();
2512
2603
  function rehydrateHotTemplate(tpl) {
2513
2604
  const list = activeTemplates.get(tpl);
2514
- if (!shared.isUndefined(list)) {
2515
- list.forEach((vm) => {
2516
- if (shared.isFalse(vm.isDirty)) {
2517
- // forcing the vm to rehydrate in the micro-task:
2518
- markComponentAsDirty(vm);
2519
- scheduleRehydration(vm);
2520
- }
2521
- });
2522
- // resetting the Set to release the memory of those vm references
2523
- // since they are not longer related to this template, instead
2524
- // they will get re-associated once these instances are rehydrated.
2525
- list.clear();
2605
+ for (const vm of list) {
2606
+ if (shared.isFalse(vm.isDirty)) {
2607
+ // forcing the vm to rehydrate in the micro-task:
2608
+ markComponentAsDirty(vm);
2609
+ scheduleRehydration(vm);
2610
+ }
2526
2611
  }
2612
+ // Resetting the Set since these VMs are no longer related to this template, instead
2613
+ // they will get re-associated once these instances are rehydrated.
2614
+ activeTemplates.delete(tpl);
2527
2615
  return true;
2528
2616
  }
2529
2617
  function rehydrateHotStyle(style) {
2530
2618
  const list = activeStyles.get(style);
2531
- if (!shared.isUndefined(list)) {
2532
- list.forEach((vm) => {
2533
- // if a style definition is swapped, we must reset
2534
- // vm's template content in the next micro-task:
2535
- forceRehydration(vm);
2536
- });
2537
- // resetting the Set to release the memory of those vm references
2538
- // since they are not longer related to this style, instead
2539
- // they will get re-associated once these instances are rehydrated.
2540
- list.clear();
2541
- }
2619
+ for (const vm of list) {
2620
+ // if a style definition is swapped, we must reset
2621
+ // vm's template content in the next micro-task:
2622
+ forceRehydration(vm);
2623
+ }
2624
+ // Resetting the Set since these VMs are no longer related to this style, instead
2625
+ // they will get re-associated once these instances are rehydrated.
2626
+ activeStyles.delete(style);
2542
2627
  return true;
2543
2628
  }
2544
2629
  function rehydrateHotComponent(Ctor) {
2545
2630
  const list = activeComponents.get(Ctor);
2546
2631
  let canRefreshAllInstances = true;
2547
- if (!shared.isUndefined(list)) {
2548
- list.forEach((vm) => {
2549
- const { owner } = vm;
2550
- if (!shared.isNull(owner)) {
2551
- // if a component class definition is swapped, we must reset
2552
- // owner's template content in the next micro-task:
2553
- forceRehydration(owner);
2554
- }
2555
- else {
2556
- // the hot swapping for components only work for instances of components
2557
- // created from a template, root elements can't be swapped because we
2558
- // don't have a way to force the creation of the element with the same state
2559
- // of the current element.
2560
- // Instead, we can report the problem to the caller so it can take action,
2561
- // for example: reload the entire page.
2562
- canRefreshAllInstances = false;
2563
- }
2564
- });
2565
- // resetting the Set to release the memory of those vm references
2566
- // since they are not longer related to this constructor, instead
2567
- // they will get re-associated once these instances are rehydrated.
2568
- list.clear();
2569
- }
2632
+ for (const vm of list) {
2633
+ const { owner } = vm;
2634
+ if (!shared.isNull(owner)) {
2635
+ // if a component class definition is swapped, we must reset
2636
+ // owner's template content in the next micro-task:
2637
+ forceRehydration(owner);
2638
+ }
2639
+ else {
2640
+ // the hot swapping for components only work for instances of components
2641
+ // created from a template, root elements can't be swapped because we
2642
+ // don't have a way to force the creation of the element with the same state
2643
+ // of the current element.
2644
+ // Instead, we can report the problem to the caller so it can take action,
2645
+ // for example: reload the entire page.
2646
+ canRefreshAllInstances = false;
2647
+ }
2648
+ }
2649
+ // resetting the Set since these VMs are no longer related to this constructor, instead
2650
+ // they will get re-associated once these instances are rehydrated.
2651
+ activeComponents.delete(Ctor);
2570
2652
  return canRefreshAllInstances;
2571
2653
  }
2572
2654
  function getTemplateOrSwappedTemplate(tpl) {
@@ -2612,75 +2694,27 @@ function setActiveVM(vm) {
2612
2694
  }
2613
2695
  // tracking active component
2614
2696
  const Ctor = vm.def.ctor;
2615
- let componentVMs = activeComponents.get(Ctor);
2616
- if (shared.isUndefined(componentVMs)) {
2617
- componentVMs = new Set();
2618
- activeComponents.set(Ctor, componentVMs);
2619
- }
2620
2697
  // this will allow us to keep track of the hot components
2621
- componentVMs.add(vm);
2698
+ activeComponents.add(Ctor, vm);
2622
2699
  // tracking active template
2623
2700
  const tpl = vm.cmpTemplate;
2624
2701
  if (tpl) {
2625
- let templateVMs = activeTemplates.get(tpl);
2626
- if (shared.isUndefined(templateVMs)) {
2627
- templateVMs = new Set();
2628
- activeTemplates.set(tpl, templateVMs);
2629
- }
2630
2702
  // this will allow us to keep track of the templates that are
2631
2703
  // being used by a hot component
2632
- templateVMs.add(vm);
2704
+ activeTemplates.add(tpl, vm);
2633
2705
  // tracking active styles associated to template
2634
2706
  const stylesheets = tpl.stylesheets;
2635
2707
  if (!shared.isUndefined(stylesheets)) {
2636
- flattenStylesheets(stylesheets).forEach((stylesheet) => {
2708
+ for (const stylesheet of flattenStylesheets(stylesheets)) {
2637
2709
  // this is necessary because we don't hold the list of styles
2638
2710
  // in the vm, we only hold the selected (already swapped template)
2639
2711
  // but the styles attached to the template might not be the actual
2640
2712
  // active ones, but the swapped versions of those.
2641
- stylesheet = getStyleOrSwappedStyle(stylesheet);
2642
- let stylesheetVMs = activeStyles.get(stylesheet);
2643
- if (shared.isUndefined(stylesheetVMs)) {
2644
- stylesheetVMs = new Set();
2645
- activeStyles.set(stylesheet, stylesheetVMs);
2646
- }
2713
+ const swappedStylesheet = getStyleOrSwappedStyle(stylesheet);
2647
2714
  // this will allow us to keep track of the stylesheet that are
2648
2715
  // being used by a hot component
2649
- stylesheetVMs.add(vm);
2650
- });
2651
- }
2652
- }
2653
- }
2654
- function removeActiveVM(vm) {
2655
- if (process.env.NODE_ENV === 'production') {
2656
- // this method should never leak to prod
2657
- throw new ReferenceError();
2658
- }
2659
- // tracking inactive component
2660
- const Ctor = vm.def.ctor;
2661
- let list = activeComponents.get(Ctor);
2662
- if (!shared.isUndefined(list)) {
2663
- // deleting the vm from the set to avoid leaking memory
2664
- list.delete(vm);
2665
- }
2666
- // removing inactive template
2667
- const tpl = vm.cmpTemplate;
2668
- if (tpl) {
2669
- list = activeTemplates.get(tpl);
2670
- if (!shared.isUndefined(list)) {
2671
- // deleting the vm from the set to avoid leaking memory
2672
- list.delete(vm);
2673
- }
2674
- // removing active styles associated to template
2675
- const styles = tpl.stylesheets;
2676
- if (!shared.isUndefined(styles)) {
2677
- flattenStylesheets(styles).forEach((style) => {
2678
- list = activeStyles.get(style);
2679
- if (!shared.isUndefined(list)) {
2680
- // deleting the vm from the set to avoid leaking memory
2681
- list.delete(vm);
2682
- }
2683
- });
2716
+ activeStyles.add(swappedStylesheet, vm);
2717
+ }
2684
2718
  }
2685
2719
  }
2686
2720
  }
@@ -5189,9 +5223,6 @@ function resetComponentStateWhenRemoved(vm) {
5189
5223
  runChildNodesDisconnectedCallback(vm);
5190
5224
  runLightChildNodesDisconnectedCallback(vm);
5191
5225
  }
5192
- if (process.env.NODE_ENV !== 'production') {
5193
- removeActiveVM(vm);
5194
- }
5195
5226
  }
5196
5227
  // this method is triggered by the diffing algo only when a vnode from the
5197
5228
  // old vnode.children is removed from the DOM.
@@ -5569,22 +5600,33 @@ function recursivelyDisconnectChildren(vnodes) {
5569
5600
  // into snabbdom. Especially useful when the reset is a consequence of an error, in which case the
5570
5601
  // children VNodes might not be representing the current state of the DOM.
5571
5602
  function resetComponentRoot(vm) {
5603
+ recursivelyRemoveChildren(vm.children, vm);
5604
+ vm.children = EmptyArray;
5605
+ runChildNodesDisconnectedCallback(vm);
5606
+ vm.velements = EmptyArray;
5607
+ }
5608
+ // Helper function to remove all children of the root node.
5609
+ // If the set of children includes VFragment nodes, we need to remove the children of those nodes too.
5610
+ // Since VFragments can contain other VFragments, we need to traverse the entire of tree of VFragments.
5611
+ // If the set contains no VFragment nodes, no traversal is needed.
5612
+ function recursivelyRemoveChildren(vnodes, vm) {
5572
5613
  const {
5573
- children,
5574
5614
  renderRoot,
5575
5615
  renderer: {
5576
5616
  remove
5577
5617
  }
5578
5618
  } = vm;
5579
- for (let i = 0, len = children.length; i < len; i++) {
5580
- const child = children[i];
5581
- if (!shared.isNull(child) && !shared.isUndefined(child.elm)) {
5582
- remove(child.elm, renderRoot);
5619
+ for (let i = 0, len = vnodes.length; i < len; i += 1) {
5620
+ const vnode = vnodes[i];
5621
+ if (!shared.isNull(vnode)) {
5622
+ // VFragments are special; their .elm property does not point to the root element since they have no single root.
5623
+ if (isVFragment(vnode)) {
5624
+ recursivelyRemoveChildren(vnode.children, vm);
5625
+ } else if (!shared.isUndefined(vnode.elm)) {
5626
+ remove(vnode.elm, renderRoot);
5627
+ }
5583
5628
  }
5584
5629
  }
5585
- vm.children = EmptyArray;
5586
- runChildNodesDisconnectedCallback(vm);
5587
- vm.velements = EmptyArray;
5588
5630
  }
5589
5631
  function scheduleRehydration(vm) {
5590
5632
  if (!process.env.IS_BROWSER || shared.isTrue(vm.isScheduled)) {
@@ -6570,4 +6612,4 @@ exports.swapTemplate = swapTemplate;
6570
6612
  exports.track = track;
6571
6613
  exports.unwrap = unwrap;
6572
6614
  exports.wire = wire;
6573
- /* version: 2.31.6 */
6615
+ /* version: 2.31.8 */
@@ -2496,6 +2496,93 @@ const BaseBridgeElement = HTMLBridgeElementFactory(HTMLElementConstructor, getOw
2496
2496
  freeze(BaseBridgeElement);
2497
2497
  seal(BaseBridgeElement.prototype);
2498
2498
 
2499
+ /*
2500
+ * Copyright (c) 2023, salesforce.com, inc.
2501
+ * All rights reserved.
2502
+ * SPDX-License-Identifier: MIT
2503
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
2504
+ */
2505
+ const supportsWeakRefs = typeof WeakRef === 'function' && typeof FinalizationRegistry === 'function';
2506
+ // In browsers that doesn't support WeakRefs, the values will still leak, but at least the keys won't
2507
+ class LegacyWeakMultiMap {
2508
+ constructor() {
2509
+ this._map = new WeakMap();
2510
+ }
2511
+ _getValues(key) {
2512
+ let values = this._map.get(key);
2513
+ if (isUndefined$1(values)) {
2514
+ values = new Set();
2515
+ this._map.set(key, values);
2516
+ }
2517
+ return values;
2518
+ }
2519
+ get(key) {
2520
+ return this._getValues(key);
2521
+ }
2522
+ add(key, vm) {
2523
+ const set = this._getValues(key);
2524
+ set.add(vm);
2525
+ }
2526
+ delete(key) {
2527
+ this._map.delete(key);
2528
+ }
2529
+ }
2530
+ // This implementation relies on the WeakRef/FinalizationRegistry proposal.
2531
+ // For some background, see: https://github.com/tc39/proposal-weakrefs
2532
+ class ModernWeakMultiMap {
2533
+ constructor() {
2534
+ this._map = new WeakMap();
2535
+ this._registry = new FinalizationRegistry((weakRefs) => {
2536
+ // This should be considered an optional cleanup method to remove GC'ed values from their respective arrays.
2537
+ // JS VMs are not obligated to call FinalizationRegistry callbacks.
2538
+ // Work backwards, removing stale VMs
2539
+ for (let i = weakRefs.length - 1; i >= 0; i--) {
2540
+ const vm = weakRefs[i].deref();
2541
+ if (isUndefined$1(vm)) {
2542
+ ArraySplice.call(weakRefs, i, 1); // remove
2543
+ }
2544
+ }
2545
+ });
2546
+ }
2547
+ _getWeakRefs(key) {
2548
+ let weakRefs = this._map.get(key);
2549
+ if (isUndefined$1(weakRefs)) {
2550
+ weakRefs = [];
2551
+ this._map.set(key, weakRefs);
2552
+ }
2553
+ return weakRefs;
2554
+ }
2555
+ get(key) {
2556
+ const weakRefs = this._getWeakRefs(key);
2557
+ const result = new Set();
2558
+ for (const weakRef of weakRefs) {
2559
+ const vm = weakRef.deref();
2560
+ if (!isUndefined$1(vm)) {
2561
+ result.add(vm);
2562
+ }
2563
+ }
2564
+ return result;
2565
+ }
2566
+ add(key, value) {
2567
+ const weakRefs = this._getWeakRefs(key);
2568
+ // We could check for duplicate values here, but it doesn't seem worth it.
2569
+ // We transform the output into a Set anyway
2570
+ ArrayPush$1.call(weakRefs, new WeakRef(value));
2571
+ // It's important here not to leak the second argument, which is the "held value." The FinalizationRegistry
2572
+ // effectively creates a strong reference between the first argument (the "target") and the held value. When
2573
+ // the target is GC'ed, the callback is called, and then the held value is GC'ed.
2574
+ // Putting the key here would mean the key is not GC'ed until the value is GC'ed, which defeats the purpose
2575
+ // of the WeakMap. Whereas putting the weakRefs array here is fine, because it doesn't have a strong reference
2576
+ // to anything. See also this example:
2577
+ // https://gist.github.com/nolanlawson/79a3d36e8e6cc25c5048bb17c1795aea
2578
+ this._registry.register(value, weakRefs);
2579
+ }
2580
+ delete(key) {
2581
+ this._map.delete(key);
2582
+ }
2583
+ }
2584
+ const WeakMultiMap = supportsWeakRefs ? ModernWeakMultiMap : LegacyWeakMultiMap;
2585
+
2499
2586
  /*
2500
2587
  * Copyright (c) 2020, salesforce.com, inc.
2501
2588
  * All rights reserved.
@@ -2505,67 +2592,62 @@ seal(BaseBridgeElement.prototype);
2505
2592
  const swappedTemplateMap = new WeakMap();
2506
2593
  const swappedComponentMap = new WeakMap();
2507
2594
  const swappedStyleMap = new WeakMap();
2508
- const activeTemplates = new WeakMap();
2509
- const activeComponents = new WeakMap();
2510
- const activeStyles = new WeakMap();
2595
+ // The important thing here is the weak values – VMs are transient (one per component instance) and should be GC'ed,
2596
+ // so we don't want to create strong references to them.
2597
+ // The weak keys are kind of useless, because Templates, LightningElementConstructors, and StylesheetFactories are
2598
+ // never GC'ed. But maybe they will be someday, so we may as well use weak keys too.
2599
+ const activeTemplates = new WeakMultiMap();
2600
+ const activeComponents = new WeakMultiMap();
2601
+ const activeStyles = new WeakMultiMap();
2511
2602
  function rehydrateHotTemplate(tpl) {
2512
2603
  const list = activeTemplates.get(tpl);
2513
- if (!isUndefined$1(list)) {
2514
- list.forEach((vm) => {
2515
- if (isFalse(vm.isDirty)) {
2516
- // forcing the vm to rehydrate in the micro-task:
2517
- markComponentAsDirty(vm);
2518
- scheduleRehydration(vm);
2519
- }
2520
- });
2521
- // resetting the Set to release the memory of those vm references
2522
- // since they are not longer related to this template, instead
2523
- // they will get re-associated once these instances are rehydrated.
2524
- list.clear();
2604
+ for (const vm of list) {
2605
+ if (isFalse(vm.isDirty)) {
2606
+ // forcing the vm to rehydrate in the micro-task:
2607
+ markComponentAsDirty(vm);
2608
+ scheduleRehydration(vm);
2609
+ }
2525
2610
  }
2611
+ // Resetting the Set since these VMs are no longer related to this template, instead
2612
+ // they will get re-associated once these instances are rehydrated.
2613
+ activeTemplates.delete(tpl);
2526
2614
  return true;
2527
2615
  }
2528
2616
  function rehydrateHotStyle(style) {
2529
2617
  const list = activeStyles.get(style);
2530
- if (!isUndefined$1(list)) {
2531
- list.forEach((vm) => {
2532
- // if a style definition is swapped, we must reset
2533
- // vm's template content in the next micro-task:
2534
- forceRehydration(vm);
2535
- });
2536
- // resetting the Set to release the memory of those vm references
2537
- // since they are not longer related to this style, instead
2538
- // they will get re-associated once these instances are rehydrated.
2539
- list.clear();
2540
- }
2618
+ for (const vm of list) {
2619
+ // if a style definition is swapped, we must reset
2620
+ // vm's template content in the next micro-task:
2621
+ forceRehydration(vm);
2622
+ }
2623
+ // Resetting the Set since these VMs are no longer related to this style, instead
2624
+ // they will get re-associated once these instances are rehydrated.
2625
+ activeStyles.delete(style);
2541
2626
  return true;
2542
2627
  }
2543
2628
  function rehydrateHotComponent(Ctor) {
2544
2629
  const list = activeComponents.get(Ctor);
2545
2630
  let canRefreshAllInstances = true;
2546
- if (!isUndefined$1(list)) {
2547
- list.forEach((vm) => {
2548
- const { owner } = vm;
2549
- if (!isNull(owner)) {
2550
- // if a component class definition is swapped, we must reset
2551
- // owner's template content in the next micro-task:
2552
- forceRehydration(owner);
2553
- }
2554
- else {
2555
- // the hot swapping for components only work for instances of components
2556
- // created from a template, root elements can't be swapped because we
2557
- // don't have a way to force the creation of the element with the same state
2558
- // of the current element.
2559
- // Instead, we can report the problem to the caller so it can take action,
2560
- // for example: reload the entire page.
2561
- canRefreshAllInstances = false;
2562
- }
2563
- });
2564
- // resetting the Set to release the memory of those vm references
2565
- // since they are not longer related to this constructor, instead
2566
- // they will get re-associated once these instances are rehydrated.
2567
- list.clear();
2568
- }
2631
+ for (const vm of list) {
2632
+ const { owner } = vm;
2633
+ if (!isNull(owner)) {
2634
+ // if a component class definition is swapped, we must reset
2635
+ // owner's template content in the next micro-task:
2636
+ forceRehydration(owner);
2637
+ }
2638
+ else {
2639
+ // the hot swapping for components only work for instances of components
2640
+ // created from a template, root elements can't be swapped because we
2641
+ // don't have a way to force the creation of the element with the same state
2642
+ // of the current element.
2643
+ // Instead, we can report the problem to the caller so it can take action,
2644
+ // for example: reload the entire page.
2645
+ canRefreshAllInstances = false;
2646
+ }
2647
+ }
2648
+ // resetting the Set since these VMs are no longer related to this constructor, instead
2649
+ // they will get re-associated once these instances are rehydrated.
2650
+ activeComponents.delete(Ctor);
2569
2651
  return canRefreshAllInstances;
2570
2652
  }
2571
2653
  function getTemplateOrSwappedTemplate(tpl) {
@@ -2611,75 +2693,27 @@ function setActiveVM(vm) {
2611
2693
  }
2612
2694
  // tracking active component
2613
2695
  const Ctor = vm.def.ctor;
2614
- let componentVMs = activeComponents.get(Ctor);
2615
- if (isUndefined$1(componentVMs)) {
2616
- componentVMs = new Set();
2617
- activeComponents.set(Ctor, componentVMs);
2618
- }
2619
2696
  // this will allow us to keep track of the hot components
2620
- componentVMs.add(vm);
2697
+ activeComponents.add(Ctor, vm);
2621
2698
  // tracking active template
2622
2699
  const tpl = vm.cmpTemplate;
2623
2700
  if (tpl) {
2624
- let templateVMs = activeTemplates.get(tpl);
2625
- if (isUndefined$1(templateVMs)) {
2626
- templateVMs = new Set();
2627
- activeTemplates.set(tpl, templateVMs);
2628
- }
2629
2701
  // this will allow us to keep track of the templates that are
2630
2702
  // being used by a hot component
2631
- templateVMs.add(vm);
2703
+ activeTemplates.add(tpl, vm);
2632
2704
  // tracking active styles associated to template
2633
2705
  const stylesheets = tpl.stylesheets;
2634
2706
  if (!isUndefined$1(stylesheets)) {
2635
- flattenStylesheets(stylesheets).forEach((stylesheet) => {
2707
+ for (const stylesheet of flattenStylesheets(stylesheets)) {
2636
2708
  // this is necessary because we don't hold the list of styles
2637
2709
  // in the vm, we only hold the selected (already swapped template)
2638
2710
  // but the styles attached to the template might not be the actual
2639
2711
  // active ones, but the swapped versions of those.
2640
- stylesheet = getStyleOrSwappedStyle(stylesheet);
2641
- let stylesheetVMs = activeStyles.get(stylesheet);
2642
- if (isUndefined$1(stylesheetVMs)) {
2643
- stylesheetVMs = new Set();
2644
- activeStyles.set(stylesheet, stylesheetVMs);
2645
- }
2712
+ const swappedStylesheet = getStyleOrSwappedStyle(stylesheet);
2646
2713
  // this will allow us to keep track of the stylesheet that are
2647
2714
  // being used by a hot component
2648
- stylesheetVMs.add(vm);
2649
- });
2650
- }
2651
- }
2652
- }
2653
- function removeActiveVM(vm) {
2654
- if (process.env.NODE_ENV === 'production') {
2655
- // this method should never leak to prod
2656
- throw new ReferenceError();
2657
- }
2658
- // tracking inactive component
2659
- const Ctor = vm.def.ctor;
2660
- let list = activeComponents.get(Ctor);
2661
- if (!isUndefined$1(list)) {
2662
- // deleting the vm from the set to avoid leaking memory
2663
- list.delete(vm);
2664
- }
2665
- // removing inactive template
2666
- const tpl = vm.cmpTemplate;
2667
- if (tpl) {
2668
- list = activeTemplates.get(tpl);
2669
- if (!isUndefined$1(list)) {
2670
- // deleting the vm from the set to avoid leaking memory
2671
- list.delete(vm);
2672
- }
2673
- // removing active styles associated to template
2674
- const styles = tpl.stylesheets;
2675
- if (!isUndefined$1(styles)) {
2676
- flattenStylesheets(styles).forEach((style) => {
2677
- list = activeStyles.get(style);
2678
- if (!isUndefined$1(list)) {
2679
- // deleting the vm from the set to avoid leaking memory
2680
- list.delete(vm);
2681
- }
2682
- });
2715
+ activeStyles.add(swappedStylesheet, vm);
2716
+ }
2683
2717
  }
2684
2718
  }
2685
2719
  }
@@ -5188,9 +5222,6 @@ function resetComponentStateWhenRemoved(vm) {
5188
5222
  runChildNodesDisconnectedCallback(vm);
5189
5223
  runLightChildNodesDisconnectedCallback(vm);
5190
5224
  }
5191
- if (process.env.NODE_ENV !== 'production') {
5192
- removeActiveVM(vm);
5193
- }
5194
5225
  }
5195
5226
  // this method is triggered by the diffing algo only when a vnode from the
5196
5227
  // old vnode.children is removed from the DOM.
@@ -5568,22 +5599,33 @@ function recursivelyDisconnectChildren(vnodes) {
5568
5599
  // into snabbdom. Especially useful when the reset is a consequence of an error, in which case the
5569
5600
  // children VNodes might not be representing the current state of the DOM.
5570
5601
  function resetComponentRoot(vm) {
5602
+ recursivelyRemoveChildren(vm.children, vm);
5603
+ vm.children = EmptyArray;
5604
+ runChildNodesDisconnectedCallback(vm);
5605
+ vm.velements = EmptyArray;
5606
+ }
5607
+ // Helper function to remove all children of the root node.
5608
+ // If the set of children includes VFragment nodes, we need to remove the children of those nodes too.
5609
+ // Since VFragments can contain other VFragments, we need to traverse the entire of tree of VFragments.
5610
+ // If the set contains no VFragment nodes, no traversal is needed.
5611
+ function recursivelyRemoveChildren(vnodes, vm) {
5571
5612
  const {
5572
- children,
5573
5613
  renderRoot,
5574
5614
  renderer: {
5575
5615
  remove
5576
5616
  }
5577
5617
  } = vm;
5578
- for (let i = 0, len = children.length; i < len; i++) {
5579
- const child = children[i];
5580
- if (!isNull(child) && !isUndefined$1(child.elm)) {
5581
- remove(child.elm, renderRoot);
5618
+ for (let i = 0, len = vnodes.length; i < len; i += 1) {
5619
+ const vnode = vnodes[i];
5620
+ if (!isNull(vnode)) {
5621
+ // VFragments are special; their .elm property does not point to the root element since they have no single root.
5622
+ if (isVFragment(vnode)) {
5623
+ recursivelyRemoveChildren(vnode.children, vm);
5624
+ } else if (!isUndefined$1(vnode.elm)) {
5625
+ remove(vnode.elm, renderRoot);
5626
+ }
5582
5627
  }
5583
5628
  }
5584
- vm.children = EmptyArray;
5585
- runChildNodesDisconnectedCallback(vm);
5586
- vm.velements = EmptyArray;
5587
5629
  }
5588
5630
  function scheduleRehydration(vm) {
5589
5631
  if (!process.env.IS_BROWSER || isTrue(vm.isScheduled)) {
@@ -6533,4 +6575,4 @@ function getComponentConstructor(elm) {
6533
6575
  }
6534
6576
 
6535
6577
  export { LightningElement, profilerControl as __unstable__ProfilerControl, api$1 as api, connectRootElement, createContextProvider, createVM, disconnectRootElement, freezeTemplate, getAssociatedVMIfPresent, getComponentConstructor, getComponentDef, getComponentHtmlPrototype, hydrateRoot, isComponentConstructor, parseFragment, parseSVGFragment, readonly, register, registerComponent, registerDecorators, registerTemplate, sanitizeAttribute, setHooks, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
6536
- /* version: 2.31.6 */
6578
+ /* version: 2.31.8 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lwc/engine-core",
3
- "version": "2.31.6",
3
+ "version": "2.31.8",
4
4
  "description": "Core LWC engine APIs.",
5
5
  "homepage": "https://lwc.dev/",
6
6
  "repository": {
@@ -24,8 +24,8 @@
24
24
  "types/"
25
25
  ],
26
26
  "dependencies": {
27
- "@lwc/features": "2.31.6",
28
- "@lwc/shared": "2.31.6"
27
+ "@lwc/features": "2.31.8",
28
+ "@lwc/shared": "2.31.8"
29
29
  },
30
30
  "devDependencies": {
31
31
  "observable-membrane": "2.0.0"
@@ -6,7 +6,6 @@ export declare function getTemplateOrSwappedTemplate(tpl: Template): Template;
6
6
  export declare function getComponentOrSwappedComponent(Ctor: LightningElementConstructor): LightningElementConstructor;
7
7
  export declare function getStyleOrSwappedStyle(style: StylesheetFactory): StylesheetFactory;
8
8
  export declare function setActiveVM(vm: VM): void;
9
- export declare function removeActiveVM(vm: VM): void;
10
9
  export declare function swapTemplate(oldTpl: Template, newTpl: Template): boolean;
11
10
  export declare function swapComponent(oldComponent: LightningElementConstructor, newComponent: LightningElementConstructor): boolean;
12
11
  export declare function swapStyle(oldStyle: StylesheetFactory, newStyle: StylesheetFactory): boolean;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * A map where the keys are weakly held and the values are a Set that are also each weakly held.
3
+ * The goal is to avoid leaking the values, which is what would happen with a WeakMap<K, Set<V>>.
4
+ *
5
+ * Note that this is currently only intended to be used in dev/PRODDEBUG environments.
6
+ * It leaks in legacy browsers, which may be undesired.
7
+ */
8
+ export interface WeakMultiMap<T extends object, V extends object> {
9
+ get(key: T): ReadonlySet<V>;
10
+ add(key: T, vm: V): void;
11
+ delete(key: T): void;
12
+ }
13
+ declare class LegacyWeakMultiMap<K extends object, V extends object> implements WeakMultiMap<K, V> {
14
+ private _map;
15
+ private _getValues;
16
+ get(key: K): ReadonlySet<V>;
17
+ add(key: K, vm: V): void;
18
+ delete(key: K): void;
19
+ }
20
+ declare class ModernWeakMultiMap<K extends object, V extends object> implements WeakMultiMap<K, V> {
21
+ private _map;
22
+ private _registry;
23
+ private _getWeakRefs;
24
+ get(key: K): ReadonlySet<V>;
25
+ add(key: K, value: V): void;
26
+ delete(key: K): void;
27
+ }
28
+ export declare const WeakMultiMap: typeof LegacyWeakMultiMap | typeof ModernWeakMultiMap;
29
+ export {};