@lwc/ssr-runtime 8.15.1 → 8.16.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/dist/index.cjs.js CHANGED
@@ -11,6 +11,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
11
11
  * SPDX-License-Identifier: MIT
12
12
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
13
13
  */
14
+ /* v8 ignore start */
14
15
  // Stubs for all the un-implemented exports from @lwc/engine-server
15
16
  function api(..._) {
16
17
  throw new Error('@api cannot be used in SSR context.');
@@ -219,6 +220,7 @@ const renderer = {
219
220
  */
220
221
  // A real stub, not a "not implemented" one! 😯
221
222
  const hot = undefined;
223
+ /* v8 ignore stop */
222
224
 
223
225
  /**
224
226
  * Copyright (c) 2025 Salesforce, Inc.
@@ -625,7 +627,7 @@ function normalizeTabIndex(value) {
625
627
  const shouldNormalize = value > 0 && typeof value !== 'boolean';
626
628
  return shouldNormalize ? 0 : value;
627
629
  }
628
- /** version: 8.15.1 */
630
+ /** version: 8.16.1 */
629
631
 
630
632
  /*
631
633
  * Copyright (c) 2024, Salesforce, Inc.
@@ -1564,7 +1566,15 @@ function fallbackTmplNoYield(emit, shadowSlottedContent, _lightSlottedContent, _
1564
1566
  }
1565
1567
  }
1566
1568
  }
1567
- async function serverSideRenderComponent(tagName, Component, props = {}, mode = DEFAULT_SSR_MODE) {
1569
+ class RenderContext {
1570
+ constructor(styleDedupePrefix, styleDedupeIsEnabled) {
1571
+ this.stylesheetToId = new WeakMap();
1572
+ this.nextId = 0;
1573
+ this.styleDedupeIsEnabled = styleDedupeIsEnabled;
1574
+ this.styleDedupePrefix = styleDedupePrefix;
1575
+ }
1576
+ }
1577
+ async function serverSideRenderComponent(tagName, Component, props = {}, styleDedupePrefix = '', styleDedupeIsEnabled = false, mode = DEFAULT_SSR_MODE) {
1568
1578
  if (typeof tagName !== 'string') {
1569
1579
  throw new Error(`tagName must be a string, found: ${tagName}`);
1570
1580
  }
@@ -1573,6 +1583,7 @@ async function serverSideRenderComponent(tagName, Component, props = {}, mode =
1573
1583
  const emit = (segment) => {
1574
1584
  markup += segment;
1575
1585
  };
1586
+ emit.cxt = new RenderContext(styleDedupePrefix, styleDedupeIsEnabled);
1576
1587
  if (!generateMarkup) {
1577
1588
  // If a non-component is accidentally provided, render an empty template
1578
1589
  emit(`<${tagName}>`);
@@ -1700,7 +1711,11 @@ function hasScopedStaticStylesheets(Component) {
1700
1711
  });
1701
1712
  return scoped;
1702
1713
  }
1703
- function renderStylesheets(defaultStylesheets, defaultScopedStylesheets, staticStylesheets, scopeToken, Component, hasScopedTemplateStyles) {
1714
+ function renderStylesheets(
1715
+ // FIXME: the `emit` function does not exist in the SSR's compiler's yield mode. If we
1716
+ // are going to use it to transport the RenderContext down the call stack, we'll need to figure out
1717
+ // how to make htat work in yield mode.
1718
+ emit, defaultStylesheets, defaultScopedStylesheets, staticStylesheets, scopeToken, Component, hasScopedTemplateStyles) {
1704
1719
  const hasAnyScopedStyles = hasScopedTemplateStyles || hasScopedStaticStylesheets(Component);
1705
1720
  const { renderMode } = Component;
1706
1721
  let result = '';
@@ -1709,10 +1724,25 @@ function renderStylesheets(defaultStylesheets, defaultScopedStylesheets, staticS
1709
1724
  const token = scoped ? scopeToken : undefined;
1710
1725
  const useActualHostSelector = !scoped || renderMode !== 'light';
1711
1726
  const useNativeDirPseudoclass = true;
1712
- const styleContents = stylesheet(token, useActualHostSelector, useNativeDirPseudoclass);
1713
- validateStyleTextContents(styleContents);
1714
- // TODO [#2869]: `<style>`s should not have scope token classes
1715
- result += `<style${hasAnyScopedStyles ? ` class="${scopeToken}"` : ''} type="text/css">${styleContents}</style>`;
1727
+ const { styleDedupeIsEnabled, stylesheetToId, styleDedupePrefix } = emit.cxt;
1728
+ if (!styleDedupeIsEnabled) {
1729
+ const styleContents = stylesheet(token, useActualHostSelector, useNativeDirPseudoclass);
1730
+ validateStyleTextContents(styleContents);
1731
+ result += `<style${hasAnyScopedStyles ? ` class="${scopeToken}"` : ''} type="text/css">${styleContents}</style>`;
1732
+ }
1733
+ else if (stylesheetToId.has(stylesheet)) {
1734
+ const styleId = stylesheetToId.get(stylesheet);
1735
+ result += `<lwc-style style-id="lwc-style-${styleDedupePrefix}-${styleId}"></lwc-style>`;
1736
+ }
1737
+ else {
1738
+ const styleId = emit.cxt.nextId++;
1739
+ stylesheetToId.set(stylesheet, styleId.toString());
1740
+ const styleContents = stylesheet(token, useActualHostSelector, useNativeDirPseudoclass);
1741
+ validateStyleTextContents(styleContents);
1742
+ // TODO [#2869]: `<style>`s should not have scope token classes
1743
+ result += `<style${hasAnyScopedStyles ? ` class="${scopeToken}"` : ''} id="lwc-style-${styleDedupePrefix}-${styleId}" type="text/css">${styleContents}</style>`;
1744
+ result += `<lwc-style style-id="lwc-style-${styleDedupePrefix}-${styleId}"></lwc-style>`;
1745
+ }
1716
1746
  };
1717
1747
  traverseStylesheets(defaultStylesheets, renderStylesheet);
1718
1748
  traverseStylesheets(defaultScopedStylesheets, renderStylesheet);
@@ -1861,5 +1891,5 @@ exports.track = track;
1861
1891
  exports.unwrap = unwrap$1;
1862
1892
  exports.validateStyleTextContents = validateStyleTextContents;
1863
1893
  exports.wire = wire;
1864
- /** version: 8.15.1 */
1894
+ /** version: 8.16.1 */
1865
1895
  //# sourceMappingURL=index.cjs.js.map
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
9
9
  */
10
+ /* v8 ignore start */
10
11
  // Stubs for all the un-implemented exports from @lwc/engine-server
11
12
  function api(..._) {
12
13
  throw new Error('@api cannot be used in SSR context.');
@@ -215,6 +216,7 @@ const renderer = {
215
216
  */
216
217
  // A real stub, not a "not implemented" one! 😯
217
218
  const hot = undefined;
219
+ /* v8 ignore stop */
218
220
 
219
221
  /**
220
222
  * Copyright (c) 2025 Salesforce, Inc.
@@ -621,7 +623,7 @@ function normalizeTabIndex(value) {
621
623
  const shouldNormalize = value > 0 && typeof value !== 'boolean';
622
624
  return shouldNormalize ? 0 : value;
623
625
  }
624
- /** version: 8.15.1 */
626
+ /** version: 8.16.1 */
625
627
 
626
628
  /*
627
629
  * Copyright (c) 2024, Salesforce, Inc.
@@ -1560,7 +1562,15 @@ function fallbackTmplNoYield(emit, shadowSlottedContent, _lightSlottedContent, _
1560
1562
  }
1561
1563
  }
1562
1564
  }
1563
- async function serverSideRenderComponent(tagName, Component, props = {}, mode = DEFAULT_SSR_MODE) {
1565
+ class RenderContext {
1566
+ constructor(styleDedupePrefix, styleDedupeIsEnabled) {
1567
+ this.stylesheetToId = new WeakMap();
1568
+ this.nextId = 0;
1569
+ this.styleDedupeIsEnabled = styleDedupeIsEnabled;
1570
+ this.styleDedupePrefix = styleDedupePrefix;
1571
+ }
1572
+ }
1573
+ async function serverSideRenderComponent(tagName, Component, props = {}, styleDedupePrefix = '', styleDedupeIsEnabled = false, mode = DEFAULT_SSR_MODE) {
1564
1574
  if (typeof tagName !== 'string') {
1565
1575
  throw new Error(`tagName must be a string, found: ${tagName}`);
1566
1576
  }
@@ -1569,6 +1579,7 @@ async function serverSideRenderComponent(tagName, Component, props = {}, mode =
1569
1579
  const emit = (segment) => {
1570
1580
  markup += segment;
1571
1581
  };
1582
+ emit.cxt = new RenderContext(styleDedupePrefix, styleDedupeIsEnabled);
1572
1583
  if (!generateMarkup) {
1573
1584
  // If a non-component is accidentally provided, render an empty template
1574
1585
  emit(`<${tagName}>`);
@@ -1696,7 +1707,11 @@ function hasScopedStaticStylesheets(Component) {
1696
1707
  });
1697
1708
  return scoped;
1698
1709
  }
1699
- function renderStylesheets(defaultStylesheets, defaultScopedStylesheets, staticStylesheets, scopeToken, Component, hasScopedTemplateStyles) {
1710
+ function renderStylesheets(
1711
+ // FIXME: the `emit` function does not exist in the SSR's compiler's yield mode. If we
1712
+ // are going to use it to transport the RenderContext down the call stack, we'll need to figure out
1713
+ // how to make htat work in yield mode.
1714
+ emit, defaultStylesheets, defaultScopedStylesheets, staticStylesheets, scopeToken, Component, hasScopedTemplateStyles) {
1700
1715
  const hasAnyScopedStyles = hasScopedTemplateStyles || hasScopedStaticStylesheets(Component);
1701
1716
  const { renderMode } = Component;
1702
1717
  let result = '';
@@ -1705,10 +1720,25 @@ function renderStylesheets(defaultStylesheets, defaultScopedStylesheets, staticS
1705
1720
  const token = scoped ? scopeToken : undefined;
1706
1721
  const useActualHostSelector = !scoped || renderMode !== 'light';
1707
1722
  const useNativeDirPseudoclass = true;
1708
- const styleContents = stylesheet(token, useActualHostSelector, useNativeDirPseudoclass);
1709
- validateStyleTextContents(styleContents);
1710
- // TODO [#2869]: `<style>`s should not have scope token classes
1711
- result += `<style${hasAnyScopedStyles ? ` class="${scopeToken}"` : ''} type="text/css">${styleContents}</style>`;
1723
+ const { styleDedupeIsEnabled, stylesheetToId, styleDedupePrefix } = emit.cxt;
1724
+ if (!styleDedupeIsEnabled) {
1725
+ const styleContents = stylesheet(token, useActualHostSelector, useNativeDirPseudoclass);
1726
+ validateStyleTextContents(styleContents);
1727
+ result += `<style${hasAnyScopedStyles ? ` class="${scopeToken}"` : ''} type="text/css">${styleContents}</style>`;
1728
+ }
1729
+ else if (stylesheetToId.has(stylesheet)) {
1730
+ const styleId = stylesheetToId.get(stylesheet);
1731
+ result += `<lwc-style style-id="lwc-style-${styleDedupePrefix}-${styleId}"></lwc-style>`;
1732
+ }
1733
+ else {
1734
+ const styleId = emit.cxt.nextId++;
1735
+ stylesheetToId.set(stylesheet, styleId.toString());
1736
+ const styleContents = stylesheet(token, useActualHostSelector, useNativeDirPseudoclass);
1737
+ validateStyleTextContents(styleContents);
1738
+ // TODO [#2869]: `<style>`s should not have scope token classes
1739
+ result += `<style${hasAnyScopedStyles ? ` class="${scopeToken}"` : ''} id="lwc-style-${styleDedupePrefix}-${styleId}" type="text/css">${styleContents}</style>`;
1740
+ result += `<lwc-style style-id="lwc-style-${styleDedupePrefix}-${styleId}"></lwc-style>`;
1741
+ }
1712
1742
  };
1713
1743
  traverseStylesheets(defaultStylesheets, renderStylesheet);
1714
1744
  traverseStylesheets(defaultScopedStylesheets, renderStylesheet);
@@ -1811,5 +1841,5 @@ function createContextProvider(adapter) {
1811
1841
  }
1812
1842
 
1813
1843
  export { ClassList, LightningElement, SYMBOL__DEFAULT_TEMPLATE, SYMBOL__GENERATE_MARKUP, SYMBOL__SET_INTERNALS, api, connectContext, createContextProvider, createElement, establishContextfulRelationship, fallbackTmpl, fallbackTmplNoYield, freezeTemplate, getComponentDef, hasScopedStaticStylesheets, hot, htmlEscape, isComponentConstructor, mutationTracker, normalizeClass, normalizeTabIndex, normalizeTextContent, parseFragment, parseSVGFragment, readonly, registerComponent, registerDecorators, registerTemplate, renderAttrs, renderAttrsNoYield, serverSideRenderComponent as renderComponent, renderStylesheets, renderTextContent, renderer, sanitizeAttribute, sanitizeHtmlContent, serverSideRenderComponent, setFeatureFlag, setFeatureFlagForTest, setHooks, swapComponent, swapStyle, swapTemplate, toIteratorDirective, track, unwrap$1 as unwrap, validateStyleTextContents, wire };
1814
- /** version: 8.15.1 */
1844
+ /** version: 8.16.1 */
1815
1845
  //# sourceMappingURL=index.js.map
package/dist/render.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type Stylesheet } from '@lwc/shared';
1
2
  import { SYMBOL__GENERATE_MARKUP } from './lightning-element';
2
3
  import type { CompilationMode } from '@lwc/shared';
3
4
  import type { LightningElement, LightningElementConstructor } from './lightning-element';
@@ -50,6 +51,13 @@ export declare function fallbackTmplNoYield(emit: Emit, shadowSlottedContent: Sl
50
51
  interface ComponentWithGenerateMarkup extends LightningElementConstructor {
51
52
  [SYMBOL__GENERATE_MARKUP]?: GenerateMarkupVariants;
52
53
  }
53
- export declare function serverSideRenderComponent(tagName: string, Component: ComponentWithGenerateMarkup, props?: Properties, mode?: CompilationMode): Promise<string>;
54
+ export declare class RenderContext {
55
+ styleDedupeIsEnabled: boolean;
56
+ stylesheetToId: WeakMap<Stylesheet, string>;
57
+ styleDedupePrefix: string;
58
+ nextId: number;
59
+ constructor(styleDedupePrefix: string, styleDedupeIsEnabled: boolean);
60
+ }
61
+ export declare function serverSideRenderComponent(tagName: string, Component: ComponentWithGenerateMarkup, props?: Properties, styleDedupePrefix?: string, styleDedupeIsEnabled?: boolean, mode?: CompilationMode): Promise<string>;
54
62
  export {};
55
63
  //# sourceMappingURL=render.d.ts.map
package/dist/styles.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import type { LightningElementConstructor } from './lightning-element';
2
2
  import type { Stylesheets, Stylesheet } from '@lwc/shared';
3
+ import type { RenderContext } from './render';
3
4
  type ForgivingStylesheets = Stylesheets | Stylesheet | undefined | null | Array<Stylesheets | undefined | null>;
5
+ type EmitFn = ((strSegment: string) => void) & {
6
+ cxt: RenderContext;
7
+ };
4
8
  export declare function hasScopedStaticStylesheets(Component: LightningElementConstructor): boolean;
5
- export declare function renderStylesheets(defaultStylesheets: ForgivingStylesheets, defaultScopedStylesheets: ForgivingStylesheets, staticStylesheets: ForgivingStylesheets, scopeToken: string, Component: LightningElementConstructor, hasScopedTemplateStyles: boolean): string;
9
+ export declare function renderStylesheets(emit: EmitFn, defaultStylesheets: ForgivingStylesheets, defaultScopedStylesheets: ForgivingStylesheets, staticStylesheets: ForgivingStylesheets, scopeToken: string, Component: LightningElementConstructor, hasScopedTemplateStyles: boolean): string;
6
10
  export {};
7
11
  //# sourceMappingURL=styles.d.ts.map
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "You can safely modify dependencies, devDependencies, keywords, etc., but other props will be overwritten."
5
5
  ],
6
6
  "name": "@lwc/ssr-runtime",
7
- "version": "8.15.1",
7
+ "version": "8.16.1",
8
8
  "description": "Runtime complement to @lwc/ssr-compiler",
9
9
  "keywords": [
10
10
  "lwc",
@@ -48,8 +48,8 @@
48
48
  }
49
49
  },
50
50
  "devDependencies": {
51
- "@lwc/shared": "8.15.1",
52
- "@lwc/engine-core": "8.15.1",
51
+ "@lwc/shared": "8.16.1",
52
+ "@lwc/engine-core": "8.16.1",
53
53
  "observable-membrane": "2.0.0"
54
54
  }
55
55
  }