@lwc/ssr-compiler 8.12.0 → 8.12.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.
@@ -1,4 +1,5 @@
1
+ import type { ComponentTransformOptions } from '../shared';
1
2
  import type { CompilationMode } from '@lwc/shared';
2
- export default function compileJS(src: string, filename: string, tagName: string, compilationMode: CompilationMode): {
3
+ export default function compileJS(src: string, filename: string, tagName: string, options: ComponentTransformOptions, compilationMode: CompilationMode): {
3
4
  code: string;
4
5
  };
@@ -1,3 +1,5 @@
1
+ import type { ImportManager } from '../imports';
2
+ import type { ComponentTransformOptions } from '../shared';
1
3
  import type { traverse } from 'estree-toolkit';
2
4
  import type { Identifier, MemberExpression, MethodDefinition, Node, ObjectExpression, PropertyDefinition } from 'estree';
3
5
  export type Visitors = Parameters<typeof traverse<Node, ComponentMetaState>>[1];
@@ -22,4 +24,6 @@ export interface ComponentMetaState {
22
24
  publicFields: Array<string>;
23
25
  privateFields: Array<string>;
24
26
  wireAdapters: WireAdapter[];
27
+ experimentalDynamicComponent: ComponentTransformOptions['experimentalDynamicComponent'];
28
+ importManager: ImportManager;
25
29
  }
@@ -1,6 +1,7 @@
1
1
  import type { TransformerContext } from './types';
2
2
  import type { Attribute as IrAttribute, Node as IrNode, Property as IrProperty } from '@lwc/template-compiler';
3
3
  import type { Expression as EsExpression, ObjectExpression as EsObjectExpression, Statement as EsStatement } from 'estree';
4
+ import type { ComplexExpression as IrComplexExpression, Expression as IrExpression, Literal as IrLiteral } from '@lwc/template-compiler';
4
5
  export declare function optimizeAdjacentYieldStmts(statements: EsStatement[]): EsStatement[];
5
6
  export declare function bAttributeValue(node: IrNode, attrName: string): EsExpression;
6
7
  /**
@@ -14,3 +15,8 @@ export declare function bAttributeValue(node: IrNode, attrName: string): EsExpre
14
15
  export declare function getScopedExpression(expression: EsExpression, cxt: TransformerContext): EsExpression;
15
16
  export declare function normalizeClassAttributeValue(value: string): string;
16
17
  export declare function getChildAttrsOrProps(attrs: (IrAttribute | IrProperty)[], cxt: TransformerContext): EsObjectExpression;
18
+ /**
19
+ * Determine if the provided node is of type Literal
20
+ * @param node
21
+ */
22
+ export declare function isLiteral(node: IrLiteral | IrExpression | IrComplexExpression): node is IrLiteral;
@@ -8,6 +8,7 @@ export interface TransformerContext {
8
8
  templateOptions: TemplateOpts;
9
9
  prevSibling?: IrNode;
10
10
  nextSibling?: IrNode;
11
+ isSlotted?: boolean;
11
12
  import: (imports: string | string[] | Record<string, string | undefined>, source?: string) => void;
12
13
  }
13
14
  export interface TemplateOpts {
@@ -0,0 +1,8 @@
1
+ import type { ImportDeclaration } from 'estree';
2
+ export declare class ImportManager {
3
+ #private;
4
+ /** Add an import to a collection of imports, probably for adding to the AST later. */
5
+ add(imports: string | string[] | Record<string, string | undefined>, source?: string): void;
6
+ /** Get the collection of imports for adding to the AST, probably soon! */
7
+ getImportDeclarations(): ImportDeclaration[];
8
+ }
package/dist/index.cjs.js CHANGED
@@ -165,6 +165,116 @@ function transmogrify(compiledComponentAst, mode = 'sync') {
165
165
  return immer.produce(compiledComponentAst, (astDraft) => estreeToolkit.traverse(astDraft, visitors$2, state));
166
166
  }
167
167
 
168
+ /******************************************************************************
169
+ Copyright (c) Microsoft Corporation.
170
+
171
+ Permission to use, copy, modify, and/or distribute this software for any
172
+ purpose with or without fee is hereby granted.
173
+
174
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
175
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
176
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
177
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
178
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
179
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
180
+ PERFORMANCE OF THIS SOFTWARE.
181
+ ***************************************************************************** */
182
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
183
+
184
+
185
+ function __classPrivateFieldGet(receiver, state, kind, f) {
186
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
187
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
188
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
189
+ }
190
+
191
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
192
+ var e = new Error(message);
193
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
194
+ };
195
+
196
+ /*
197
+ * Copyright (c) 2024, salesforce.com, inc.
198
+ * All rights reserved.
199
+ * SPDX-License-Identifier: MIT
200
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
201
+ */
202
+ /**
203
+ * Creates an import statement, e.g. `import { foo, bar as $bar$ } from "pkg"`
204
+ * @param imports names to be imported; values can be a string (plain import) or object (aliased)
205
+ * @param source source location to import from; defaults to @lwc/ssr-runtime
206
+ */
207
+ const bImportDeclaration = (imports, source = '@lwc/ssr-runtime') => {
208
+ let parsed;
209
+ if (typeof imports === 'string') {
210
+ parsed = [[imports, undefined]];
211
+ }
212
+ else if (Array.isArray(imports)) {
213
+ parsed = imports.map((imp) => [imp, undefined]);
214
+ }
215
+ else {
216
+ parsed = Object.entries(imports);
217
+ }
218
+ const specifiers = parsed.map(([imported, local]) => {
219
+ if (imported === 'default') {
220
+ return estreeToolkit.builders.importDefaultSpecifier(estreeToolkit.builders.identifier(local));
221
+ }
222
+ else if (imported === '*') {
223
+ return estreeToolkit.builders.importNamespaceSpecifier(estreeToolkit.builders.identifier(local));
224
+ }
225
+ else if (local) {
226
+ return estreeToolkit.builders.importSpecifier(estreeToolkit.builders.identifier(imported), estreeToolkit.builders.identifier(local));
227
+ }
228
+ else {
229
+ return estreeToolkit.builders.importSpecifier(estreeToolkit.builders.identifier(imported));
230
+ }
231
+ });
232
+ return estreeToolkit.builders.importDeclaration(specifiers, estreeToolkit.builders.literal(source));
233
+ };
234
+
235
+ /*
236
+ * Copyright (c) 2024, Salesforce, Inc.
237
+ * All rights reserved.
238
+ * SPDX-License-Identifier: MIT
239
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
240
+ */
241
+ var _ImportManager_map;
242
+ class ImportManager {
243
+ constructor() {
244
+ _ImportManager_map.set(this, new Map());
245
+ }
246
+ /** Add an import to a collection of imports, probably for adding to the AST later. */
247
+ add(imports, source = '@lwc/ssr-runtime') {
248
+ let specifiers;
249
+ if (typeof imports === 'string') {
250
+ specifiers = [[imports, undefined]];
251
+ }
252
+ else if (Array.isArray(imports)) {
253
+ specifiers = imports.map((name) => [name, undefined]);
254
+ }
255
+ else {
256
+ specifiers = Object.entries(imports);
257
+ }
258
+ let specifierMap = __classPrivateFieldGet(this, _ImportManager_map, "f").get(source);
259
+ if (specifierMap) {
260
+ for (const [imported, local] of specifiers) {
261
+ specifierMap.set(imported, local);
262
+ }
263
+ }
264
+ else {
265
+ specifierMap = new Map(specifiers);
266
+ __classPrivateFieldGet(this, _ImportManager_map, "f").set(source, specifierMap);
267
+ }
268
+ }
269
+ /** Get the collection of imports for adding to the AST, probably soon! */
270
+ getImportDeclarations() {
271
+ return Array.from(__classPrivateFieldGet(this, _ImportManager_map, "f"), ([source, specifierMap]) => {
272
+ return bImportDeclaration(Object.fromEntries(specifierMap), source);
273
+ });
274
+ }
275
+ }
276
+ _ImportManager_map = new WeakMap();
277
+
168
278
  /*
169
279
  * Copyright (c) 2024, salesforce.com, inc.
170
280
  * All rights reserved.
@@ -440,45 +550,6 @@ if (process.env.NODE_ENV !== 'production') {
440
550
  }
441
551
  }
442
552
 
443
- /*
444
- * Copyright (c) 2024, salesforce.com, inc.
445
- * All rights reserved.
446
- * SPDX-License-Identifier: MIT
447
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
448
- */
449
- /**
450
- * Creates an import statement, e.g. `import { foo, bar as $bar$ } from "pkg"`
451
- * @param imports names to be imported; values can be a string (plain import) or object (aliased)
452
- * @param source source location to import from; defaults to @lwc/ssr-runtime
453
- */
454
- const bImportDeclaration = (imports, source = '@lwc/ssr-runtime') => {
455
- let parsed;
456
- if (typeof imports === 'string') {
457
- parsed = [[imports, undefined]];
458
- }
459
- else if (Array.isArray(imports)) {
460
- parsed = imports.map((imp) => [imp, undefined]);
461
- }
462
- else {
463
- parsed = Object.entries(imports);
464
- }
465
- const specifiers = parsed.map(([imported, local]) => {
466
- if (imported === 'default') {
467
- return estreeToolkit.builders.importDefaultSpecifier(estreeToolkit.builders.identifier(local));
468
- }
469
- else if (imported === '*') {
470
- return estreeToolkit.builders.importNamespaceSpecifier(estreeToolkit.builders.identifier(local));
471
- }
472
- else if (local) {
473
- return estreeToolkit.builders.importSpecifier(estreeToolkit.builders.identifier(imported), estreeToolkit.builders.identifier(local));
474
- }
475
- else {
476
- return estreeToolkit.builders.importSpecifier(estreeToolkit.builders.identifier(imported));
477
- }
478
- });
479
- return estreeToolkit.builders.importDeclaration(specifiers, estreeToolkit.builders.literal(source));
480
- };
481
-
482
553
  /*
483
554
  * Copyright (c) 2024, salesforce.com, inc.
484
555
  * All rights reserved.
@@ -496,19 +567,23 @@ function bMemberExpressionChain(props) {
496
567
  function getWireParams(node) {
497
568
  const { decorators } = node;
498
569
  if (decorators.length > 1) {
570
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
499
571
  throw new Error('todo - multiple decorators at once');
500
572
  }
501
573
  // validate the parameters
502
574
  const wireDecorator = decorators[0].expression;
503
575
  if (!estreeToolkit.is.callExpression(wireDecorator)) {
576
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
504
577
  throw new Error('todo - invalid usage');
505
578
  }
506
579
  const args = wireDecorator.arguments;
507
580
  if (args.length === 0 || args.length > 2) {
581
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
508
582
  throw new Error('todo - wrong number of args');
509
583
  }
510
584
  const [id, config] = args;
511
585
  if (estreeToolkit.is.spreadElement(id) || estreeToolkit.is.spreadElement(config)) {
586
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
512
587
  throw new Error('todo - spread in params');
513
588
  }
514
589
  return [id, config];
@@ -518,14 +593,17 @@ function validateWireId(id, path) {
518
593
  let wireAdapterVar;
519
594
  if (estreeToolkit.is.memberExpression(id)) {
520
595
  if (id.computed) {
596
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
521
597
  throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_COMPUTED_PROPS');
522
598
  }
523
599
  if (!estreeToolkit.is.identifier(id.object)) {
600
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
524
601
  throw new Error('todo - FUNCTION_IDENTIFIER_CANNOT_HAVE_NESTED_MEMBER_EXRESSIONS');
525
602
  }
526
603
  wireAdapterVar = id.object.name;
527
604
  }
528
605
  else if (!estreeToolkit.is.identifier(id)) {
606
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
529
607
  throw new Error('todo - invalid adapter name');
530
608
  }
531
609
  else {
@@ -533,11 +611,13 @@ function validateWireId(id, path) {
533
611
  }
534
612
  // This is not the exact same validation done in @lwc/babel-plugin-component but it accomplishes the same thing
535
613
  if (path.scope?.getBinding(wireAdapterVar)?.kind !== 'module') {
614
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
536
615
  throw new Error('todo - WIRE_ADAPTER_SHOULD_BE_IMPORTED');
537
616
  }
538
617
  }
539
618
  function validateWireConfig(config, path) {
540
619
  if (!estreeToolkit.is.objectExpression(config)) {
620
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
541
621
  throw new Error('todo - CONFIG_OBJECT_SHOULD_BE_SECOND_PARAMETER');
542
622
  }
543
623
  for (const property of config.properties) {
@@ -560,6 +640,7 @@ function validateWireConfig(config, path) {
560
640
  if (estreeToolkit.is.templateLiteral(key)) {
561
641
  // A template literal is not guaranteed to always result in the same value
562
642
  // (e.g. `${Math.random()}`), so we disallow them entirely.
643
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
563
644
  throw new Error('todo - COMPUTED_PROPERTY_CANNOT_BE_TEMPLATE_LITERAL');
564
645
  }
565
646
  else if (!('regex' in key)) {
@@ -567,6 +648,7 @@ function validateWireConfig(config, path) {
567
648
  continue;
568
649
  }
569
650
  }
651
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
570
652
  throw new Error('todo - COMPUTED_PROPERTY_MUST_BE_CONSTANT_OR_LITERAL');
571
653
  }
572
654
  }
@@ -788,8 +870,28 @@ const visitors = {
788
870
  catalogAndReplaceStyleImports(path, state);
789
871
  removeDecoratorImport(path);
790
872
  },
791
- ImportExpression(path) {
792
- return path.replaceWith(estreeToolkit.builders.callExpression(estreeToolkit.builders.memberExpression(estreeToolkit.builders.identifier('Promise'), estreeToolkit.builders.identifier('resolve')), []));
873
+ ImportExpression(path, state) {
874
+ const { experimentalDynamicComponent, importManager } = state;
875
+ if (!experimentalDynamicComponent) {
876
+ // if no `experimentalDynamicComponent` config, then leave dynamic `import()`s as-is
877
+ return;
878
+ }
879
+ if (experimentalDynamicComponent.strictSpecifier) {
880
+ if (!estreeToolkit.is.literal(path.node?.source) || typeof path.node.source.value !== 'string') {
881
+ // TODO [#5032]: Harmonize errors thrown in `@lwc/ssr-compiler`
882
+ throw new Error('todo - LWCClassErrors.INVALID_DYNAMIC_IMPORT_SOURCE_STRICT');
883
+ }
884
+ }
885
+ const loader = experimentalDynamicComponent.loader;
886
+ if (!loader) {
887
+ // if no `loader` defined, then leave dynamic `import()`s as-is
888
+ return;
889
+ }
890
+ const source = path.node.source;
891
+ // 1. insert `import { load as __load } from '${loader}'` at top of program
892
+ importManager.add({ load: '__load' }, loader);
893
+ // 2. replace this import with `__load(${source})`
894
+ path.replaceWith(estreeToolkit.builders.callExpression(estreeToolkit.builders.identifier('__load'), [structuredClone(source)]));
793
895
  },
794
896
  ClassDeclaration(path, state) {
795
897
  const { node } = path;
@@ -902,8 +1004,17 @@ const visitors = {
902
1004
  path.parentPath.node.arguments = [estreeToolkit.builders.identifier('propsAvailableAtConstruction')];
903
1005
  }
904
1006
  },
1007
+ Program: {
1008
+ leave(path, state) {
1009
+ // After parsing the whole tree, insert needed imports
1010
+ const importDeclarations = state.importManager.getImportDeclarations();
1011
+ if (importDeclarations.length > 0) {
1012
+ path.node?.body.unshift(...importDeclarations);
1013
+ }
1014
+ },
1015
+ },
905
1016
  };
906
- function compileJS(src, filename, tagName, compilationMode) {
1017
+ function compileJS(src, filename, tagName, options, compilationMode) {
907
1018
  let ast = meriyah.parseModule(src, {
908
1019
  module: true,
909
1020
  next: true,
@@ -924,6 +1035,8 @@ function compileJS(src, filename, tagName, compilationMode) {
924
1035
  publicFields: [],
925
1036
  privateFields: [],
926
1037
  wireAdapters: [],
1038
+ experimentalDynamicComponent: options.experimentalDynamicComponent,
1039
+ importManager: new ImportManager(),
927
1040
  };
928
1041
  estreeToolkit.traverse(ast, visitors, state);
929
1042
  if (!state.isLWC) {
@@ -1138,6 +1251,13 @@ function getChildAttrsOrProps(attrs, cxt) {
1138
1251
  .filter(Boolean);
1139
1252
  return estreeToolkit.builders.objectExpression(objectAttrsOrProps);
1140
1253
  }
1254
+ /**
1255
+ * Determine if the provided node is of type Literal
1256
+ * @param node
1257
+ */
1258
+ function isLiteral(node) {
1259
+ return node.type === 'Literal';
1260
+ }
1141
1261
 
1142
1262
  /*
1143
1263
  * Copyright (c) 2024, Salesforce, Inc.
@@ -1327,6 +1447,8 @@ function getLightSlottedContent(rootNodes, cxt) {
1327
1447
  return results;
1328
1448
  }
1329
1449
  function getSlottedContent(node, cxt) {
1450
+ const { isSlotted } = cxt;
1451
+ cxt.isSlotted = true;
1330
1452
  // Anything inside the slotted content is a normal slotted content except for `<template lwc:slot-data>` which is a scoped slot.
1331
1453
  const slottableChildren = node.children.filter((child) => child.type !== 'ScopedSlotFragment');
1332
1454
  const scopedSlottableChildren = node.children.filter((child) => child.type === 'ScopedSlotFragment');
@@ -1336,13 +1458,17 @@ function getSlottedContent(node, cxt) {
1336
1458
  const boundVariableName = child.slotData.value.name;
1337
1459
  const boundVariable = estreeToolkit.builders.identifier(boundVariableName);
1338
1460
  cxt.pushLocalVars([boundVariableName]);
1461
+ const slotName = isLiteral(child.slotName)
1462
+ ? estreeToolkit.builders.literal(child.slotName.value)
1463
+ : expressionIrToEs(child.slotName, cxt);
1339
1464
  // TODO [#4768]: what if the bound variable is `generateMarkup` or some framework-specific identifier?
1340
- const addLightContentExpr = estreeToolkit.builders.expressionStatement(bAddLightContent(child.slotName, boundVariable, irChildrenToEs(child.children, cxt)));
1465
+ const addLightContentExpr = estreeToolkit.builders.expressionStatement(bAddLightContent(slotName, boundVariable, irChildrenToEs(child.children, cxt)));
1341
1466
  cxt.popLocalVars();
1342
1467
  return addLightContentExpr;
1343
1468
  });
1344
1469
  const hasShadowSlottedContent = estreeToolkit.builders.literal(shadowSlotContent.length > 0);
1345
1470
  const hasLightSlottedContent = estreeToolkit.builders.literal(lightSlotContent.length > 0 || scopedSlotContent.length > 0);
1471
+ cxt.isSlotted = isSlotted;
1346
1472
  return bGenerateSlottedContent(hasShadowSlottedContent, shadowSlotContent, hasLightSlottedContent, lightSlotContent, scopedSlotContent);
1347
1473
  }
1348
1474
 
@@ -1615,9 +1741,6 @@ const Element = function Element(node, cxt) {
1615
1741
  }
1616
1742
  return result;
1617
1743
  });
1618
- if (shared.isVoidElement(node.name, shared.HTML_NAMESPACE)) {
1619
- return [bYield(estreeToolkit.builders.literal(`<${node.name}`)), ...yieldAttrsAndProps, bYield(estreeToolkit.builders.literal(`>`))];
1620
- }
1621
1744
  let childContent;
1622
1745
  // An element can have children or lwc:inner-html, but not both
1623
1746
  // If it has both, the template compiler will throw an error before reaching here
@@ -1633,14 +1756,15 @@ const Element = function Element(node, cxt) {
1633
1756
  else {
1634
1757
  childContent = [];
1635
1758
  }
1759
+ const isForeignSelfClosingElement = node.namespace !== shared.HTML_NAMESPACE && childContent.length === 0;
1760
+ const isSelfClosingElement = shared.isVoidElement(node.name, shared.HTML_NAMESPACE) || isForeignSelfClosingElement;
1636
1761
  return [
1637
1762
  bYield(estreeToolkit.builders.literal(`<${node.name}`)),
1638
1763
  // If we haven't already prefixed the scope token to an existing class, add an explicit class here
1639
1764
  ...(hasClassAttribute ? [] : [bConditionallyYieldScopeTokenClass()]),
1640
1765
  ...yieldAttrsAndProps,
1641
- bYield(estreeToolkit.builders.literal(`>`)),
1642
- ...childContent,
1643
- bYield(estreeToolkit.builders.literal(`</${node.name}>`)),
1766
+ bYield(estreeToolkit.builders.literal(isForeignSelfClosingElement ? `/>` : `>`)),
1767
+ ...(isSelfClosingElement ? [] : [...childContent, bYield(estreeToolkit.builders.literal(`</${node.name}>`))]),
1644
1768
  ].filter(Boolean);
1645
1769
  };
1646
1770
 
@@ -1736,7 +1860,7 @@ function bIfStatement(ifElseIfNode, cxt) {
1736
1860
  elseBlock = bIfStatement(elseNode, cxt);
1737
1861
  }
1738
1862
  }
1739
- return estreeToolkit.builders.ifStatement(expressionIrToEs(condition, cxt), bBlockStatement(children, cxt, true), elseBlock);
1863
+ return estreeToolkit.builders.ifStatement(expressionIrToEs(condition, cxt), bBlockStatement(children, cxt, !cxt.isSlotted), elseBlock);
1740
1864
  }
1741
1865
  const IfBlock = function IfBlock(node, cxt) {
1742
1866
  return [bIfStatement(node, cxt)];
@@ -1751,12 +1875,15 @@ const IfBlock = function IfBlock(node, cxt) {
1751
1875
  const bConditionalSlot = (esTemplateWithYield `
1752
1876
  if (isLightDom) {
1753
1877
  const isScopedSlot = ${ /* isScopedSlot */estreeToolkit.is.literal};
