@lwc/template-compiler 2.45.5 → 2.46.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.
package/README.md CHANGED
@@ -56,6 +56,7 @@ const { code, warnings } = compile(`<template><h1>Hello World!</h1></template>`,
56
56
  - `enableStaticContentOptimization` (boolean, optional, `true` by default) - set to `false` to disable static content optimizations.
57
57
  - `enableLwcSpread` (boolean, optional, `false` by default) - set to `true` to enable `lwc:spread` directive in the template.
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
+ - `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.
59
60
 
60
61
  - Example 1: Config to match `<use>` elements under the `svg` namespace and have `href` attribute set.
61
62
 
@@ -1,5 +1,5 @@
1
1
  import * as t from '../shared/estree';
2
- import { ChildNode, Element, Expression, ComplexExpression, Literal, LWCDirectiveRenderMode, Root } from '../shared/types';
2
+ import { ChildNode, Element, Expression, ComplexExpression, Literal, LWCDirectiveRenderMode, Root, EventListener } from '../shared/types';
3
3
  import State from '../state';
4
4
  export default class CodeGen {
5
5
  /** The AST root. */
@@ -76,6 +76,7 @@ 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
80
  /**
80
81
  * This routine generates an expression that avoids
81
82
  * computing the sanitized html of a raw html if it does not change
package/dist/config.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { InstrumentationObject } from '@lwc/errors';
1
2
  import { CustomRendererConfig } from './shared/renderer-hooks';
2
3
  export interface Config {
3
4
  /**
@@ -50,6 +51,10 @@ export interface Config {
50
51
  * When true, enables `lwc:spread` directive.
51
52
  */
52
53
  enableLwcSpread?: boolean;
54
+ /**
55
+ * Config to use to collect metrics and logs
56
+ */
57
+ instrumentation?: InstrumentationObject;
53
58
  }
54
- export type NormalizedConfig = Required<Omit<Config, 'customRendererConfig'>> & Partial<Pick<Config, 'customRendererConfig'>>;
59
+ export type NormalizedConfig = Required<Omit<Config, 'customRendererConfig' | 'instrumentation'>> & Partial<Pick<Config, 'customRendererConfig' | 'instrumentation'>>;
55
60
  export declare function normalizeConfig(config: Config): NormalizedConfig;
package/dist/index.cjs.js CHANGED
@@ -141,6 +141,7 @@ const AVAILABLE_OPTION_NAMES = new Set([
141
141
  'experimentalDynamicDirective',
142
142
  'enableDynamicComponents',
143
143
  'preserveHtmlComments',
144
+ 'instrumentation',
144
145
  ]);
145
146
  function normalizeCustomRendererConfig(config) {
146
147
  const tagNames = [];
@@ -175,6 +176,7 @@ function normalizeConfig(config) {
175
176
  const customRendererConfig = config.customRendererConfig
176
177
  ? normalizeCustomRendererConfig(config.customRendererConfig)
177
178
  : undefined;
179
+ const instrumentation = config.instrumentation || undefined;
178
180
  for (const property in config) {
179
181
  if (!AVAILABLE_OPTION_NAMES.has(property) && shared.hasOwnProperty.call(config, property)) {
180
182
  throw errors.generateCompilerError(errors.TemplateErrors.UNKNOWN_OPTION_PROPERTY, {
@@ -182,9 +184,9 @@ function normalizeConfig(config) {
182
184
  });
183
185
  }
184
186
  }
185
- return Object.assign(Object.assign({ preserveHtmlComments: false, experimentalComputedMemberExpression: false,
187
+ return Object.assign(Object.assign(Object.assign({ preserveHtmlComments: false, experimentalComputedMemberExpression: false,
186
188
  // TODO [#3370]: remove experimental template expression flag
187
- experimentalComplexExpressions: false, experimentalDynamicDirective: false, enableDynamicComponents: false, enableStaticContentOptimization: true, enableLwcSpread: false }, config), { customRendererConfig });
189
+ experimentalComplexExpressions: false, experimentalDynamicDirective: false, enableDynamicComponents: false, enableStaticContentOptimization: true, enableLwcSpread: false }, config), { customRendererConfig }), { instrumentation });
188
190
  }
189
191
 
190
192
  function isIdentifier(node) {
@@ -1589,6 +1591,7 @@ class ParserCtx {
1589
1591
  this.ecmaVersion = config.experimentalComplexExpressions
1590
1592
  ? TMPL_EXPR_ECMASCRIPT_EDITION
1591
1593
  : 2020;
1594
+ this.instrumentation = config.instrumentation;
1592
1595
  }
1593
1596
  getSource(start, end) {
1594
1597
  return this.source.slice(start, end);
@@ -3098,6 +3101,7 @@ function applyRootLwcDirectives(ctx, parsedAttr, root) {
3098
3101
  applyLwcPreserveCommentsDirective(ctx, parsedAttr, root);
3099
3102
  }
3100
3103
  function applyLwcRenderModeDirective(ctx, parsedAttr, root) {
3104
+ var _a;
3101
3105
  const lwcRenderModeAttribute = parsedAttr.pick(exports.RootDirectiveName.RenderMode);
3102
3106
  if (!lwcRenderModeAttribute) {
3103
3107
  return;
@@ -3109,6 +3113,7 @@ function applyLwcRenderModeDirective(ctx, parsedAttr, root) {
3109
3113
  ctx.throwOnNode(errors.ParserDiagnostics.LWC_RENDER_MODE_INVALID_VALUE, root);
3110
3114
  }
3111
3115
  root.directives.push(renderModeDirective(renderDomAttr.value, lwcRenderModeAttribute.location));
3116
+ (_a = ctx.instrumentation) === null || _a === void 0 ? void 0 : _a.incrementCounter(errors.CompilerMetrics.LWCRenderModeDirective);
3112
3117
  }
3113
3118
  function applyLwcPreserveCommentsDirective(ctx, parsedAttr, root) {
3114
3119
  const lwcPreserveCommentAttribute = parsedAttr.pick(exports.RootDirectiveName.PreserveComments);
@@ -3211,6 +3216,7 @@ function applyLwcExternalDirective(ctx, parsedAttr, element) {
3211
3216
  }
3212
3217
  }
3213
3218
  function applyLwcDynamicDirective(ctx, parsedAttr, element) {
3219
+ var _a;
3214
3220
  const { name: tag } = element;
3215
3221
  const lwcDynamicAttribute = parsedAttr.pick(exports.ElementDirectiveName.Dynamic);
3216
3222
  if (!lwcDynamicAttribute) {
@@ -3230,6 +3236,7 @@ function applyLwcDynamicDirective(ctx, parsedAttr, element) {
3230
3236
  }
3231
3237
  // lwc:dynamic will be deprecated in 246, issue a warning when usage is detected.
3232
3238
  ctx.warnOnNode(errors.ParserDiagnostics.DEPRECATED_LWC_DYNAMIC_ATTRIBUTE, element);
3239
+ (_a = ctx.instrumentation) === null || _a === void 0 ? void 0 : _a.incrementCounter(errors.CompilerMetrics.LWCDynamicDirective);
3233
3240
  element.directives.push(dynamicDirective(lwcDynamicAttr, location));
3234
3241
  }
3235
3242
  function applyLwcIsDirective(ctx, parsedAttr, element) {
@@ -3970,7 +3977,7 @@ function parseClassNames(classNames) {
3970
3977
  }
3971
3978
  function isStaticNode(node) {
3972
3979
  let result = true;
3973
- const { name: nodeName, namespace = '', attributes, directives, properties, listeners } = node;
3980
+ const { name: nodeName, namespace = '', attributes, directives, properties } = node;
3974
3981
  if (namespace !== shared.HTML_NAMESPACE) {
3975
3982
  // TODO [#3313]: re-enable static optimization for SVGs once scope token is always lowercase
3976
3983
  return false;
@@ -3992,7 +3999,6 @@ function isStaticNode(node) {
3992
3999
  })); // all attrs are static
3993
4000
  result && (result = directives.length === 0); // do not have any directive
3994
4001
  result && (result = properties.every((prop) => isLiteral(prop.value))); // all properties are static
3995
- result && (result = listeners.length === 0); // do not have any event listener
3996
4002
  return result;
3997
4003
  }
3998
4004
  function collectStaticNodes(node, staticNodes, state) {
@@ -4008,7 +4014,10 @@ function collectStaticNodes(node, staticNodes, state) {
4008
4014
  // it is ElseBlock | ForBlock | If | BaseElement
4009
4015
  node.children.forEach((childNode) => {
4010
4016
  collectStaticNodes(childNode, staticNodes, state);
4011
- childrenAreStatic = childrenAreStatic && staticNodes.has(childNode);
4017
+ 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);
4012
4021
  });
4013
4022
  // for IfBlock and ElseifBlock, traverse down the else branch
4014
4023
  if (isConditionalParentBlock(node) && node.else) {
@@ -4453,6 +4462,14 @@ class CodeGen {
4453
4462
  genBooleanAttributeExpr(bindExpr) {
4454
4463
  return conditionalExpression(bindExpr, literal$1(''), literal$1(null));
4455
4464
  }
4465
+ genEventListeners(listeners) {
4466
+ const listenerObj = Object.fromEntries(listeners.map((listener) => [listener.name, listener]));
4467
+ return objectToAST(listenerObj, (key) => {
4468
+ const componentHandler = this.bindExpression(listenerObj[key].handler);
4469
+ const handler = this.genBind(componentHandler);
4470
+ return memorizeHandler(this, componentHandler, handler);
4471
+ });
4472
+ }
4456
4473
  /**
4457
4474
  * This routine generates an expression that avoids
4458
4475
  * computing the sanitized html of a raw html if it does not change
@@ -4577,10 +4594,12 @@ class CodeGen {
4577
4594
  identifier: identifier$1,
4578
4595
  expr,
4579
4596
  });
4580
- return this._renderApiCall(RENDER_APIS.staticFragment, [
4581
- callExpression(identifier$1, []),
4582
- literal$1(key),
4583
- ]);
4597
+ 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)]));
4601
+ }
4602
+ return this._renderApiCall(RENDER_APIS.staticFragment, args);
4584
4603
  }
4585
4604
  }
4586
4605
 
@@ -4767,6 +4786,7 @@ function format(templateFn, codeGen) {
4767
4786
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
4768
4787
  */
4769
4788
  function transform(codeGen) {
4789
+ const instrumentation = codeGen.state.config.instrumentation;
4770
4790
  function transformElement(element, slotParentName) {
4771
4791
  const databag = elementDataBag(element, slotParentName);
4772
4792
  let res;
@@ -5179,8 +5199,10 @@ function transform(codeGen) {
5179
5199
  ]);
5180
5200
  data.push(property$1(identifier('context'), contextObj));
5181
5201
  }
5202
+ // Spread
5182
5203
  if (spread) {
5183
5204
  data.push(property$1(identifier('spread'), codeGen.bindExpression(spread.value)));
5205
+ instrumentation === null || instrumentation === void 0 ? void 0 : instrumentation.incrementCounter(errors.CompilerMetrics.LWCSpreadDirective);
5184
5206
  }
5185
5207
  // Key property on VNode
5186
5208
  if (forKey) {
@@ -5205,12 +5227,7 @@ function transform(codeGen) {
5205
5227
  }
5206
5228
  // Event handler
5207
5229
  if (listeners.length) {
5208
- const listenerObj = Object.fromEntries(listeners.map((listener) => [listener.name, listener]));
5209
- const listenerObjAST = objectToAST(listenerObj, (key) => {
5210
- const componentHandler = codeGen.bindExpression(listenerObj[key].handler);
5211
- const handler = codeGen.genBind(componentHandler);
5212
- return memorizeHandler(codeGen, componentHandler, handler);
5213
- });
5230
+ const listenerObjAST = codeGen.genEventListeners(listeners);
5214
5231
  data.push(property$1(identifier('on'), listenerObjAST));
5215
5232
  }
5216
5233
  // SVG handling
@@ -5310,5 +5327,5 @@ function compile(source, config) {
5310
5327
  exports.compile = compile;
5311
5328
  exports.default = compile;
5312
5329
  exports.parse = parse;
5313
- /** version: 2.45.5 */
5330
+ /** version: 2.46.0 */
5314
5331
  //# sourceMappingURL=index.cjs.js.map