@lwc/template-compiler 2.48.0 → 2.49.1

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.
package/README.md CHANGED
@@ -54,7 +54,7 @@ const { code, warnings } = compile(`<template><h1>Hello World!</h1></template>`,
54
54
  - `enableDynamicComponents` (boolean, optional, `false` by default) - set to `true` to enable `lwc:is` directive in the template.
55
55
  - `preserveHtmlComments` (boolean, optional, `false` by default) - set to `true` to disable the default behavior of stripping HTML comments.
56
56
  - `enableStaticContentOptimization` (boolean, optional, `true` by default) - set to `false` to disable static content optimizations.
57
- - `enableLwcSpread` (boolean, optional, `false` by default) - set to `true` to enable `lwc:spread` directive in the template.
57
+ - `enableLwcSpread` (boolean, optional, `true` by default) - Deprecated. Ignored by template-compiler. `lwc:spread` is always enabled.
58
58
  - `customRendererConfig` (CustomRendererConfig, optional) - specifies a configuration to use to match elements. Matched elements will get a custom renderer hook in the generated template.
59
59
  - `instrumentation` (InstrumentationObject, optional) - instrumentation object to gather metrics and non-error logs for internal use. See the `@lwc/errors` package for details on the interface.
60
60
 
@@ -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/config.d.ts CHANGED
@@ -48,7 +48,7 @@ export interface Config {
48
48
  */
49
49
  enableStaticContentOptimization?: boolean;
50
50
  /**
51
- * When true, enables `lwc:spread` directive.
51
+ * @deprecated Spread operator is now always enabled.
52
52
  */
53
53
  enableLwcSpread?: boolean;
54
54
  /**
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.
@@ -186,7 +182,7 @@ function normalizeConfig(config) {
186
182
  }
187
183
  return Object.assign(Object.assign(Object.assign({ preserveHtmlComments: false, experimentalComputedMemberExpression: false,
188
184
  // TODO [#3370]: remove experimental template expression flag
189
- experimentalComplexExpressions: false, experimentalDynamicDirective: false, enableDynamicComponents: false, enableStaticContentOptimization: true, enableLwcSpread: false }, config), { customRendererConfig }), { instrumentation });
185
+ experimentalComplexExpressions: false, experimentalDynamicDirective: false, enableDynamicComponents: false, enableStaticContentOptimization: true, enableLwcSpread: true }, config), { customRendererConfig }), { instrumentation });
190
186
  }
191
187
 
192
188
  function isIdentifier(node) {
@@ -3190,9 +3186,6 @@ function applyLwcSpreadDirective(ctx, parsedAttr, element) {
3190
3186
  if (!lwcSpread) {
3191
3187
  return;
3192
3188
  }
3193
- if (!ctx.config.enableLwcSpread) {
3194
- ctx.throwOnNode(errors.ParserDiagnostics.INVALID_OPTS_LWC_SPREAD, element);
3195
- }
3196
3189
  const { value: lwcSpreadAttr } = lwcSpread;
3197
3190
  if (!isExpression$1(lwcSpreadAttr)) {
3198
3191
  ctx.throwOnNode(errors.ParserDiagnostics.INVALID_LWC_SPREAD_LITERAL_PROP, element, [`<${tag}>`]);
@@ -3799,8 +3792,12 @@ function isInIteratorElement(ctx) {
3799
3792
  return !!(getForOfParent(ctx) || getForEachParent(ctx));
3800
3793
  }
3801
3794
 
3802
- function checkElement(element, state) {
3803
- // Custom elements are not allowed to have a custom renderer hook.
3795
+ function shouldAddCustomRenderer(element, state) {
3796
+ // Elements of type `ExternalComponent` (e.g., elements with the lwc:external directive)
3797
+ if (state.crDirectives.has('lwc:external') && element.type === 'ExternalComponent') {
3798
+ return true;
3799
+ }
3800
+ // Elements of type `Component` are not allowed to have custom renderer hooks.
3804
3801
  // The renderer is cascaded down from the owner(custom element) to all its child nodes who
3805
3802
  // do not have a renderer specified.
3806
3803
  // lwc:component will resolve to a custom element at runtime.
@@ -3842,7 +3839,7 @@ function isCustomRendererHookRequired(element, state) {
3842
3839
  return cachedResult;
3843
3840
  }
3844
3841
  else {
3845
- addCustomRenderer = checkElement(element, state);
3842
+ addCustomRenderer = shouldAddCustomRenderer(element, state);
3846
3843
  state.crCheckedElements.set(element, addCustomRenderer);
3847
3844
  }
3848
3845
  }
@@ -3982,8 +3979,9 @@ function isStaticNode(node) {
3982
3979
  // TODO [#3313]: re-enable static optimization for SVGs once scope token is always lowercase
3983
3980
  return false;
3984
3981
  }
3982
+ // it is an element
3985
3983
  result && (result = isElement(node));
3986
- // it is an element.
3984
+ // all attrs are static-safe
3987
3985
  result && (result = attributes.every(({ name, value }) => {
3988
3986
  return (isLiteral(value) &&
3989
3987
  name !== 'slot' &&
@@ -3996,11 +3994,22 @@ function isStaticNode(node) {
3996
3994
  // Check for ScopedFragId
3997
3995
  !(isAllowedFragOnlyUrlsXHTML(nodeName, name, namespace) &&
3998
3996
  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
3997
+ }));
3998
+ // all directives are static-safe
3999
+ result && (result = !directives.some((directive) => !STATIC_SAFE_DIRECTIVES.has(directive.name)));
4000
+ // all properties are static
4001
+ result && (result = properties.every((prop) => isLiteral(prop.value)));
4002
4002
  return result;
4003
4003
  }
4004
+ function isSafeStaticChild(childNode) {
4005
+ if (!isBaseElement(childNode)) {
4006
+ // don't need to check non-base-element nodes, because they don't have listeners/directives
4007
+ return true;
4008
+ }
4009
+ // Bail out if any children have event listeners or directives. These are only allowed at the top level of a
4010
+ // static fragment, because the engine currently cannot set listeners/refs/etc. on nodes inside a static fragment.
4011
+ return childNode.listeners.length === 0 && childNode.directives.length === 0;
4012
+ }
4004
4013
  function collectStaticNodes(node, staticNodes, state) {
4005
4014
  let childrenAreStatic = true;
4006
4015
  let nodeIsStatic;
@@ -4015,9 +4024,7 @@ function collectStaticNodes(node, staticNodes, state) {
4015
4024
  node.children.forEach((childNode) => {
4016
4025
  collectStaticNodes(childNode, staticNodes, state);
4017
4026
  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);
4027
+ childrenAreStatic && (childrenAreStatic = isSafeStaticChild(childNode));
4021
4028
  });
4022
4029
  // for IfBlock and ElseifBlock, traverse down the else branch
4023
4030
  if (isConditionalParentBlock(node) && node.else) {
@@ -4464,11 +4471,16 @@ class CodeGen {
4464
4471
  }
4465
4472
  genEventListeners(listeners) {
4466
4473
  const listenerObj = Object.fromEntries(listeners.map((listener) => [listener.name, listener]));
4467
- return objectToAST(listenerObj, (key) => {
4474
+ const listenerObjectAST = objectToAST(listenerObj, (key) => {
4468
4475
  const componentHandler = this.bindExpression(listenerObj[key].handler);
4469
4476
  const handler = this.genBind(componentHandler);
4470
4477
  return memorizeHandler(this, componentHandler, handler);
4471
4478
  });
4479
+ return property$1(identifier('on'), listenerObjectAST);
4480
+ }
4481
+ genRef(ref) {
4482
+ this.hasRefs = true;
4483
+ return property$1(identifier('ref'), ref.value);
4472
4484
  }
4473
4485
  /**
4474
4486
  * This routine generates an expression that avoids
@@ -4569,7 +4581,7 @@ class CodeGen {
4569
4581
  });
4570
4582
  return expression;
4571
4583
  }
4572
- genHoistedElement(element, slotParentName) {
4584
+ genStaticElement(element, slotParentName) {
4573
4585
  const key = slotParentName !== undefined
4574
4586
  ? `@${slotParentName}:${this.generateKey()}`
4575
4587
  : this.generateKey();
@@ -4595,9 +4607,20 @@ class CodeGen {
4595
4607
  expr,
4596
4608
  });
4597
4609
  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)]));
4610
+ // Only add the third argument (databag) if this element needs it
4611
+ if (element.listeners.length || element.directives.length) {
4612
+ const databagProperties = [];
4613
+ // has event listeners
4614
+ if (element.listeners.length) {
4615
+ databagProperties.push(this.genEventListeners(element.listeners));
4616
+ }
4617
+ // see STATIC_SAFE_DIRECTIVES for what's allowed here
4618
+ for (const directive of element.directives) {
4619
+ if (directive.name === 'Ref') {
4620
+ databagProperties.push(this.genRef(directive));
4621
+ }
4622
+ }
4623
+ args.push(objectExpression(databagProperties));
4601
4624
  }
4602
4625
  return this._renderApiCall(RENDER_APIS.staticFragment, args);
4603
4626
  }
@@ -4792,7 +4815,7 @@ function transform(codeGen) {
4792
4815
  let res;
4793
4816
  if (codeGen.staticNodes.has(element) && isElement(element)) {
4794
4817
  // do not process children of static nodes.
4795
- return codeGen.genHoistedElement(element, slotParentName);
4818
+ return codeGen.genStaticElement(element, slotParentName);
4796
4819
  }
4797
4820
  const children = transformChildren(element);
4798
4821
  const { name } = element;
@@ -5186,8 +5209,7 @@ function transform(codeGen) {
5186
5209
  }
5187
5210
  // Properties: lwc:ref directive
5188
5211
  if (ref) {
5189
- data.push(property$1(identifier('ref'), ref.value));
5190
- codeGen.hasRefs = true;
5212
+ data.push(codeGen.genRef(ref));
5191
5213
  }
5192
5214
  if (propsObj.properties.length) {
5193
5215
  data.push(property$1(identifier('props'), propsObj));
@@ -5227,8 +5249,7 @@ function transform(codeGen) {
5227
5249
  }
5228
5250
  // Event handler
5229
5251
  if (listeners.length) {
5230
- const listenerObjAST = codeGen.genEventListeners(listeners);
5231
- data.push(property$1(identifier('on'), listenerObjAST));
5252
+ data.push(codeGen.genEventListeners(listeners));
5232
5253
  }
5233
5254
  // SVG handling
5234
5255
  if (element.namespace === shared.SVG_NAMESPACE) {
@@ -5327,5 +5348,5 @@ function compile(source, config) {
5327
5348
  exports.compile = compile;
5328
5349
  exports.default = compile;
5329
5350
  exports.parse = parse;
5330
- /** version: 2.48.0 */
5351
+ /** version: 2.49.1 */
5331
5352
  //# sourceMappingURL=index.cjs.js.map