@lwc/template-compiler 2.47.0 → 2.49.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.
@@ -1,5 +1,5 @@
1
1
  import * as t from '../shared/estree';
2
- import { ChildNode, Element, Expression, ComplexExpression, Literal, LWCDirectiveRenderMode, Root, EventListener } from '../shared/types';
2
+ import { ChildNode, Element, Expression, ComplexExpression, Literal, LWCDirectiveRenderMode, Root, EventListener, RefDirective } from '../shared/types';
3
3
  import State from '../state';
4
4
  export default class CodeGen {
5
5
  /** The AST root. */
@@ -76,7 +76,8 @@ export default class CodeGen {
76
76
  genTabIndex(children: [t.Expression]): import("estree").CallExpression;
77
77
  getMemorizationId(): import("estree").Identifier;
78
78
  genBooleanAttributeExpr(bindExpr: t.Expression): import("estree").ConditionalExpression;
79
- genEventListeners(listeners: EventListener[]): import("estree").ObjectExpression;
79
+ genEventListeners(listeners: EventListener[]): import("estree").Property;
80
+ genRef(ref: RefDirective): import("estree").Property;
80
81
  /**
81
82
  * This routine generates an expression that avoids
82
83
  * computing the sanitized html of a raw html if it does not change
@@ -101,5 +102,5 @@ export default class CodeGen {
101
102
  * - {value[index]} --> {$cmp.value[$cmp.index]}
102
103
  */
103
104
  bindExpression(expression: Expression | Literal | ComplexExpression): t.Expression;
104
- genHoistedElement(element: Element, slotParentName?: string): t.Expression;
105
+ genStaticElement(element: Element, slotParentName?: string): t.Expression;
105
106
  }
package/dist/index.cjs.js CHANGED
@@ -58,12 +58,6 @@ class State {
58
58
  }
59
59
  }
60
60
 
61
- /*
62
- * Copyright (c) 2018, salesforce.com, inc.
63
- * All rights reserved.
64
- * SPDX-License-Identifier: MIT
65
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
66
- */
67
61
  const SECURE_REGISTER_TEMPLATE_METHOD_NAME = 'registerTemplate';
68
62
  const PARSE_FRAGMENT_METHOD_NAME = 'parseFragment';
69
63
  const PARSE_SVG_FRAGMENT_METHOD_NAME = 'parseSVGFragment';
@@ -86,6 +80,8 @@ const DASHED_TAGNAME_ELEMENT_SET = new Set([
86
80
  'font-face-name',
87
81
  'missing-glyph',
88
82
  ]);
83
+ // Subset of LWC template directives that can safely be statically optimized
84
+ const STATIC_SAFE_DIRECTIVES = new Set(['Ref']);
89
85
 
