@lwc/engine-core 2.8.0 → 2.9.0

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.
@@ -71,6 +71,18 @@ function parseStyleText(cssText) {
71
71
  }
72
72
 
73
73
  return styleMap;
74
+ } // Make a shallow copy of an object but omit the given key
75
+
76
+ function cloneAndOmitKey(object, keyToOmit) {
77
+ const result = {};
78
+
79
+ for (const key of Object.keys(object)) {
80
+ if (key !== keyToOmit) {
81
+ result[key] = object[key];
82
+ }
83
+ }
84
+
85
+ return result;
74
86
  }
75
87
 
76
88
  //
@@ -4170,11 +4182,13 @@ function fallbackElmHook(elm, vnode) {
4170
4182
  ) {
4171
4183
  // this element will now accept any manual content inserted into it
4172
4184
  observeElementChildNodes(elm);
4173
- } // when running in synthetic shadow mode, we need to set the shadowToken value
4174
- // into each element from the template, so they can be styled accordingly.
4175
-
4185
+ }
4176
4186
 
4177
- setElementShadowToken(elm, stylesheetToken);
4187
+ if (!shared.isUndefined(stylesheetToken)) {
4188
+ // when running in synthetic shadow mode, we need to set the shadowToken value
4189
+ // into each element from the template, so they can be styled accordingly.
4190
+ setElementShadowToken(elm, stylesheetToken);
4191
+ }
4178
4192
  }
4179
4193
 
4180
4194
  if (process.env.NODE_ENV !== 'production') {
@@ -4260,7 +4274,9 @@ function createViewModelHook(elm, vnode) {
4260
4274
  } = owner.context; // when running in synthetic shadow mode, we need to set the shadowToken value
4261
4275
  // into each element from the template, so they can be styled accordingly.
4262
4276
 
4263
- setElementShadowToken(elm, stylesheetToken);
4277
+ if (!shared.isUndefined(stylesheetToken)) {
4278
+ setElementShadowToken(elm, stylesheetToken);
4279
+ }
4264
4280
  }
4265
4281
 