1878
+ const isSlotted = ${ /* isSlotted */estreeToolkit.is.literal};
1754
1879
  // start bookend HTML comment for light DOM slot vfragment
1755
- yield '<!---->';
1756
-
1757
- // scoped slot factory has its own vfragment hence its own bookend
1758
- if (isScopedSlot) {
1880
+ if (!isSlotted) {
1759
1881
  yield '<!---->';
1882
+
1883
+ // scoped slot factory has its own vfragment hence its own bookend
1884
+ if (isScopedSlot) {
1885
+ yield '<!---->';
1886
+ }
1760
1887
  }
1761
1888
 
1762
1889
  const generators = lightSlottedContent?.[${ /* slotName */estreeToolkit.is.expression} ?? ""];
@@ -1772,14 +1899,16 @@ const bConditionalSlot = (esTemplateWithYield `
1772
1899
  // TODO: default/fallback slot content
1773
1900
  ${ /* slot fallback content */estreeToolkit.is.statement}
1774
1901
  }
1775
-
1776
- // scoped slot factory has its own vfragment hence its own bookend
1777
- if (isScopedSlot) {
1778
- yield '<!---->';
1779
- }
1780
1902
 
1781
1903
  // end bookend HTML comment for light DOM slot vfragment
1782
- yield '<!---->';
1904
+ if (!isSlotted) {
1905
+ yield '<!---->';
1906
+
1907
+ // scoped slot factory has its own vfragment hence its own bookend
1908
+ if (isScopedSlot) {
1909
+ yield '<!---->';
1910
+ }
1911
+ }
1783
1912
  } else {
1784
1913
  ${ /* slot element AST */estreeToolkit.is.statement}
1785
1914
  }
@@ -1794,7 +1923,8 @@ const Slot = function Slot(node, ctx) {
1794
1923
  const slotAst = Element(node, ctx);
1795
1924
  const slotChildren = irChildrenToEs(node.children, ctx);
1796
1925
  const isScopedSlot = estreeToolkit.builders.literal(Boolean(slotBound));
1797
- return [bConditionalSlot(isScopedSlot, slotName, slotBound, slotChildren, slotAst)];
1926
+ const isSlotted = estreeToolkit.builders.literal(Boolean(ctx.isSlotted));
1927
+ return [bConditionalSlot(isScopedSlot, isSlotted, slotName, slotBound, slotChildren, slotAst)];
1798
1928
  };
1799
1929
 
1800
1930
  /*
@@ -1807,9 +1937,6 @@ const bBufferTextContent = (esTemplateWithYield `
1807
1937
  didBufferTextContent = true;
1808
1938
  textContentBuffer += massageTextContent(${ /* string value */estreeToolkit.is.expression});
1809
1939
  `);
1810
- function isLiteral(node) {
1811
- return node.type === 'Literal';
1812
- }
1813
1940
  const Text = function Text(node, cxt) {
1814
1941
  cxt.import(['htmlEscape', 'massageTextContent']);
1815
1942
  const isLastInSeries = isLastConcatenatedNode(cxt);
@@ -1826,39 +1953,7 @@ const Text = function Text(node, cxt) {
1826
1953
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
1827
1954
  */
1828
1955
  function createNewContext(templateOptions) {
1829
- /** Map of source to imported name to local name. */
1830
- const importMap = new Map();
1831
- /**
1832
- * Hoist an import declaration to the top of the file. If source is not specified, defaults to
1833
- * `@lwc/ssr-runtime`.
1834
- */
1835
- const _import = (imports, source = '@lwc/ssr-runtime') => {
1836
- let specifiers;
1837
- if (typeof imports === 'string') {
1838
- specifiers = [[imports, undefined]];
1839
- }
1840
- else if (Array.isArray(imports)) {
1841
- specifiers = imports.map((name) => [name, undefined]);
1842
- }
1843
- else {
1844
- specifiers = Object.entries(imports);
1845
- }
1846
- let specifierMap = importMap.get(source);
1847
- if (specifierMap) {
1848
- for (const [imported, local] of specifiers) {
1849
- specifierMap.set(imported, local);
1850
- }
1851
- }
1852
- else {
1853
- specifierMap = new Map(specifiers);
1854
- importMap.set(source, specifierMap);
1855
- }
1856
- };
1857
- const getImports = () => {
1858
- return Array.from(importMap, ([source, specifierMap]) => {
1859
- return bImportDeclaration(Object.fromEntries(specifierMap), source);
1860
- });
1861
- };
1956
+ const importManager = new ImportManager();
1862
1957
  const localVarStack = [];
1863
1958
  const pushLocalVars = (vars) => {
1864
1959
  localVarStack.push(new Set(vars));
@@ -1878,13 +1973,13 @@ function createNewContext(templateOptions) {
1878
1973
  return false;
1879
1974
  };
1880
1975
  return {
1881
- getImports,
1976
+ getImports: () => importManager.getImportDeclarations(),
1882
1977
  cxt: {
1883
1978
  pushLocalVars,
1884
1979
  popLocalVars,
1885
1980
  isLocalVar,
1886
1981
  templateOptions,
1887
- import: _import,
1982
+ import: importManager.add.bind(importManager),
1888
1983
  },
1889
1984
  };
1890
1985
  }
@@ -2068,7 +2163,7 @@ function compileTemplate(src, filename, options, compilationMode) {
2068
2163
  */
2069
2164
  function compileComponentForSSR(src, filename, options, mode = shared.DEFAULT_SSR_MODE) {
2070
2165
  const tagName = shared.generateCustomElementTagName(options.namespace, options.name);
2071
- const { code } = compileJS(src, filename, tagName, mode);
2166
+ const { code } = compileJS(src, filename, tagName, options, mode);
2072
2167
  return { code, map: undefined };
2073
2168
  }
2074
2169
  function compileTemplateForSSR(src, filename, options, mode = shared.DEFAULT_SSR_MODE) {
@@ -2078,5 +2173,5 @@ function compileTemplateForSSR(src, filename, options, mode = shared.DEFAULT_SSR
2078
2173
 
2079
2174
  exports.compileComponentForSSR = compileComponentForSSR;
2080
2175
  exports.compileTemplateForSSR = compileTemplateForSSR;
2081
- /** version: 8.12.0 */
2176
+ /** version: 8.12.1 */
2082
2177
  //# sourceMappingURL=index.cjs.js.map