90
86
  /*
91
87
  * Copyright (c) 2018, salesforce.com, inc.
@@ -3799,8 +3795,12 @@ function isInIteratorElement(ctx) {
3799
3795
  return !!(getForOfParent(ctx) || getForEachParent(ctx));
3800
3796
  }
3801
3797
 
3802
- function checkElement(element, state) {
3803
- // Custom elements are not allowed to have a custom renderer hook.
3798
+ function shouldAddCustomRenderer(element, state) {
3799
+ // Elements of type `ExternalComponent` (e.g., elements with the lwc:external directive)
3800
+ if (state.crDirectives.has('lwc:external') && element.type === 'ExternalComponent') {
3801
+ return true;
3802
+ }
3803
+ // Elements of type `Component` are not allowed to have custom renderer hooks.
3804
3804
  // The renderer is cascaded down from the owner(custom element) to all its child nodes who
3805
3805
  // do not have a renderer specified.
3806
3806
  // lwc:component will resolve to a custom element at runtime.
@@ -3842,7 +3842,7 @@ function isCustomRendererHookRequired(element, state) {
3842
3842
  return cachedResult;
3843
3843
  }
3844
3844
  else {
3845
- addCustomRenderer = checkElement(element, state);
3845
+ addCustomRenderer = shouldAddCustomRenderer(element, state);
3846
3846
  state.crCheckedElements.set(element, addCustomRenderer);
3847
3847
  }
3848
3848
  }
@@ -3982,8 +3982,9 @@ function isStaticNode(node) {
3982
3982
  // TODO [#3313]: re-enable static optimization for SVGs once scope token is always lowercase
3983
3983
  return false;
3984
3984
  }
3985
+ // it is an element
3985
3986
  result && (result = isElement(node));
3986
- // it is an element.
3987
+ // all attrs are static-safe
3987
3988
  result && (result = attributes.every(({ name, value }) => {
3988
3989
  return (isLiteral(value) &&
3989
3990
  name !== 'slot' &&
@@ -3996,11 +3997,22 @@ function isStaticNode(node) {
3996
3997
  // Check for ScopedFragId
3997
3998
  !(isAllowedFragOnlyUrlsXHTML(nodeName, name, namespace) &&
3998
3999
  isFragmentOnlyUrl(value.value)));
3999
- })); // all attrs are static
4000
- result && (result = directives.length === 0); // do not have any directive
4001
- result && (result = properties.every((prop) => isLiteral(prop.value))); // all properties are static
4000
+ }));
4001
+ // all directives are static-safe
4002
+ result && (result = !directives.some((directive) => !STATIC_SAFE_DIRECTIVES.has(directive.name)));
4003
+ // all properties are static
4004
+ result && (result = properties.every((prop) => isLiteral(prop.value)));
4002
4005
  return result;
4003
4006
  }
4007
+ function isSafeStaticChild(childNode) {
4008
+ if (!isBaseElement(childNode)) {
4009
+ // don't need to check non-base-element nodes, because they don't have listeners/directives
4010
+ return true;
4011
+ }
4012
+ // Bail out if any children have event listeners or directives. These are only allowed at the top level of a
4013
+ // static fragment, because the engine currently cannot set listeners/refs/etc. on nodes inside a static fragment.
4014
+ return childNode.listeners.length === 0 && childNode.directives.length === 0;
4015
+ }
4004
4016
  function collectStaticNodes(node, staticNodes, state) {
4005
4017
  let childrenAreStatic = true;
4006
4018
  let nodeIsStatic;
@@ -4015,9 +4027,7 @@ function collectStaticNodes(node, staticNodes, state) {
4015
4027
  node.children.forEach((childNode) => {
4016
4028
  collectStaticNodes(childNode, staticNodes, state);
4017
4029
  childrenAreStatic && (childrenAreStatic = staticNodes.has(childNode));
4018
- // Bail out if any children have event listeners. Event listeners are only allowed at the top level of a
4019
- // static fragment, because the engine currently cannot attach listeners to nodes inside a static fragment.
4020
- childrenAreStatic && (childrenAreStatic = !isBaseElement(childNode) || childNode.listeners.length === 0);
4030
+ childrenAreStatic && (childrenAreStatic = isSafeStaticChild(childNode));
4021
4031
  });
4022
4032
  // for IfBlock and ElseifBlock, traverse down the else branch
4023
4033
  if (isConditionalParentBlock(node) && node.else) {
@@ -4464,11 +4474,16 @@ class CodeGen {
4464
4474
  }
4465
4475
  genEventListeners(listeners) {
4466
4476
  const listenerObj = Object.fromEntries(listeners.map((listener) => [listener.name, listener]));
4467
- return objectToAST(listenerObj, (key) => {
4477
+ const listenerObjectAST = objectToAST(listenerObj, (key) => {
4468
4478
  const componentHandler = this.bindExpression(listenerObj[key].handler);
4469
4479
  const handler = this.genBind(componentHandler);
4470
4480
  return memorizeHandler(this, componentHandler, handler);
4471
4481
  });
4482
+ return property$1(identifier('on'), listenerObjectAST);
4483
+ }
4484
+ genRef(ref) {
4485
+ this.hasRefs = true;
4486
+ return property$1(identifier('ref'), ref.value);
4472
4487
  }
4473
4488
  /**
4474
4489
  * This routine generates an expression that avoids
@@ -4569,7 +4584,7 @@ class CodeGen {
4569
4584
  });
4570
4585
  return expression;
4571
4586
  }
4572
- genHoistedElement(element, slotParentName) {
4587
+ genStaticElement(element, slotParentName) {
4573
4588
  const key = slotParentName !== undefined
4574
4589
  ? `@${slotParentName}:${this.generateKey()}`
4575
4590
  : this.generateKey();
@@ -4595,9 +4610,20 @@ class CodeGen {
4595
4610
  expr,
4596
4611
  });
4597
4612
  const args = [callExpression(identifier$1, []), literal$1(key)];
4598
- if (element.listeners.length) {
4599
- const listenerObjectAST = this.genEventListeners(element.listeners);
4600
- args.push(objectExpression([property$1(identifier('on'), listenerObjectAST)]));
4613
+ // Only add the third argument (databag) if this element needs it
4614
+ if (element.listeners.length || element.directives.length) {
4615
+ const databagProperties = [];
4616
+ // has event listeners
4617
+ if (element.listeners.length) {
4618
+ databagProperties.push(this.genEventListeners(element.listeners));
4619
+ }
4620
+ // see STATIC_SAFE_DIRECTIVES for what's allowed here
4621
+ for (const directive of element.directives) {
4622
+ if (directive.name === 'Ref') {
4623
+ databagProperties.push(this.genRef(directive));
4624
+ }
4625
+ }
4626
+ args.push(objectExpression(databagProperties));
4601
4627
  }
4602
4628
  return this._renderApiCall(RENDER_APIS.staticFragment, args);
4603
4629
  }
@@ -4792,7 +4818,7 @@ function transform(codeGen) {
4792
4818
  let res;
4793
4819
  if (codeGen.staticNodes.has(element) && isElement(element)) {
4794
4820
  // do not process children of static nodes.
4795
- return codeGen.genHoistedElement(element, slotParentName);
4821
+ return codeGen.genStaticElement(element, slotParentName);
4796
4822
  }
4797
4823
  const children = transformChildren(element);
4798
4824
  const { name } = element;
@@ -5186,8 +5212,7 @@ function transform(codeGen) {
5186
5212
  }
5187
5213
  // Properties: lwc:ref directive
5188
5214
  if (ref) {
5189
- data.push(property$1(identifier('ref'), ref.value));
5190
- codeGen.hasRefs = true;
5215
+ data.push(codeGen.genRef(ref));
5191
5216
  }
5192
5217
  if (propsObj.properties.length) {
5193
5218
  data.push(property$1(identifier('props'), propsObj));
@@ -5227,8 +5252,7 @@ function transform(codeGen) {
5227
5252
  }
5228
5253
  // Event handler
5229
5254
  if (listeners.length) {
5230
- const listenerObjAST = codeGen.genEventListeners(listeners);
5231
- data.push(property$1(identifier('on'), listenerObjAST));
5255
+ data.push(codeGen.genEventListeners(listeners));
5232
5256
  }
5233
5257
  // SVG handling
5234
5258
  if (element.namespace === shared.SVG_NAMESPACE) {
@@ -5327,5 +5351,5 @@ function compile(source, config) {
5327
5351
  exports.compile = compile;
5328
5352
  exports.default = compile;
5329
5353
  exports.parse = parse;
5330
- /** version: 2.47.0 */
5354
+ /** version: 2.49.0 */
5331
5355
  //# sourceMappingURL=index.cjs.js.map