4266
4282
  vm = createVM(elm, ctor, {
@@ -4441,6 +4457,7 @@ function updateDynamicChildren(parentElm, oldCh, newCh) {
4441
4457
  let idxInOld;
4442
4458
  let elmToMove;
4443
4459
  let before;
4460
+ let clonedOldCh = false;
4444
4461
 
4445
4462
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
4446
4463
  if (!isVNode(oldStartVnode)) {
@@ -4492,7 +4509,18 @@ function updateDynamicChildren(parentElm, oldCh, newCh) {
4492
4509
  newStartVnode.hook.create(newStartVnode);
4493
4510
  newStartVnode.hook.insert(newStartVnode, parentElm, oldStartVnode.elm);
4494
4511
  } else {
4495
- patchVnode(elmToMove, newStartVnode);
4512
+ patchVnode(elmToMove, newStartVnode); // Delete the old child, but copy the array since it is read-only.
4513
+ // The `oldCh` will be GC'ed after `updateDynamicChildren` is complete,
4514
+ // so we only care about the `oldCh` object inside this function.
4515
+ // To avoid cloning over and over again, we check `clonedOldCh`
4516
+ // and only clone once.
4517
+
4518
+ if (!clonedOldCh) {
4519
+ clonedOldCh = true;
4520
+ oldCh = [...oldCh];
4521
+ } // We've already cloned at least once, so it's no longer read-only
4522
+
4523
+
4496
4524
  oldCh[idxInOld] = undefined;
4497
4525
  newStartVnode.hook.move(elmToMove, parentElm, oldStartVnode.elm);
4498
4526
  }
@@ -4588,7 +4616,7 @@ function addVNodeToChildLWC(vnode) {
4588
4616
  } // [h]tml node
4589
4617
 
4590
4618
 
4591
- function h(sel, data, children) {
4619
+ function h(sel, data, children = EmptyArray) {
4592
4620
  const vmBeingRendered = getVMBeingRendered();
4593
4621
 
4594
4622
  if (process.env.NODE_ENV !== 'production') {
@@ -4986,7 +5014,7 @@ let dynamicImportedComponentCounter = 0;
4986
5014
  * create a dynamic component via `<x-foo lwc:dynamic={Ctor}>`
4987
5015
  */
4988
5016
 
4989
- function dc(sel, Ctor, data, children) {
5017
+ function dc(sel, Ctor, data, children = EmptyArray) {
4990
5018
  if (process.env.NODE_ENV !== 'production') {
4991
5019
  shared.assert.isTrue(shared.isString(sel), `dc() 1st argument sel must be a string.`);
4992
5020
  shared.assert.isTrue(shared.isObject(data), `dc() 3nd argument data must be an object.`);
@@ -5010,10 +5038,14 @@ function dc(sel, Ctor, data, children) {
5010
5038
  } // the new vnode key is a mix of idx and compiler key, this is required by the diffing algo
5011
5039
  // to identify different constructors as vnodes with different keys to avoid reusing the
5012
5040
  // element used for previous constructors.
5041
+ // Shallow clone is necessary here becuase VElementData may be shared across VNodes due to
5042
+ // hoisting optimization.
5013
5043
 
5014
5044
 
5015
- data.key = `dc:${idx}:${data.key}`;
5016
- return c(sel, Ctor, data, children);
5045
+ const newData = Object.assign(Object.assign({}, data), {
5046
+ key: `dc:${idx}:${data.key}`
5047
+ });
5048
+ return c(sel, Ctor, newData, children);
5017
5049
  }
5018
5050
  /**
5019
5051
  * slow children collection marking mechanism. this API allows the compiler to signal
@@ -5133,12 +5165,14 @@ function updateStylesheetToken(vm, template) {
5133
5165
  hasTokenInAttribute: oldHasTokenInAttribute
5134
5166
  } = context;
5135
5167
 
5136
- if (oldHasTokenInClass) {
5137
- getClassList(elm).remove(makeHostToken(oldToken));
5138
- }
5168
+ if (!shared.isUndefined(oldToken)) {
5169
+ if (oldHasTokenInClass) {
5170
+ getClassList(elm).remove(makeHostToken(oldToken));
5171
+ }
5139
5172
 
5140
- if (oldHasTokenInAttribute) {
5141
- removeAttribute(elm, makeHostToken(oldToken));
5173
+ if (oldHasTokenInAttribute) {
5174
+ removeAttribute(elm, makeHostToken(oldToken));
5175
+ }
5142
5176
  } // Apply the new template styling token to the host element, if the new template has any
5143
5177
  // associated stylesheets. In the case of light DOM, also ensure there is at least one scoped stylesheet.
5144
5178
 
@@ -5919,7 +5953,10 @@ function hydrateElement(vnode, node) {
5919
5953
 
5920
5954
  if (!shared.isUndefined(props) && !shared.isUndefined(props.innerHTML)) {
5921
5955
  if (elm.innerHTML === props.innerHTML) {
5922
- delete props.innerHTML;
5956
+ // Do a shallow clone since VNodeData may be shared across VNodes due to hoist optimization
5957
+ vnode.data = Object.assign(Object.assign({}, vnode.data), {
5958
+ props: cloneAndOmitKey(props, 'innerHTML')
5959
+ });
5923
5960
  } else {
5924
5961
  logWarn(`Mismatch hydrating element <${elm.tagName.toLowerCase()}>: innerHTML values do not match for element, will recover from the difference`, vnode.owner);
5925
5962
  }
@@ -7268,4 +7305,4 @@ exports.swapTemplate = swapTemplate;
7268
7305
  exports.track = track;
7269
7306
  exports.unwrap = unwrap;
7270
7307
  exports.wire = wire;
7271
- /* version: 2.8.0 */
7308
+ /* version: 2.9.0 */
@@ -68,6 +68,18 @@ function parseStyleText(cssText) {
68
68
  }
69
69
 
70
70
  return styleMap;
71
+ } // Make a shallow copy of an object but omit the given key
72
+
73
+ function cloneAndOmitKey(object, keyToOmit) {
74
+ const result = {};
75
+
76
+ for (const key of Object.keys(object)) {
77
+ if (key !== keyToOmit) {
78
+ result[key] = object[key];
79
+ }
80
+ }
81
+
82
+ return result;
71
83
  }
72
84
 
73
85
  //
@@ -4167,11 +4179,13 @@ function fallbackElmHook(elm, vnode) {
4167
4179
  ) {
4168
4180
  // this element will now accept any manual content inserted into it
4169
4181
  observeElementChildNodes(elm);
4170
- } // when running in synthetic shadow mode, we need to set the shadowToken value
4171
- // into each element from the template, so they can be styled accordingly.
4172
-
4182
+ }
4173
4183
 
4174
- setElementShadowToken(elm, stylesheetToken);
4184
+ if (!isUndefined$1(stylesheetToken)) {
4185
+ // when running in synthetic shadow mode, we need to set the shadowToken value
4186
+ // into each element from the template, so they can be styled accordingly.
4187
+ setElementShadowToken(elm, stylesheetToken);
4188
+ }
4175
4189
  }
4176
4190
 
4177
4191
  if (process.env.NODE_ENV !== 'production') {
@@ -4257,7 +4271,9 @@ function createViewModelHook(elm, vnode) {
4257
4271
  } = owner.context; // when running in synthetic shadow mode, we need to set the shadowToken value
4258
4272
  // into each element from the template, so they can be styled accordingly.
4259
4273
 
4260
- setElementShadowToken(elm, stylesheetToken);
4274
+ if (!isUndefined$1(stylesheetToken)) {
4275
+ setElementShadowToken(elm, stylesheetToken);
4276
+ }
4261
4277
  }
4262
4278
 
4263
4279
  vm = createVM(elm, ctor, {
@@ -4438,6 +4454,7 @@ function updateDynamicChildren(parentElm, oldCh, newCh) {
4438
4454
  let idxInOld;
4439
4455
  let elmToMove;
4440
4456
  let before;
4457
+ let clonedOldCh = false;
4441
4458
 
4442
4459
  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
4443
4460
  if (!isVNode(oldStartVnode)) {
@@ -4489,7 +4506,18 @@ function updateDynamicChildren(parentElm, oldCh, newCh) {
4489
4506
  newStartVnode.hook.create(newStartVnode);
4490
4507
  newStartVnode.hook.insert(newStartVnode, parentElm, oldStartVnode.elm);
4491
4508
  } else {
4492
- patchVnode(elmToMove, newStartVnode);
4509
+ patchVnode(elmToMove, newStartVnode); // Delete the old child, but copy the array since it is read-only.
4510
+ // The `oldCh` will be GC'ed after `updateDynamicChildren` is complete,
4511
+ // so we only care about the `oldCh` object inside this function.
4512
+ // To avoid cloning over and over again, we check `clonedOldCh`
4513
+ // and only clone once.
4514
+
4515
+ if (!clonedOldCh) {
4516
+ clonedOldCh = true;
4517
+ oldCh = [...oldCh];
4518
+ } // We've already cloned at least once, so it's no longer read-only
4519
+
4520
+
4493
4521
  oldCh[idxInOld] = undefined;
4494
4522
  newStartVnode.hook.move(elmToMove, parentElm, oldStartVnode.elm);
4495
4523
  }
@@ -4585,7 +4613,7 @@ function addVNodeToChildLWC(vnode) {
4585
4613
  } // [h]tml node
4586
4614
 
4587
4615
 
4588
- function h(sel, data, children) {
4616
+ function h(sel, data, children = EmptyArray) {
4589
4617
  const vmBeingRendered = getVMBeingRendered();
4590
4618
 
4591
4619
  if (process.env.NODE_ENV !== 'production') {
@@ -4983,7 +5011,7 @@ let dynamicImportedComponentCounter = 0;
4983
5011
  * create a dynamic component via `<x-foo lwc:dynamic={Ctor}>`
4984
5012
  */
4985
5013
 
4986
- function dc(sel, Ctor, data, children) {
5014
+ function dc(sel, Ctor, data, children = EmptyArray) {
4987
5015
  if (process.env.NODE_ENV !== 'production') {
4988
5016
  assert.isTrue(isString(sel), `dc() 1st argument sel must be a string.`);
4989
5017
  assert.isTrue(isObject(data), `dc() 3nd argument data must be an object.`);
@@ -5007,10 +5035,14 @@ function dc(sel, Ctor, data, children) {
5007
5035
  } // the new vnode key is a mix of idx and compiler key, this is required by the diffing algo
5008
5036
  // to identify different constructors as vnodes with different keys to avoid reusing the
5009
5037
  // element used for previous constructors.
5038
+ // Shallow clone is necessary here becuase VElementData may be shared across VNodes due to
5039
+ // hoisting optimization.
5010
5040
 
5011
5041
 
5012
- data.key = `dc:${idx}:${data.key}`;
5013
- return c(sel, Ctor, data, children);
5042
+ const newData = Object.assign(Object.assign({}, data), {
5043
+ key: `dc:${idx}:${data.key}`
5044
+ });
5045
+ return c(sel, Ctor, newData, children);
5014
5046
  }
5015
5047
  /**
5016
5048
  * slow children collection marking mechanism. this API allows the compiler to signal
@@ -5130,12 +5162,14 @@ function updateStylesheetToken(vm, template) {
5130
5162
  hasTokenInAttribute: oldHasTokenInAttribute
5131
5163
  } = context;
5132
5164
 
5133
- if (oldHasTokenInClass) {
5134
- getClassList(elm).remove(makeHostToken(oldToken));
5135
- }
5165
+ if (!isUndefined$1(oldToken)) {
5166
+ if (oldHasTokenInClass) {
5167
+ getClassList(elm).remove(makeHostToken(oldToken));
5168
+ }
5136
5169
 
5137
- if (oldHasTokenInAttribute) {
5138
- removeAttribute(elm, makeHostToken(oldToken));
5170
+ if (oldHasTokenInAttribute) {
5171
+ removeAttribute(elm, makeHostToken(oldToken));
5172
+ }
5139
5173
  } // Apply the new template styling token to the host element, if the new template has any
5140
5174
  // associated stylesheets. In the case of light DOM, also ensure there is at least one scoped stylesheet.
5141
5175
 
@@ -5916,7 +5950,10 @@ function hydrateElement(vnode, node) {
5916
5950
 
5917
5951
  if (!isUndefined$1(props) && !isUndefined$1(props.innerHTML)) {
5918
5952
  if (elm.innerHTML === props.innerHTML) {
5919
- delete props.innerHTML;
5953
+ // Do a shallow clone since VNodeData may be shared across VNodes due to hoist optimization
5954
+ vnode.data = Object.assign(Object.assign({}, vnode.data), {
5955
+ props: cloneAndOmitKey(props, 'innerHTML')
5956
+ });
5920
5957
  } else {
5921
5958
  logWarn(`Mismatch hydrating element <${elm.tagName.toLowerCase()}>: innerHTML values do not match for element, will recover from the difference`, vnode.owner);
5922
5959
  }
@@ -7192,4 +7229,4 @@ function setHooks(hooks) {
7192
7229
  }
7193
7230
 
7194
7231
  export { LightningElement, profilerControl as __unstable__ProfilerControl, api$1 as api, connectRootElement, createContextProvider, createVM, disconnectRootElement, getAssociatedVMIfPresent, getComponentDef, getComponentHtmlPrototype, getUpgradableConstructor, hydrateRootElement, isComponentConstructor, readonly, register, registerComponent, registerDecorators, registerTemplate, sanitizeAttribute, setAddEventListener, setAssertInstanceOfHTMLElement, setAttachShadow, setCreateComment, setCreateElement, setCreateText, setDefineCustomElement, setDispatchEvent, setGetAttribute, setGetBoundingClientRect, setGetChildNodes, setGetChildren, setGetClassList, setGetCustomElement, setGetElementsByClassName, setGetElementsByTagName, setGetFirstChild, setGetFirstElementChild, setGetLastChild, setGetLastElementChild, setGetProperty, setHTMLElement, setHooks, setInsert, setInsertGlobalStylesheet, setInsertStylesheet, setIsConnected, setIsHydrating, setIsNativeShadowDefined, setIsSyntheticShadowDefined, setNextSibling, setQuerySelector, setQuerySelectorAll, setRemove, setRemoveAttribute, setRemoveEventListener, setSetAttribute, setSetCSSStyleProperty, setSetProperty, setSetText, setSsr, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
7195
- /* version: 2.8.0 */
7232
+ /* version: 2.9.0 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lwc/engine-core",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
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.8.0",
28
- "@lwc/shared": "2.8.0"
27
+ "@lwc/features": "2.9.0",
28
+ "@lwc/shared": "2.9.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "observable-membrane": "2.0.0"
@@ -1,7 +1,7 @@
1
1
  import { SlotSet } from './vm';
2
2
  import { LightningElementConstructor } from './base-lightning-element';
3
3
  import { VNode, VNodes, VElement, VText, VCustomElement, VComment, VElementData } from './vnodes';
4
- declare function h(sel: string, data: VElementData, children: VNodes): VElement;
4
+ declare function h(sel: string, data: VElementData, children?: VNodes): VElement;
5
5
  declare function ti(value: any): number;
6
6
  declare function s(slotName: string, data: VElementData, children: VNodes, slotset: SlotSet | undefined): VElement | VNodes;
7
7
  declare function c(sel: string, Ctor: LightningElementConstructor, data: VElementData, children?: VNodes): VCustomElement;
@@ -9,7 +9,7 @@ declare function i(iterable: Iterable<any>, factory: (value: any, index: number,
9
9
  /**
10
10
  * [f]lattening
11
11
  */
12
- declare function f(items: any[]): any[];
12
+ declare function f(items: Readonly<Array<Readonly<Array<VNodes>> | VNodes>>): VNodes;
13
13
  declare function t(text: string): VText;
14
14
  declare function co(text: string): VComment;
15
15
  declare function d(value: any): string;
@@ -1,7 +1,7 @@
1
1
  import { RenderAPI } from './api';
2
2
  import { SlotSet, TemplateCache, VM } from './vm';
3
3
  import { TemplateStylesheetFactories } from './stylesheet';
4
- import { VNode, VNodes } from './vnodes';
4
+ import { VNodes } from './vnodes';
5
5
  export interface Template {
6
6
  (api: RenderAPI, cmp: object, slotSet: SlotSet, cache: TemplateCache): VNodes;
7
7
  /** The list of slot names used in the template. */
@@ -16,4 +16,4 @@ export interface Template {
16
16
  export declare let isUpdatingTemplate: boolean;
17
17
  export declare function getVMBeingRendered(): VM | null;
18
18
  export declare function setVMBeingRendered(vm: VM | null): void;
19
- export declare function evaluateTemplate(vm: VM, html: Template): Array<VNode | null>;
19
+ export declare function evaluateTemplate(vm: VM, html: Template): VNodes;
@@ -7,4 +7,9 @@ export declare function guid(): string;
7
7
  export declare function parseStyleText(cssText: string): {
8
8
  [name: string]: string;
9
9
  };
10
+ export declare function cloneAndOmitKey(object: {
11
+ [key: string]: any;
12
+ }, keyToOmit: string): {
13
+ [key: string]: any;
14
+ };
10
15
  export {};
@@ -8,7 +8,7 @@ export declare const enum VNodeType {
8
8
  }
9
9
  export declare type VNode = VText | VComment | VElement | VCustomElement;
10
10
  export declare type VParentElement = VElement | VCustomElement;
11
- export declare type VNodes = Array<VNode | null>;
11
+ export declare type VNodes = Readonly<Array<VNode | null>>;
12
12
  export interface BaseVNode {
13
13
  type: VNodeType;
14
14
  elm: Node | undefined;
@@ -46,18 +46,18 @@ export interface VCustomElement extends VBaseElement {
46
46
  aChildren?: VNodes;
47
47
  }
48
48
  export interface VNodeData {
49
- props?: Record<string, any>;
50
- attrs?: Record<string, string | number | boolean>;
51
- className?: string;
52
- style?: string;
53
- classMap?: Record<string, boolean>;
54
- styleDecls?: Array<[string, string, boolean]>;
55
- context?: Record<string, Record<string, any>>;
56
- on?: Record<string, (event: Event) => any>;
57
- svg?: boolean;
49
+ readonly props?: Readonly<Record<string, any>>;
50
+ readonly attrs?: Readonly<Record<string, string | number | boolean>>;
51
+ readonly className?: string;
52
+ readonly style?: string;
53
+ readonly classMap?: Readonly<Record<string, boolean>>;
54
+ readonly styleDecls?: Readonly<Array<[string, string, boolean]>>;
55
+ readonly context?: Readonly<Record<string, Readonly<Record<string, any>>>>;
56
+ readonly on?: Readonly<Record<string, (event: Event) => any>>;
57
+ readonly svg?: boolean;
58
58
  }
59
59
  export interface VElementData extends VNodeData {
60
- key: Key;
60
+ readonly key: Key;
61
61
  }
62
62
  export interface Hooks<N extends VNode> {
63
63
  create: (vNode: N) => void;