@lwc/engine-core 8.12.4 → 8.12.5
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/framework/hydration-utils.d.ts +10 -0
- package/dist/framework/sanitized-html-content.d.ts +1 -7
- package/dist/index.cjs.js +153 -110
- package/dist/index.js +153 -110
- package/package.json +4 -4
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type Classes = Omit<Set<string>, 'add'>;
|
|
2
|
+
export declare function prettyPrintAttribute(attribute: string, value: any): string;
|
|
3
|
+
export declare function prettyPrintClasses(classes: Classes): string;
|
|
4
|
+
export declare function queueHydrationError(type: string, serverRendered?: any, clientExpected?: any): void;
|
|
5
|
+
export declare function flushHydrationErrors(source?: Node | null): void;
|
|
6
|
+
export declare function isTypeElement(node?: Node): node is Element;
|
|
7
|
+
export declare function isTypeText(node?: Node): node is Text;
|
|
8
|
+
export declare function isTypeComment(node?: Node): node is Comment;
|
|
9
|
+
export declare function logHydrationWarning(...args: any): void;
|
|
10
|
+
//# sourceMappingURL=hydration-utils.d.ts.map
|
|
@@ -3,6 +3,7 @@ declare const sanitizedHtmlContentSymbol: unique symbol;
|
|
|
3
3
|
export type SanitizedHtmlContent = {
|
|
4
4
|
[sanitizedHtmlContentSymbol]: unknown;
|
|
5
5
|
};
|
|
6
|
+
export declare function unwrapIfNecessary(object: any): any;
|
|
6
7
|
/**
|
|
7
8
|
* Wrap a pre-sanitized string designated for `.innerHTML` via `lwc:inner-html`
|
|
8
9
|
* as an object with a Symbol that only we have access to.
|
|
@@ -19,12 +20,5 @@ export declare function createSanitizedHtmlContent(sanitizedString: unknown): Sa
|
|
|
19
20
|
* @param value - value to set
|
|
20
21
|
*/
|
|
21
22
|
export declare function safelySetProperty(setProperty: RendererAPI['setProperty'], elm: Element, key: string, value: any): void;
|
|
22
|
-
/**
|
|
23
|
-
* Given two objects (likely either a string or a SanitizedHtmlContent object), return true if their
|
|
24
|
-
* string values are equivalent.
|
|
25
|
-
* @param first
|
|
26
|
-
* @param second
|
|
27
|
-
*/
|
|
28
|
-
export declare function isSanitizedHtmlContentEqual(first: any, second: any): boolean;
|
|
29
23
|
export {};
|
|
30
24
|
//# sourceMappingURL=sanitized-html-content.d.ts.map
|
package/dist/index.cjs.js
CHANGED
|
@@ -3977,15 +3977,6 @@ function safelySetProperty(setProperty, elm, key, value) {
|
|
|
3977
3977
|
setProperty(elm, key, value);
|
|
3978
3978
|
}
|
|
3979
3979
|
}
|
|
3980
|
-
/**
|
|
3981
|
-
* Given two objects (likely either a string or a SanitizedHtmlContent object), return true if their
|
|
3982
|
-
* string values are equivalent.
|
|
3983
|
-
* @param first
|
|
3984
|
-
* @param second
|
|
3985
|
-
*/
|
|
3986
|
-
function isSanitizedHtmlContentEqual(first, second) {
|
|
3987
|
-
return unwrapIfNecessary(first) === unwrapIfNecessary(second);
|
|
3988
|
-
}
|
|
3989
3980
|
|
|
3990
3981
|
/*
|
|
3991
3982
|
* Copyright (c) 2018, salesforce.com, inc.
|
|
@@ -7538,6 +7529,78 @@ if (process.env.IS_BROWSER && isGlobalAriaPolyfillLoaded()) {
|
|
|
7538
7529
|
}
|
|
7539
7530
|
}
|
|
7540
7531
|
|
|
7532
|
+
/*
|
|
7533
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
7534
|
+
* All rights reserved.
|
|
7535
|
+
* SPDX-License-Identifier: MIT
|
|
7536
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
7537
|
+
*/
|
|
7538
|
+
// Errors that occured during the hydration process
|
|
7539
|
+
let hydrationErrors = [];
|
|
7540
|
+
/*
|
|
7541
|
+
Prints attributes as null or "value"
|
|
7542
|
+
*/
|
|
7543
|
+
function prettyPrintAttribute(attribute, value) {
|
|
7544
|
+
assertNotProd(); // this method should never leak to prod
|
|
7545
|
+
return `${attribute}=${shared.isNull(value) || shared.isUndefined(value) ? value : `"${value}"`}`;
|
|
7546
|
+
}
|
|
7547
|
+
/*
|
|
7548
|
+
Sorts and stringifies classes
|
|
7549
|
+
*/
|
|
7550
|
+
function prettyPrintClasses(classes) {
|
|
7551
|
+
assertNotProd(); // this method should never leak to prod
|
|
7552
|
+
const value = JSON.stringify(shared.ArrayJoin.call(shared.ArraySort.call(shared.ArrayFrom(classes)), ' '));
|
|
7553
|
+
return `class=${value}`;
|
|
7554
|
+
}
|
|
7555
|
+
/*
|
|
7556
|
+
Hydration errors occur before the source node has been fully hydrated,
|
|
7557
|
+
queue them so they can be logged later against the mounted node.
|
|
7558
|
+
*/
|
|
7559
|
+
function queueHydrationError(type, serverRendered, clientExpected) {
|
|
7560
|
+
assertNotProd(); // this method should never leak to prod
|
|
7561
|
+
shared.ArrayPush.call(hydrationErrors, { type, serverRendered, clientExpected });
|
|
7562
|
+
}
|
|
7563
|
+
/*
|
|
7564
|
+
Flushes (logs) any queued errors after the source node has been mounted.
|
|
7565
|
+
*/
|
|
7566
|
+
function flushHydrationErrors(source) {
|
|
7567
|
+
assertNotProd(); // this method should never leak to prod
|
|
7568
|
+
for (const hydrationError of hydrationErrors) {
|
|
7569
|
+
logHydrationWarning(`Hydration ${hydrationError.type} mismatch on:`, source, `\n- rendered on server:`, hydrationError.serverRendered, `\n- expected on client:`, hydrationError.clientExpected || source);
|
|
7570
|
+
}
|
|
7571
|
+
hydrationErrors = [];
|
|
7572
|
+
}
|
|
7573
|
+
function isTypeElement(node) {
|
|
7574
|
+
const isCorrectType = node?.nodeType === 1 /* EnvNodeTypes.ELEMENT */;
|
|
7575
|
+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
|
|
7576
|
+
queueHydrationError('node', node);
|
|
7577
|
+
}
|
|
7578
|
+
return isCorrectType;
|
|
7579
|
+
}
|
|
7580
|
+
function isTypeText(node) {
|
|
7581
|
+
const isCorrectType = node?.nodeType === 3 /* EnvNodeTypes.TEXT */;
|
|
7582
|
+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
|
|
7583
|
+
queueHydrationError('node', node);
|
|
7584
|
+
}
|
|
7585
|
+
return isCorrectType;
|
|
7586
|
+
}
|
|
7587
|
+
function isTypeComment(node) {
|
|
7588
|
+
const isCorrectType = node?.nodeType === 8 /* EnvNodeTypes.COMMENT */;
|
|
7589
|
+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
|
|
7590
|
+
queueHydrationError('node', node);
|
|
7591
|
+
}
|
|
7592
|
+
return isCorrectType;
|
|
7593
|
+
}
|
|
7594
|
+
/*
|
|
7595
|
+
logger.ts converts all args to a string, losing object referenences and has
|
|
7596
|
+
legacy bloat which would have meant more pathing.
|
|
7597
|
+
*/
|
|
7598
|
+
function logHydrationWarning(...args) {
|
|
7599
|
+
assertNotProd(); // this method should never leak to prod
|
|
7600
|
+
/* eslint-disable-next-line no-console */
|
|
7601
|
+
console.warn('[LWC warn:', ...args);
|
|
7602
|
+
}
|
|
7603
|
+
|
|
7541
7604
|
/*
|
|
7542
7605
|
* Copyright (c) 2022, salesforce.com, inc.
|
|
7543
7606
|
* All rights reserved.
|
|
@@ -7552,8 +7615,15 @@ function hydrateRoot(vm) {
|
|
|
7552
7615
|
hasMismatch = false;
|
|
7553
7616
|
runConnectedCallback(vm);
|
|
7554
7617
|
hydrateVM(vm);
|
|
7555
|
-
if (
|
|
7556
|
-
|
|
7618
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
7619
|
+
/*
|
|
7620
|
+
Errors are queued as they occur and then logged with the source element once it has been hydrated and mounted to the DOM.
|
|
7621
|
+
Means the element in the console matches what is on the page and the highlighting works properly when you hover over the elements in the console.
|
|
7622
|
+
*/
|
|
7623
|
+
flushHydrationErrors(vm.renderRoot);
|
|
7624
|
+
if (hasMismatch) {
|
|
7625
|
+
logHydrationWarning('Hydration completed with errors.');
|
|
7626
|
+
}
|
|
7557
7627
|
}
|
|
7558
7628
|
}
|
|
7559
7629
|
function hydrateVM(vm) {
|
|
@@ -7591,21 +7661,25 @@ function hydrateNode(node, vnode, renderer) {
|
|
|
7591
7661
|
hydratedNode = hydrateCustomElement(node, vnode, vnode.data.renderer ?? renderer);
|
|
7592
7662
|
break;
|
|
7593
7663
|
}
|
|
7664
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
7665
|
+
/*
|
|
7666
|
+
Errors are queued as they occur and then logged with the source element once it has been hydrated and mounted to the DOM.
|
|
7667
|
+
Means the element in the console matches what is on the page and the highlighting works properly when you hover over the elements in the console.
|
|
7668
|
+
*/
|
|
7669
|
+
flushHydrationErrors(hydratedNode);
|
|
7670
|
+
}
|
|
7594
7671
|
return renderer.nextSibling(hydratedNode);
|
|
7595
7672
|
}
|
|
7596
7673
|
const NODE_VALUE_PROP = 'nodeValue';
|
|
7597
|
-
function
|
|
7674
|
+
function validateTextNodeEquality(node, vnode, renderer) {
|
|
7598
7675
|
const { getProperty } = renderer;
|
|
7599
7676
|
const nodeValue = getProperty(node, NODE_VALUE_PROP);
|
|
7600
|
-
if (nodeValue
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
if (nodeValue === '\u200D' && vnode.text === '') {
|
|
7606
|
-
return true;
|
|
7677
|
+
if (nodeValue !== vnode.text &&
|
|
7678
|
+
// Special case for empty text nodes – these are serialized differently on the server
|
|
7679
|
+
// See https://github.com/salesforce/lwc/pull/2656
|
|
7680
|
+
(nodeValue !== '\u200D' || vnode.text !== '')) {
|
|
7681
|
+
queueHydrationError('text content', nodeValue, vnode.text);
|
|
7607
7682
|
}
|
|
7608
|
-
return false;
|
|
7609
7683
|
}
|
|
7610
7684
|
// The validationOptOut static property can be an array of attribute names.
|
|
7611
7685
|
// Any attribute names specified in that array will not be validated, and the
|
|
@@ -7628,7 +7702,7 @@ function getValidationPredicate(elm, renderer, optOutStaticProp) {
|
|
|
7628
7702
|
!shared.isUndefined(optOutStaticProp) &&
|
|
7629
7703
|
!shared.isTrue(optOutStaticProp) &&
|
|
7630
7704
|
!isValidArray) {
|
|
7631
|
-
|
|
7705
|
+
logHydrationWarning('`validationOptOut` must be `true` or an array of attributes that should not be validated.');
|
|
7632
7706
|
}
|
|
7633
7707
|
return (attrName) => {
|
|
7634
7708
|
// Component wants to opt out of all validation
|
|
@@ -7648,16 +7722,14 @@ function getValidationPredicate(elm, renderer, optOutStaticProp) {
|
|
|
7648
7722
|
};
|
|
7649
7723
|
}
|
|
7650
7724
|
function hydrateText(node, vnode, renderer) {
|
|
7651
|
-
if (!
|
|
7725
|
+
if (!isTypeText(node)) {
|
|
7652
7726
|
return handleMismatch(node, vnode, renderer);
|
|
7653
7727
|
}
|
|
7654
|
-
return updateTextContent(node, vnode,
|
|
7728
|
+
return updateTextContent(node, vnode, renderer);
|
|
7655
7729
|
}
|
|
7656
|
-
function updateTextContent(node, vnode,
|
|
7730
|
+
function updateTextContent(node, vnode, renderer) {
|
|
7657
7731
|
if (process.env.NODE_ENV !== 'production') {
|
|
7658
|
-
|
|
7659
|
-
logWarn('Hydration mismatch: text values do not match, will recover from the difference', owner);
|
|
7660
|
-
}
|
|
7732
|
+
validateTextNodeEquality(node, vnode, renderer);
|
|
7661
7733
|
}
|
|
7662
7734
|
const { setText } = renderer;
|
|
7663
7735
|
setText(node, vnode.text ?? null);
|
|
@@ -7665,14 +7737,14 @@ function updateTextContent(node, vnode, owner, renderer) {
|
|
|
7665
7737
|
return node;
|
|
7666
7738
|
}
|
|
7667
7739
|
function hydrateComment(node, vnode, renderer) {
|
|
7668
|
-
if (!
|
|
7740
|
+
if (!isTypeComment(node)) {
|
|
7669
7741
|
return handleMismatch(node, vnode, renderer);
|
|
7670
7742
|
}
|
|
7671
7743
|
if (process.env.NODE_ENV !== 'production') {
|
|
7672
7744
|
const { getProperty } = renderer;
|
|
7673
7745
|
const nodeValue = getProperty(node, NODE_VALUE_PROP);
|
|
7674
7746
|
if (nodeValue !== vnode.text) {
|
|
7675
|
-
|
|
7747
|
+
queueHydrationError('comment', nodeValue, vnode.text);
|
|
7676
7748
|
}
|
|
7677
7749
|
}
|
|
7678
7750
|
const { setProperty } = renderer;
|
|
@@ -7683,11 +7755,12 @@ function hydrateComment(node, vnode, renderer) {
|
|
|
7683
7755
|
return node;
|
|
7684
7756
|
}
|
|
7685
7757
|
function hydrateStaticElement(elm, vnode, renderer) {
|
|
7686
|
-
if (
|
|
7687
|
-
|
|
7688
|
-
|
|
7758
|
+
if (isTypeElement(elm) &&
|
|
7759
|
+
isTypeElement(vnode.fragment) &&
|
|
7760
|
+
areStaticElementsCompatible(vnode.fragment, elm, vnode, renderer)) {
|
|
7761
|
+
return hydrateStaticElementParts(elm, vnode, renderer);
|
|
7689
7762
|
}
|
|
7690
|
-
return
|
|
7763
|
+
return handleMismatch(elm, vnode, renderer);
|
|
7691
7764
|
}
|
|
7692
7765
|
function hydrateStaticElementParts(elm, vnode, renderer) {
|
|
7693
7766
|
const { parts } = vnode;
|
|
@@ -7710,8 +7783,7 @@ function hydrateFragment(elm, vnode, renderer) {
|
|
|
7710
7783
|
return (vnode.elm = children[children.length - 1].elm);
|
|
7711
7784
|
}
|
|
7712
7785
|
function hydrateElement(elm, vnode, renderer) {
|
|
7713
|
-
if (!
|
|
7714
|
-
!isMatchingElement(vnode, elm, renderer)) {
|
|
7786
|
+
if (!isTypeElement(elm) || !isMatchingElement(vnode, elm, renderer)) {
|
|
7715
7787
|
return handleMismatch(elm, vnode, renderer);
|
|
7716
7788
|
}
|
|
7717
7789
|
vnode.elm = elm;
|
|
@@ -7724,17 +7796,17 @@ function hydrateElement(elm, vnode, renderer) {
|
|
|
7724
7796
|
const { data: { props }, } = vnode;
|
|
7725
7797
|
const { getProperty } = renderer;
|
|
7726
7798
|
if (!shared.isUndefined(props) && !shared.isUndefined(props.innerHTML)) {
|
|
7727
|
-
|
|
7799
|
+
const unwrappedServerInnerHTML = unwrapIfNecessary(getProperty(elm, 'innerHTML'));
|
|
7800
|
+
const unwrappedClientInnerHTML = unwrapIfNecessary(props.innerHTML);
|
|
7801
|
+
if (unwrappedServerInnerHTML === unwrappedClientInnerHTML) {
|
|
7728
7802
|
// Do a shallow clone since VNodeData may be shared across VNodes due to hoist optimization
|
|
7729
7803
|
vnode.data = {
|
|
7730
7804
|
...vnode.data,
|
|
7731
7805
|
props: cloneAndOmitKey(props, 'innerHTML'),
|
|
7732
7806
|
};
|
|
7733
7807
|
}
|
|
7734
|
-
else {
|
|
7735
|
-
|
|
7736
|
-
logWarn(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: innerHTML values do not match for element, will recover from the difference`, owner);
|
|
7737
|
-
}
|
|
7808
|
+
else if (process.env.NODE_ENV !== 'production') {
|
|
7809
|
+
queueHydrationError('innerHTML', unwrappedServerInnerHTML, unwrappedClientInnerHTML);
|
|
7738
7810
|
}
|
|
7739
7811
|
}
|
|
7740
7812
|
}
|
|
@@ -7757,8 +7829,7 @@ function hydrateCustomElement(elm, vnode, renderer) {
|
|
|
7757
7829
|
//
|
|
7758
7830
|
// Therefore, if validationOptOut is falsey or an array of strings, we need to
|
|
7759
7831
|
// examine some or all of the custom element's attributes.
|
|
7760
|
-
if (!
|
|
7761
|
-
!isMatchingElement(vnode, elm, renderer, shouldValidateAttr)) {
|
|
7832
|
+
if (!isTypeElement(elm) || !isMatchingElement(vnode, elm, renderer, shouldValidateAttr)) {
|
|
7762
7833
|
return handleMismatch(elm, vnode, renderer);
|
|
7763
7834
|
}
|
|
7764
7835
|
const { sel, mode, ctor, owner } = vnode;
|
|
@@ -7794,9 +7865,13 @@ function hydrateChildren(node, children, parentNode, owner,
|
|
|
7794
7865
|
// last node of the fragment. Hydration should not fail if a trailing sibling is
|
|
7795
7866
|
// found in this case.
|
|
7796
7867
|
expectAddlSiblings) {
|
|
7797
|
-
let
|
|
7868
|
+
let mismatchedChildren = false;
|
|
7798
7869
|
let nextNode = node;
|
|
7799
7870
|
const { renderer } = owner;
|
|
7871
|
+
const { getChildNodes, cloneNode } = renderer;
|
|
7872
|
+
const serverNodes = process.env.NODE_ENV !== 'production'
|
|
7873
|
+
? Array.from(getChildNodes(parentNode), (node) => cloneNode(node, true))
|
|
7874
|
+
: null;
|
|
7800
7875
|
for (let i = 0; i < children.length; i++) {
|
|
7801
7876
|
const childVnode = children[i];
|
|
7802
7877
|
if (!shared.isNull(childVnode)) {
|
|
@@ -7804,13 +7879,7 @@ expectAddlSiblings) {
|
|
|
7804
7879
|
nextNode = hydrateNode(nextNode, childVnode, renderer);
|
|
7805
7880
|
}
|
|
7806
7881
|
else {
|
|
7807
|
-
|
|
7808
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
7809
|
-
if (!hasWarned) {
|
|
7810
|
-
hasWarned = true;
|
|
7811
|
-
logWarn(`Hydration mismatch: incorrect number of rendered nodes. Client produced more nodes than the server.`, owner);
|
|
7812
|
-
}
|
|
7813
|
-
}
|
|
7882
|
+
mismatchedChildren = true;
|
|
7814
7883
|
mount(childVnode, parentNode, renderer, nextNode);
|
|
7815
7884
|
nextNode = renderer.nextSibling(childVnode.type === 5 /* VNodeType.Fragment */ ? childVnode.trailing : childVnode.elm);
|
|
7816
7885
|
}
|
|
@@ -7827,12 +7896,7 @@ expectAddlSiblings) {
|
|
|
7827
7896
|
// rendered more nodes than the client.
|
|
7828
7897
|
(!useCommentsForBookends || !expectAddlSiblings) &&
|
|
7829
7898
|
nextNode) {
|
|
7830
|
-
|
|
7831
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
7832
|
-
if (!hasWarned) {
|
|
7833
|
-
logWarn(`Hydration mismatch: incorrect number of rendered nodes. Server rendered more nodes than the client.`, owner);
|
|
7834
|
-
}
|
|
7835
|
-
}
|
|
7899
|
+
mismatchedChildren = true;
|
|
7836
7900
|
// nextSibling is mostly harmless, and since we don't have
|
|
7837
7901
|
// a good reference to what element to act upon, we instead
|
|
7838
7902
|
// rely on the vm's associated renderer for navigating to the
|
|
@@ -7844,6 +7908,14 @@ expectAddlSiblings) {
|
|
|
7844
7908
|
removeNode(current, parentNode, renderer);
|
|
7845
7909
|
} while (nextNode);
|
|
7846
7910
|
}
|
|
7911
|
+
if (mismatchedChildren) {
|
|
7912
|
+
hasMismatch = true;
|
|
7913
|
+
// We can't know exactly which node(s) caused the delta, but we can provide context (parent) and the mismatched sets
|
|
7914
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
7915
|
+
const clientNodes = shared.ArrayMap.call(children, (c) => c?.elm);
|
|
7916
|
+
queueHydrationError('child node', serverNodes, clientNodes);
|
|
7917
|
+
}
|
|
7918
|
+
}
|
|
7847
7919
|
}
|
|
7848
7920
|
function handleMismatch(node, vnode, renderer) {
|
|
7849
7921
|
hasMismatch = true;
|
|
@@ -7859,31 +7931,21 @@ function patchElementPropsAndAttrsAndRefs(vnode, renderer) {
|
|
|
7859
7931
|
// The `refs` object is blown away in every re-render, so we always need to re-apply them
|
|
7860
7932
|
applyRefs(vnode, vnode.owner);
|
|
7861
7933
|
}
|
|
7862
|
-
function hasCorrectNodeType(vnode, node, nodeType, renderer) {
|
|
7863
|
-
const { getProperty } = renderer;
|
|
7864
|
-
if (getProperty(node, 'nodeType') !== nodeType) {
|
|
7865
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
7866
|
-
logWarn('Hydration mismatch: incorrect node type received', vnode.owner);
|
|
7867
|
-
}
|
|
7868
|
-
return false;
|
|
7869
|
-
}
|
|
7870
|
-
return true;
|
|
7871
|
-
}
|
|
7872
7934
|
function isMatchingElement(vnode, elm, renderer, shouldValidateAttr = () => true) {
|
|
7873
7935
|
const { getProperty } = renderer;
|
|
7874
7936
|
if (vnode.sel.toLowerCase() !== getProperty(elm, 'tagName').toLowerCase()) {
|
|
7875
7937
|
if (process.env.NODE_ENV !== 'production') {
|
|
7876
|
-
|
|
7938
|
+
queueHydrationError('node', elm);
|
|
7877
7939
|
}
|
|
7878
7940
|
return false;
|
|
7879
7941
|
}
|
|
7880
7942
|
const { data } = vnode;
|
|
7881
|
-
const hasCompatibleAttrs = validateAttrs(
|
|
7943
|
+
const hasCompatibleAttrs = validateAttrs(elm, data, renderer, shouldValidateAttr);
|
|
7882
7944
|
const hasCompatibleClass = shouldValidateAttr('class')
|
|
7883
7945
|
? validateClassAttr(vnode, elm, data, renderer)
|
|
7884
7946
|
: true;
|
|
7885
7947
|
const hasCompatibleStyle = shouldValidateAttr('style')
|
|
7886
|
-
? validateStyleAttr(
|
|
7948
|
+
? validateStyleAttr(elm, data, renderer)
|
|
7887
7949
|
: true;
|
|
7888
7950
|
return hasCompatibleAttrs && hasCompatibleClass && hasCompatibleStyle;
|
|
7889
7951
|
}
|
|
@@ -7900,7 +7962,7 @@ function attributeValuesAreEqual(vnodeValue, value) {
|
|
|
7900
7962
|
// In all other cases, the two values are not considered equal
|
|
7901
7963
|
return false;
|
|
7902
7964
|
}
|
|
7903
|
-
function validateAttrs(
|
|
7965
|
+
function validateAttrs(elm, data, renderer, shouldValidateAttr) {
|
|
7904
7966
|
const { attrs = {} } = data;
|
|
7905
7967
|
let nodesAreCompatible = true;
|
|
7906
7968
|
// Validate attributes, though we could always recovery from those by running the update mods.
|
|
@@ -7913,8 +7975,7 @@ function validateAttrs(vnode, elm, data, renderer, shouldValidateAttr) {
|
|
|
7913
7975
|
const elmAttrValue = getAttribute(elm, attrName);
|
|
7914
7976
|
if (!attributeValuesAreEqual(attrValue, elmAttrValue)) {
|
|
7915
7977
|
if (process.env.NODE_ENV !== 'production') {
|
|
7916
|
-
|
|
7917
|
-
logWarn(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: attribute "${attrName}" has different values, expected "${attrValue}" but found ${shared.isNull(elmAttrValue) ? 'null' : `"${elmAttrValue}"`}`, vnode.owner);
|
|
7978
|
+
queueHydrationError('attribute', prettyPrintAttribute(attrName, elmAttrValue), prettyPrintAttribute(attrName, attrValue));
|
|
7918
7979
|
}
|
|
7919
7980
|
nodesAreCompatible = false;
|
|
7920
7981
|
}
|
|
@@ -7942,7 +8003,6 @@ function validateClassAttr(vnode, elm, data, renderer) {
|
|
|
7942
8003
|
// classMap is never available on VStaticPartData so it can default to undefined
|
|
7943
8004
|
// casting to prevent TS error.
|
|
7944
8005
|
const { className, classMap } = data;
|
|
7945
|
-
const { getProperty } = renderer;
|
|
7946
8006
|
// ---------- Step 1: get the classes from the element and the vnode
|
|
7947
8007
|
// Use a Set because we don't care to validate mismatches for 1) different ordering in SSR vs CSR, or 2)
|
|
7948
8008
|
// duplicated class names. These don't have an effect on rendered styles.
|
|
@@ -7988,12 +8048,11 @@ function validateClassAttr(vnode, elm, data, renderer) {
|
|
|
7988
8048
|
// ---------- Step 3: check for compatibility
|
|
7989
8049
|
const classesAreCompatible = checkClassesCompatibility(vnodeClasses, elmClasses);
|
|
7990
8050
|
if (process.env.NODE_ENV !== 'production' && !classesAreCompatible) {
|
|
7991
|
-
|
|
7992
|
-
logWarn(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: attribute "class" has different values, expected ${prettyPrint(vnodeClasses)} but found ${prettyPrint(elmClasses)}`, vnode.owner);
|
|
8051
|
+
queueHydrationError('attribute', prettyPrintClasses(elmClasses), prettyPrintClasses(vnodeClasses));
|
|
7993
8052
|
}
|
|
7994
8053
|
return classesAreCompatible;
|
|
7995
8054
|
}
|
|
7996
|
-
function validateStyleAttr(
|
|
8055
|
+
function validateStyleAttr(elm, data, renderer) {
|
|
7997
8056
|
// Note styleDecls is always undefined for VStaticPartData, casting here to default it to undefined
|
|
7998
8057
|
const { style, styleDecls } = data;
|
|
7999
8058
|
const { getAttribute } = renderer;
|
|
@@ -8027,49 +8086,33 @@ function validateStyleAttr(vnode, elm, data, renderer) {
|
|
|
8027
8086
|
}
|
|
8028
8087
|
vnodeStyle = shared.ArrayJoin.call(expectedStyle, ' ');
|
|
8029
8088
|
}
|
|
8030
|
-
if (!nodesAreCompatible) {
|
|
8031
|
-
|
|
8032
|
-
const { getProperty } = renderer;
|
|
8033
|
-
logWarn(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: attribute "style" has different values, expected "${vnodeStyle}" but found "${elmStyle}".`, vnode.owner);
|
|
8034
|
-
}
|
|
8089
|
+
if (process.env.NODE_ENV !== 'production' && !nodesAreCompatible) {
|
|
8090
|
+
queueHydrationError('attribute', prettyPrintAttribute('style', elmStyle), prettyPrintAttribute('style', vnodeStyle));
|
|
8035
8091
|
}
|
|
8036
8092
|
return nodesAreCompatible;
|
|
8037
8093
|
}
|
|
8038
|
-
function
|
|
8094
|
+
function areStaticElementsCompatible(clientElement, serverElement, vnode, renderer) {
|
|
8039
8095
|
const { getProperty, getAttribute } = renderer;
|
|
8040
|
-
|
|
8041
|
-
if (!hasCorrectNodeType(vnode, ssr, 3 /* EnvNodeTypes.TEXT */, renderer)) {
|
|
8042
|
-
return false;
|
|
8043
|
-
}
|
|
8044
|
-
return getProperty(client, NODE_VALUE_PROP) === getProperty(ssr, NODE_VALUE_PROP);
|
|
8045
|
-
}
|
|
8046
|
-
if (getProperty(client, 'nodeType') === 8 /* EnvNodeTypes.COMMENT */) {
|
|
8047
|
-
if (!hasCorrectNodeType(vnode, ssr, 8 /* EnvNodeTypes.COMMENT */, renderer)) {
|
|
8048
|
-
return false;
|
|
8049
|
-
}
|
|
8050
|
-
return getProperty(client, NODE_VALUE_PROP) === getProperty(ssr, NODE_VALUE_PROP);
|
|
8051
|
-
}
|
|
8052
|
-
if (!hasCorrectNodeType(vnode, ssr, 1 /* EnvNodeTypes.ELEMENT */, renderer)) {
|
|
8053
|
-
return false;
|
|
8054
|
-
}
|
|
8055
|
-
const { owner, parts } = vnode;
|
|
8096
|
+
const { parts } = vnode;
|
|
8056
8097
|
let isCompatibleElements = true;
|
|
8057
|
-
if (getProperty(
|
|
8098
|
+
if (getProperty(clientElement, 'tagName') !== getProperty(serverElement, 'tagName')) {
|
|
8058
8099
|
if (process.env.NODE_ENV !== 'production') {
|
|
8059
|
-
|
|
8100
|
+
queueHydrationError('node', serverElement);
|
|
8060
8101
|
}
|
|
8061
8102
|
return false;
|
|
8062
8103
|
}
|
|
8063
|
-
const clientAttrsNames = getProperty(
|
|
8104
|
+
const clientAttrsNames = getProperty(clientElement, 'getAttributeNames').call(clientElement);
|
|
8064
8105
|
clientAttrsNames.forEach((attrName) => {
|
|
8065
|
-
|
|
8106
|
+
const clientAttributeValue = getAttribute(clientElement, attrName);
|
|
8107
|
+
const serverAttributeValue = getAttribute(serverElement, attrName);
|
|
8108
|
+
if (clientAttributeValue !== serverAttributeValue) {
|
|
8066
8109
|
// Check if the root element attributes have expressions, if it does then we need to delegate hydration
|
|
8067
8110
|
// validation to haveCompatibleStaticParts.
|
|
8068
8111
|
// Note if there are no parts then it is a fully static fragment.
|
|
8069
8112
|
// partId === 0 will always refer to the root element, this is guaranteed by the compiler.
|
|
8070
8113
|
if (parts?.[0].partId !== 0) {
|
|
8071
8114
|
if (process.env.NODE_ENV !== 'production') {
|
|
8072
|
-
|
|
8115
|
+
queueHydrationError('attribute', prettyPrintAttribute(attrName, serverAttributeValue), prettyPrintAttribute(attrName, clientAttributeValue));
|
|
8073
8116
|
}
|
|
8074
8117
|
isCompatibleElements = false;
|
|
8075
8118
|
}
|
|
@@ -8078,7 +8121,7 @@ function areCompatibleStaticNodes(client, ssr, vnode, renderer) {
|
|
|
8078
8121
|
return isCompatibleElements;
|
|
8079
8122
|
}
|
|
8080
8123
|
function haveCompatibleStaticParts(vnode, renderer) {
|
|
8081
|
-
const { parts
|
|
8124
|
+
const { parts } = vnode;
|
|
8082
8125
|
if (shared.isUndefined(parts)) {
|
|
8083
8126
|
return true;
|
|
8084
8127
|
}
|
|
@@ -8089,11 +8132,11 @@ function haveCompatibleStaticParts(vnode, renderer) {
|
|
|
8089
8132
|
for (const part of parts) {
|
|
8090
8133
|
const { elm } = part;
|
|
8091
8134
|
if (isVStaticPartElement(part)) {
|
|
8092
|
-
if (!
|
|
8135
|
+
if (!isTypeElement(elm)) {
|
|
8093
8136
|
return false;
|
|
8094
8137
|
}
|
|
8095
8138
|
const { data } = part;
|
|
8096
|
-
const hasMatchingAttrs = validateAttrs(
|
|
8139
|
+
const hasMatchingAttrs = validateAttrs(elm, data, renderer, () => true);
|
|
8097
8140
|
// Explicitly skip hydration validation when static parts don't contain `style` or `className`.
|
|
8098
8141
|
// This means the style/class attributes are either static or don't exist on the element and
|
|
8099
8142
|
// cannot be affected by hydration.
|
|
@@ -8103,7 +8146,7 @@ function haveCompatibleStaticParts(vnode, renderer) {
|
|
|
8103
8146
|
? validateClassAttr(vnode, elm, data, renderer)
|
|
8104
8147
|
: true;
|
|
8105
8148
|
const hasMatchingStyleAttr = shouldValidateAttr(data, 'style')
|
|
8106
|
-
? validateStyleAttr(
|
|
8149
|
+
? validateStyleAttr(elm, data, renderer)
|
|
8107
8150
|
: true;
|
|
8108
8151
|
if (shared.isFalse(hasMatchingAttrs && hasMatchingClass && hasMatchingStyleAttr)) {
|
|
8109
8152
|
return false;
|
|
@@ -8111,10 +8154,10 @@ function haveCompatibleStaticParts(vnode, renderer) {
|
|
|
8111
8154
|
}
|
|
8112
8155
|
else {
|
|
8113
8156
|
// VStaticPartText
|
|
8114
|
-
if (!
|
|
8157
|
+
if (!isTypeText(elm)) {
|
|
8115
8158
|
return false;
|
|
8116
8159
|
}
|
|
8117
|
-
updateTextContent(elm, part,
|
|
8160
|
+
updateTextContent(elm, part, renderer);
|
|
8118
8161
|
}
|
|
8119
8162
|
}
|
|
8120
8163
|
return true;
|
|
@@ -8431,5 +8474,5 @@ exports.swapTemplate = swapTemplate;
|
|
|
8431
8474
|
exports.track = track;
|
|
8432
8475
|
exports.unwrap = unwrap;
|
|
8433
8476
|
exports.wire = wire;
|
|
8434
|
-
/** version: 8.12.
|
|
8477
|
+
/** version: 8.12.5 */
|
|
8435
8478
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.js
CHANGED
|
@@ -3974,15 +3974,6 @@ function safelySetProperty(setProperty, elm, key, value) {
|
|
|
3974
3974
|
setProperty(elm, key, value);
|
|
3975
3975
|
}
|
|
3976
3976
|
}
|
|
3977
|
-
/**
|
|
3978
|
-
* Given two objects (likely either a string or a SanitizedHtmlContent object), return true if their
|
|
3979
|
-
* string values are equivalent.
|
|
3980
|
-
* @param first
|
|
3981
|
-
* @param second
|
|
3982
|
-
*/
|
|
3983
|
-
function isSanitizedHtmlContentEqual(first, second) {
|
|
3984
|
-
return unwrapIfNecessary(first) === unwrapIfNecessary(second);
|
|
3985
|
-
}
|
|
3986
3977
|
|
|
3987
3978
|
/*
|
|
3988
3979
|
* Copyright (c) 2018, salesforce.com, inc.
|
|
@@ -7535,6 +7526,78 @@ if (process.env.IS_BROWSER && isGlobalAriaPolyfillLoaded()) {
|
|
|
7535
7526
|
}
|
|
7536
7527
|
}
|
|
7537
7528
|
|
|
7529
|
+
/*
|
|
7530
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
7531
|
+
* All rights reserved.
|
|
7532
|
+
* SPDX-License-Identifier: MIT
|
|
7533
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
|
|
7534
|
+
*/
|
|
7535
|
+
// Errors that occured during the hydration process
|
|
7536
|
+
let hydrationErrors = [];
|
|
7537
|
+
/*
|
|
7538
|
+
Prints attributes as null or "value"
|
|
7539
|
+
*/
|
|
7540
|
+
function prettyPrintAttribute(attribute, value) {
|
|
7541
|
+
assertNotProd(); // this method should never leak to prod
|
|
7542
|
+
return `${attribute}=${isNull(value) || isUndefined$1(value) ? value : `"${value}"`}`;
|
|
7543
|
+
}
|
|
7544
|
+
/*
|
|
7545
|
+
Sorts and stringifies classes
|
|
7546
|
+
*/
|
|
7547
|
+
function prettyPrintClasses(classes) {
|
|
7548
|
+
assertNotProd(); // this method should never leak to prod
|
|
7549
|
+
const value = JSON.stringify(ArrayJoin.call(ArraySort.call(ArrayFrom(classes)), ' '));
|
|
7550
|
+
return `class=${value}`;
|
|
7551
|
+
}
|
|
7552
|
+
/*
|
|
7553
|
+
Hydration errors occur before the source node has been fully hydrated,
|
|
7554
|
+
queue them so they can be logged later against the mounted node.
|
|
7555
|
+
*/
|
|
7556
|
+
function queueHydrationError(type, serverRendered, clientExpected) {
|
|
7557
|
+
assertNotProd(); // this method should never leak to prod
|
|
7558
|
+
ArrayPush$1.call(hydrationErrors, { type, serverRendered, clientExpected });
|
|
7559
|
+
}
|
|
7560
|
+
/*
|
|
7561
|
+
Flushes (logs) any queued errors after the source node has been mounted.
|
|
7562
|
+
*/
|
|
7563
|
+
function flushHydrationErrors(source) {
|
|
7564
|
+
assertNotProd(); // this method should never leak to prod
|
|
7565
|
+
for (const hydrationError of hydrationErrors) {
|
|
7566
|
+
logHydrationWarning(`Hydration ${hydrationError.type} mismatch on:`, source, `\n- rendered on server:`, hydrationError.serverRendered, `\n- expected on client:`, hydrationError.clientExpected || source);
|
|
7567
|
+
}
|
|
7568
|
+
hydrationErrors = [];
|
|
7569
|
+
}
|
|
7570
|
+
function isTypeElement(node) {
|
|
7571
|
+
const isCorrectType = node?.nodeType === 1 /* EnvNodeTypes.ELEMENT */;
|
|
7572
|
+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
|
|
7573
|
+
queueHydrationError('node', node);
|
|
7574
|
+
}
|
|
7575
|
+
return isCorrectType;
|
|
7576
|
+
}
|
|
7577
|
+
function isTypeText(node) {
|
|
7578
|
+
const isCorrectType = node?.nodeType === 3 /* EnvNodeTypes.TEXT */;
|
|
7579
|
+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
|
|
7580
|
+
queueHydrationError('node', node);
|
|
7581
|
+
}
|
|
7582
|
+
return isCorrectType;
|
|
7583
|
+
}
|
|
7584
|
+
function isTypeComment(node) {
|
|
7585
|
+
const isCorrectType = node?.nodeType === 8 /* EnvNodeTypes.COMMENT */;
|
|
7586
|
+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
|
|
7587
|
+
queueHydrationError('node', node);
|
|
7588
|
+
}
|
|
7589
|
+
return isCorrectType;
|
|
7590
|
+
}
|
|
7591
|
+
/*
|
|
7592
|
+
logger.ts converts all args to a string, losing object referenences and has
|
|
7593
|
+
legacy bloat which would have meant more pathing.
|
|
7594
|
+
*/
|
|
7595
|
+
function logHydrationWarning(...args) {
|
|
7596
|
+
assertNotProd(); // this method should never leak to prod
|
|
7597
|
+
/* eslint-disable-next-line no-console */
|
|
7598
|
+
console.warn('[LWC warn:', ...args);
|
|
7599
|
+
}
|
|
7600
|
+
|
|
7538
7601
|
/*
|
|
7539
7602
|
* Copyright (c) 2022, salesforce.com, inc.
|
|
7540
7603
|
* All rights reserved.
|
|
@@ -7549,8 +7612,15 @@ function hydrateRoot(vm) {
|
|
|
7549
7612
|
hasMismatch = false;
|
|
7550
7613
|
runConnectedCallback(vm);
|
|
7551
7614
|
hydrateVM(vm);
|
|
7552
|
-
if (
|
|
7553
|
-
|
|
7615
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
7616
|
+
/*
|
|
7617
|
+
Errors are queued as they occur and then logged with the source element once it has been hydrated and mounted to the DOM.
|
|
7618
|
+
Means the element in the console matches what is on the page and the highlighting works properly when you hover over the elements in the console.
|
|
7619
|
+
*/
|
|
7620
|
+
flushHydrationErrors(vm.renderRoot);
|
|
7621
|
+
if (hasMismatch) {
|
|
7622
|
+
logHydrationWarning('Hydration completed with errors.');
|
|
7623
|
+
}
|
|
7554
7624
|
}
|
|
7555
7625
|
}
|
|
7556
7626
|
function hydrateVM(vm) {
|
|
@@ -7588,21 +7658,25 @@ function hydrateNode(node, vnode, renderer) {
|
|
|
7588
7658
|
hydratedNode = hydrateCustomElement(node, vnode, vnode.data.renderer ?? renderer);
|
|
7589
7659
|
break;
|
|
7590
7660
|
}
|
|
7661
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
7662
|
+
/*
|
|
7663
|
+
Errors are queued as they occur and then logged with the source element once it has been hydrated and mounted to the DOM.
|
|
7664
|
+
Means the element in the console matches what is on the page and the highlighting works properly when you hover over the elements in the console.
|
|
7665
|
+
*/
|
|
7666
|
+
flushHydrationErrors(hydratedNode);
|
|
7667
|
+
}
|
|
7591
7668
|
return renderer.nextSibling(hydratedNode);
|
|
7592
7669
|
}
|
|
7593
7670
|
const NODE_VALUE_PROP = 'nodeValue';
|
|
7594
|
-
function
|
|
7671
|
+
function validateTextNodeEquality(node, vnode, renderer) {
|
|
7595
7672
|
const { getProperty } = renderer;
|
|
7596
7673
|
const nodeValue = getProperty(node, NODE_VALUE_PROP);
|
|
7597
|
-
if (nodeValue
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
if (nodeValue === '\u200D' && vnode.text === '') {
|
|
7603
|
-
return true;
|
|
7674
|
+
if (nodeValue !== vnode.text &&
|
|
7675
|
+
// Special case for empty text nodes – these are serialized differently on the server
|
|
7676
|
+
// See https://github.com/salesforce/lwc/pull/2656
|
|
7677
|
+
(nodeValue !== '\u200D' || vnode.text !== '')) {
|
|
7678
|
+
queueHydrationError('text content', nodeValue, vnode.text);
|
|
7604
7679
|
}
|
|
7605
|
-
return false;
|
|
7606
7680
|
}
|
|
7607
7681
|
// The validationOptOut static property can be an array of attribute names.
|
|
7608
7682
|
// Any attribute names specified in that array will not be validated, and the
|
|
@@ -7625,7 +7699,7 @@ function getValidationPredicate(elm, renderer, optOutStaticProp) {
|
|
|
7625
7699
|
!isUndefined$1(optOutStaticProp) &&
|
|
7626
7700
|
!isTrue(optOutStaticProp) &&
|
|
7627
7701
|
!isValidArray) {
|
|
7628
|
-
|
|
7702
|
+
logHydrationWarning('`validationOptOut` must be `true` or an array of attributes that should not be validated.');
|
|
7629
7703
|
}
|
|
7630
7704
|
return (attrName) => {
|
|
7631
7705
|
// Component wants to opt out of all validation
|
|
@@ -7645,16 +7719,14 @@ function getValidationPredicate(elm, renderer, optOutStaticProp) {
|
|
|
7645
7719
|
};
|
|
7646
7720
|
}
|
|
7647
7721
|
function hydrateText(node, vnode, renderer) {
|
|
7648
|
-
if (!
|
|
7722
|
+
if (!isTypeText(node)) {
|
|
7649
7723
|
return handleMismatch(node, vnode, renderer);
|
|
7650
7724
|
}
|
|
7651
|
-
return updateTextContent(node, vnode,
|
|
7725
|
+
return updateTextContent(node, vnode, renderer);
|
|
7652
7726
|
}
|
|
7653
|
-
function updateTextContent(node, vnode,
|
|
7727
|
+
function updateTextContent(node, vnode, renderer) {
|
|
7654
7728
|
if (process.env.NODE_ENV !== 'production') {
|
|
7655
|
-
|
|
7656
|
-
logWarn('Hydration mismatch: text values do not match, will recover from the difference', owner);
|
|
7657
|
-
}
|
|
7729
|
+
validateTextNodeEquality(node, vnode, renderer);
|
|
7658
7730
|
}
|
|
7659
7731
|
const { setText } = renderer;
|
|
7660
7732
|
setText(node, vnode.text ?? null);
|
|
@@ -7662,14 +7734,14 @@ function updateTextContent(node, vnode, owner, renderer) {
|
|
|
7662
7734
|
return node;
|
|
7663
7735
|
}
|
|
7664
7736
|
function hydrateComment(node, vnode, renderer) {
|
|
7665
|
-
if (!
|
|
7737
|
+
if (!isTypeComment(node)) {
|
|
7666
7738
|
return handleMismatch(node, vnode, renderer);
|
|
7667
7739
|
}
|
|
7668
7740
|
if (process.env.NODE_ENV !== 'production') {
|
|
7669
7741
|
const { getProperty } = renderer;
|
|
7670
7742
|
const nodeValue = getProperty(node, NODE_VALUE_PROP);
|
|
7671
7743
|
if (nodeValue !== vnode.text) {
|
|
7672
|
-
|
|
7744
|
+
queueHydrationError('comment', nodeValue, vnode.text);
|
|
7673
7745
|
}
|
|
7674
7746
|
}
|
|
7675
7747
|
const { setProperty } = renderer;
|
|
@@ -7680,11 +7752,12 @@ function hydrateComment(node, vnode, renderer) {
|
|
|
7680
7752
|
return node;
|
|
7681
7753
|
}
|
|
7682
7754
|
function hydrateStaticElement(elm, vnode, renderer) {
|
|
7683
|
-
if (
|
|
7684
|
-
|
|
7685
|
-
|
|
7755
|
+
if (isTypeElement(elm) &&
|
|
7756
|
+
isTypeElement(vnode.fragment) &&
|
|
7757
|
+
areStaticElementsCompatible(vnode.fragment, elm, vnode, renderer)) {
|
|
7758
|
+
return hydrateStaticElementParts(elm, vnode, renderer);
|
|
7686
7759
|
}
|
|
7687
|
-
return
|
|
7760
|
+
return handleMismatch(elm, vnode, renderer);
|
|
7688
7761
|
}
|
|
7689
7762
|
function hydrateStaticElementParts(elm, vnode, renderer) {
|
|
7690
7763
|
const { parts } = vnode;
|
|
@@ -7707,8 +7780,7 @@ function hydrateFragment(elm, vnode, renderer) {
|
|
|
7707
7780
|
return (vnode.elm = children[children.length - 1].elm);
|
|
7708
7781
|
}
|
|
7709
7782
|
function hydrateElement(elm, vnode, renderer) {
|
|
7710
|
-
if (!
|
|
7711
|
-
!isMatchingElement(vnode, elm, renderer)) {
|
|
7783
|
+
if (!isTypeElement(elm) || !isMatchingElement(vnode, elm, renderer)) {
|
|
7712
7784
|
return handleMismatch(elm, vnode, renderer);
|
|
7713
7785
|
}
|
|
7714
7786
|
vnode.elm = elm;
|
|
@@ -7721,17 +7793,17 @@ function hydrateElement(elm, vnode, renderer) {
|
|
|
7721
7793
|
const { data: { props }, } = vnode;
|
|
7722
7794
|
const { getProperty } = renderer;
|
|
7723
7795
|
if (!isUndefined$1(props) && !isUndefined$1(props.innerHTML)) {
|
|
7724
|
-
|
|
7796
|
+
const unwrappedServerInnerHTML = unwrapIfNecessary(getProperty(elm, 'innerHTML'));
|
|
7797
|
+
const unwrappedClientInnerHTML = unwrapIfNecessary(props.innerHTML);
|
|
7798
|
+
if (unwrappedServerInnerHTML === unwrappedClientInnerHTML) {
|
|
7725
7799
|
// Do a shallow clone since VNodeData may be shared across VNodes due to hoist optimization
|
|
7726
7800
|
vnode.data = {
|
|
7727
7801
|
...vnode.data,
|
|
7728
7802
|
props: cloneAndOmitKey(props, 'innerHTML'),
|
|
7729
7803
|
};
|
|
7730
7804
|
}
|
|
7731
|
-
else {
|
|
7732
|
-
|
|
7733
|
-
logWarn(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: innerHTML values do not match for element, will recover from the difference`, owner);
|
|
7734
|
-
}
|
|
7805
|
+
else if (process.env.NODE_ENV !== 'production') {
|
|
7806
|
+
queueHydrationError('innerHTML', unwrappedServerInnerHTML, unwrappedClientInnerHTML);
|
|
7735
7807
|
}
|
|
7736
7808
|
}
|
|
7737
7809
|
}
|
|
@@ -7754,8 +7826,7 @@ function hydrateCustomElement(elm, vnode, renderer) {
|
|
|
7754
7826
|
//
|
|
7755
7827
|
// Therefore, if validationOptOut is falsey or an array of strings, we need to
|
|
7756
7828
|
// examine some or all of the custom element's attributes.
|
|
7757
|
-
if (!
|
|
7758
|
-
!isMatchingElement(vnode, elm, renderer, shouldValidateAttr)) {
|
|
7829
|
+
if (!isTypeElement(elm) || !isMatchingElement(vnode, elm, renderer, shouldValidateAttr)) {
|
|
7759
7830
|
return handleMismatch(elm, vnode, renderer);
|
|
7760
7831
|
}
|
|
7761
7832
|
const { sel, mode, ctor, owner } = vnode;
|
|
@@ -7791,9 +7862,13 @@ function hydrateChildren(node, children, parentNode, owner,
|
|
|
7791
7862
|
// last node of the fragment. Hydration should not fail if a trailing sibling is
|
|
7792
7863
|
// found in this case.
|
|
7793
7864
|
expectAddlSiblings) {
|
|
7794
|
-
let
|
|
7865
|
+
let mismatchedChildren = false;
|
|
7795
7866
|
let nextNode = node;
|
|
7796
7867
|
const { renderer } = owner;
|
|
7868
|
+
const { getChildNodes, cloneNode } = renderer;
|
|
7869
|
+
const serverNodes = process.env.NODE_ENV !== 'production'
|
|
7870
|
+
? Array.from(getChildNodes(parentNode), (node) => cloneNode(node, true))
|
|
7871
|
+
: null;
|
|
7797
7872
|
for (let i = 0; i < children.length; i++) {
|
|
7798
7873
|
const childVnode = children[i];
|
|
7799
7874
|
if (!isNull(childVnode)) {
|
|
@@ -7801,13 +7876,7 @@ expectAddlSiblings) {
|
|
|
7801
7876
|
nextNode = hydrateNode(nextNode, childVnode, renderer);
|
|
7802
7877
|
}
|
|
7803
7878
|
else {
|
|
7804
|
-
|
|
7805
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
7806
|
-
if (!hasWarned) {
|
|
7807
|
-
hasWarned = true;
|
|
7808
|
-
logWarn(`Hydration mismatch: incorrect number of rendered nodes. Client produced more nodes than the server.`, owner);
|
|
7809
|
-
}
|
|
7810
|
-
}
|
|
7879
|
+
mismatchedChildren = true;
|
|
7811
7880
|
mount(childVnode, parentNode, renderer, nextNode);
|
|
7812
7881
|
nextNode = renderer.nextSibling(childVnode.type === 5 /* VNodeType.Fragment */ ? childVnode.trailing : childVnode.elm);
|
|
7813
7882
|
}
|
|
@@ -7824,12 +7893,7 @@ expectAddlSiblings) {
|
|
|
7824
7893
|
// rendered more nodes than the client.
|
|
7825
7894
|
(!useCommentsForBookends || !expectAddlSiblings) &&
|
|
7826
7895
|
nextNode) {
|
|
7827
|
-
|
|
7828
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
7829
|
-
if (!hasWarned) {
|
|
7830
|
-
logWarn(`Hydration mismatch: incorrect number of rendered nodes. Server rendered more nodes than the client.`, owner);
|
|
7831
|
-
}
|
|
7832
|
-
}
|
|
7896
|
+
mismatchedChildren = true;
|
|
7833
7897
|
// nextSibling is mostly harmless, and since we don't have
|
|
7834
7898
|
// a good reference to what element to act upon, we instead
|
|
7835
7899
|
// rely on the vm's associated renderer for navigating to the
|
|
@@ -7841,6 +7905,14 @@ expectAddlSiblings) {
|
|
|
7841
7905
|
removeNode(current, parentNode, renderer);
|
|
7842
7906
|
} while (nextNode);
|
|
7843
7907
|
}
|
|
7908
|
+
if (mismatchedChildren) {
|
|
7909
|
+
hasMismatch = true;
|
|
7910
|
+
// We can't know exactly which node(s) caused the delta, but we can provide context (parent) and the mismatched sets
|
|
7911
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
7912
|
+
const clientNodes = ArrayMap.call(children, (c) => c?.elm);
|
|
7913
|
+
queueHydrationError('child node', serverNodes, clientNodes);
|
|
7914
|
+
}
|
|
7915
|
+
}
|
|
7844
7916
|
}
|
|
7845
7917
|
function handleMismatch(node, vnode, renderer) {
|
|
7846
7918
|
hasMismatch = true;
|
|
@@ -7856,31 +7928,21 @@ function patchElementPropsAndAttrsAndRefs(vnode, renderer) {
|
|
|
7856
7928
|
// The `refs` object is blown away in every re-render, so we always need to re-apply them
|
|
7857
7929
|
applyRefs(vnode, vnode.owner);
|
|
7858
7930
|
}
|
|
7859
|
-
function hasCorrectNodeType(vnode, node, nodeType, renderer) {
|
|
7860
|
-
const { getProperty } = renderer;
|
|
7861
|
-
if (getProperty(node, 'nodeType') !== nodeType) {
|
|
7862
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
7863
|
-
logWarn('Hydration mismatch: incorrect node type received', vnode.owner);
|
|
7864
|
-
}
|
|
7865
|
-
return false;
|
|
7866
|
-
}
|
|
7867
|
-
return true;
|
|
7868
|
-
}
|
|
7869
7931
|
function isMatchingElement(vnode, elm, renderer, shouldValidateAttr = () => true) {
|
|
7870
7932
|
const { getProperty } = renderer;
|
|
7871
7933
|
if (vnode.sel.toLowerCase() !== getProperty(elm, 'tagName').toLowerCase()) {
|
|
7872
7934
|
if (process.env.NODE_ENV !== 'production') {
|
|
7873
|
-
|
|
7935
|
+
queueHydrationError('node', elm);
|
|
7874
7936
|
}
|
|
7875
7937
|
return false;
|
|
7876
7938
|
}
|
|
7877
7939
|
const { data } = vnode;
|
|
7878
|
-
const hasCompatibleAttrs = validateAttrs(
|
|
7940
|
+
const hasCompatibleAttrs = validateAttrs(elm, data, renderer, shouldValidateAttr);
|
|
7879
7941
|
const hasCompatibleClass = shouldValidateAttr('class')
|
|
7880
7942
|
? validateClassAttr(vnode, elm, data, renderer)
|
|
7881
7943
|
: true;
|
|
7882
7944
|
const hasCompatibleStyle = shouldValidateAttr('style')
|
|
7883
|
-
? validateStyleAttr(
|
|
7945
|
+
? validateStyleAttr(elm, data, renderer)
|
|
7884
7946
|
: true;
|
|
7885
7947
|
return hasCompatibleAttrs && hasCompatibleClass && hasCompatibleStyle;
|
|
7886
7948
|
}
|
|
@@ -7897,7 +7959,7 @@ function attributeValuesAreEqual(vnodeValue, value) {
|
|
|
7897
7959
|
// In all other cases, the two values are not considered equal
|
|
7898
7960
|
return false;
|
|
7899
7961
|
}
|
|
7900
|
-
function validateAttrs(
|
|
7962
|
+
function validateAttrs(elm, data, renderer, shouldValidateAttr) {
|
|
7901
7963
|
const { attrs = {} } = data;
|
|
7902
7964
|
let nodesAreCompatible = true;
|
|
7903
7965
|
// Validate attributes, though we could always recovery from those by running the update mods.
|
|
@@ -7910,8 +7972,7 @@ function validateAttrs(vnode, elm, data, renderer, shouldValidateAttr) {
|
|
|
7910
7972
|
const elmAttrValue = getAttribute(elm, attrName);
|
|
7911
7973
|
if (!attributeValuesAreEqual(attrValue, elmAttrValue)) {
|
|
7912
7974
|
if (process.env.NODE_ENV !== 'production') {
|
|
7913
|
-
|
|
7914
|
-
logWarn(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: attribute "${attrName}" has different values, expected "${attrValue}" but found ${isNull(elmAttrValue) ? 'null' : `"${elmAttrValue}"`}`, vnode.owner);
|
|
7975
|
+
queueHydrationError('attribute', prettyPrintAttribute(attrName, elmAttrValue), prettyPrintAttribute(attrName, attrValue));
|
|
7915
7976
|
}
|
|
7916
7977
|
nodesAreCompatible = false;
|
|
7917
7978
|
}
|
|
@@ -7939,7 +8000,6 @@ function validateClassAttr(vnode, elm, data, renderer) {
|
|
|
7939
8000
|
// classMap is never available on VStaticPartData so it can default to undefined
|
|
7940
8001
|
// casting to prevent TS error.
|
|
7941
8002
|
const { className, classMap } = data;
|
|
7942
|
-
const { getProperty } = renderer;
|
|
7943
8003
|
// ---------- Step 1: get the classes from the element and the vnode
|
|
7944
8004
|
// Use a Set because we don't care to validate mismatches for 1) different ordering in SSR vs CSR, or 2)
|
|
7945
8005
|
// duplicated class names. These don't have an effect on rendered styles.
|
|
@@ -7985,12 +8045,11 @@ function validateClassAttr(vnode, elm, data, renderer) {
|
|
|
7985
8045
|
// ---------- Step 3: check for compatibility
|
|
7986
8046
|
const classesAreCompatible = checkClassesCompatibility(vnodeClasses, elmClasses);
|
|
7987
8047
|
if (process.env.NODE_ENV !== 'production' && !classesAreCompatible) {
|
|
7988
|
-
|
|
7989
|
-
logWarn(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: attribute "class" has different values, expected ${prettyPrint(vnodeClasses)} but found ${prettyPrint(elmClasses)}`, vnode.owner);
|
|
8048
|
+
queueHydrationError('attribute', prettyPrintClasses(elmClasses), prettyPrintClasses(vnodeClasses));
|
|
7990
8049
|
}
|
|
7991
8050
|
return classesAreCompatible;
|
|
7992
8051
|
}
|
|
7993
|
-
function validateStyleAttr(
|
|
8052
|
+
function validateStyleAttr(elm, data, renderer) {
|
|
7994
8053
|
// Note styleDecls is always undefined for VStaticPartData, casting here to default it to undefined
|
|
7995
8054
|
const { style, styleDecls } = data;
|
|
7996
8055
|
const { getAttribute } = renderer;
|
|
@@ -8024,49 +8083,33 @@ function validateStyleAttr(vnode, elm, data, renderer) {
|
|
|
8024
8083
|
}
|
|
8025
8084
|
vnodeStyle = ArrayJoin.call(expectedStyle, ' ');
|
|
8026
8085
|
}
|
|
8027
|
-
if (!nodesAreCompatible) {
|
|
8028
|
-
|
|
8029
|
-
const { getProperty } = renderer;
|
|
8030
|
-
logWarn(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: attribute "style" has different values, expected "${vnodeStyle}" but found "${elmStyle}".`, vnode.owner);
|
|
8031
|
-
}
|
|
8086
|
+
if (process.env.NODE_ENV !== 'production' && !nodesAreCompatible) {
|
|
8087
|
+
queueHydrationError('attribute', prettyPrintAttribute('style', elmStyle), prettyPrintAttribute('style', vnodeStyle));
|
|
8032
8088
|
}
|
|
8033
8089
|
return nodesAreCompatible;
|
|
8034
8090
|
}
|
|
8035
|
-
function
|
|
8091
|
+
function areStaticElementsCompatible(clientElement, serverElement, vnode, renderer) {
|
|
8036
8092
|
const { getProperty, getAttribute } = renderer;
|
|
8037
|
-
|
|
8038
|
-
if (!hasCorrectNodeType(vnode, ssr, 3 /* EnvNodeTypes.TEXT */, renderer)) {
|
|
8039
|
-
return false;
|
|
8040
|
-
}
|
|
8041
|
-
return getProperty(client, NODE_VALUE_PROP) === getProperty(ssr, NODE_VALUE_PROP);
|
|
8042
|
-
}
|
|
8043
|
-
if (getProperty(client, 'nodeType') === 8 /* EnvNodeTypes.COMMENT */) {
|
|
8044
|
-
if (!hasCorrectNodeType(vnode, ssr, 8 /* EnvNodeTypes.COMMENT */, renderer)) {
|
|
8045
|
-
return false;
|
|
8046
|
-
}
|
|
8047
|
-
return getProperty(client, NODE_VALUE_PROP) === getProperty(ssr, NODE_VALUE_PROP);
|
|
8048
|
-
}
|
|
8049
|
-
if (!hasCorrectNodeType(vnode, ssr, 1 /* EnvNodeTypes.ELEMENT */, renderer)) {
|
|
8050
|
-
return false;
|
|
8051
|
-
}
|
|
8052
|
-
const { owner, parts } = vnode;
|
|
8093
|
+
const { parts } = vnode;
|
|
8053
8094
|
let isCompatibleElements = true;
|
|
8054
|
-
if (getProperty(
|
|
8095
|
+
if (getProperty(clientElement, 'tagName') !== getProperty(serverElement, 'tagName')) {
|
|
8055
8096
|
if (process.env.NODE_ENV !== 'production') {
|
|
8056
|
-
|
|
8097
|
+
queueHydrationError('node', serverElement);
|
|
8057
8098
|
}
|
|
8058
8099
|
return false;
|
|
8059
8100
|
}
|
|
8060
|
-
const clientAttrsNames = getProperty(
|
|
8101
|
+
const clientAttrsNames = getProperty(clientElement, 'getAttributeNames').call(clientElement);
|
|
8061
8102
|
clientAttrsNames.forEach((attrName) => {
|
|
8062
|
-
|
|
8103
|
+
const clientAttributeValue = getAttribute(clientElement, attrName);
|
|
8104
|
+
const serverAttributeValue = getAttribute(serverElement, attrName);
|
|
8105
|
+
if (clientAttributeValue !== serverAttributeValue) {
|
|
8063
8106
|
// Check if the root element attributes have expressions, if it does then we need to delegate hydration
|
|
8064
8107
|
// validation to haveCompatibleStaticParts.
|
|
8065
8108
|
// Note if there are no parts then it is a fully static fragment.
|
|
8066
8109
|
// partId === 0 will always refer to the root element, this is guaranteed by the compiler.
|
|
8067
8110
|
if (parts?.[0].partId !== 0) {
|
|
8068
8111
|
if (process.env.NODE_ENV !== 'production') {
|
|
8069
|
-
|
|
8112
|
+
queueHydrationError('attribute', prettyPrintAttribute(attrName, serverAttributeValue), prettyPrintAttribute(attrName, clientAttributeValue));
|
|
8070
8113
|
}
|
|
8071
8114
|
isCompatibleElements = false;
|
|
8072
8115
|
}
|
|
@@ -8075,7 +8118,7 @@ function areCompatibleStaticNodes(client, ssr, vnode, renderer) {
|
|
|
8075
8118
|
return isCompatibleElements;
|
|
8076
8119
|
}
|
|
8077
8120
|
function haveCompatibleStaticParts(vnode, renderer) {
|
|
8078
|
-
const { parts
|
|
8121
|
+
const { parts } = vnode;
|
|
8079
8122
|
if (isUndefined$1(parts)) {
|
|
8080
8123
|
return true;
|
|
8081
8124
|
}
|
|
@@ -8086,11 +8129,11 @@ function haveCompatibleStaticParts(vnode, renderer) {
|
|
|
8086
8129
|
for (const part of parts) {
|
|
8087
8130
|
const { elm } = part;
|
|
8088
8131
|
if (isVStaticPartElement(part)) {
|
|
8089
|
-
if (!
|
|
8132
|
+
if (!isTypeElement(elm)) {
|
|
8090
8133
|
return false;
|
|
8091
8134
|
}
|
|
8092
8135
|
const { data } = part;
|
|
8093
|
-
const hasMatchingAttrs = validateAttrs(
|
|
8136
|
+
const hasMatchingAttrs = validateAttrs(elm, data, renderer, () => true);
|
|
8094
8137
|
// Explicitly skip hydration validation when static parts don't contain `style` or `className`.
|
|
8095
8138
|
// This means the style/class attributes are either static or don't exist on the element and
|
|
8096
8139
|
// cannot be affected by hydration.
|
|
@@ -8100,7 +8143,7 @@ function haveCompatibleStaticParts(vnode, renderer) {
|
|
|
8100
8143
|
? validateClassAttr(vnode, elm, data, renderer)
|
|
8101
8144
|
: true;
|
|
8102
8145
|
const hasMatchingStyleAttr = shouldValidateAttr(data, 'style')
|
|
8103
|
-
? validateStyleAttr(
|
|
8146
|
+
? validateStyleAttr(elm, data, renderer)
|
|
8104
8147
|
: true;
|
|
8105
8148
|
if (isFalse(hasMatchingAttrs && hasMatchingClass && hasMatchingStyleAttr)) {
|
|
8106
8149
|
return false;
|
|
@@ -8108,10 +8151,10 @@ function haveCompatibleStaticParts(vnode, renderer) {
|
|
|
8108
8151
|
}
|
|
8109
8152
|
else {
|
|
8110
8153
|
// VStaticPartText
|
|
8111
|
-
if (!
|
|
8154
|
+
if (!isTypeText(elm)) {
|
|
8112
8155
|
return false;
|
|
8113
8156
|
}
|
|
8114
|
-
updateTextContent(elm, part,
|
|
8157
|
+
updateTextContent(elm, part, renderer);
|
|
8115
8158
|
}
|
|
8116
8159
|
}
|
|
8117
8160
|
return true;
|
|
@@ -8377,5 +8420,5 @@ function readonly(obj) {
|
|
|
8377
8420
|
}
|
|
8378
8421
|
|
|
8379
8422
|
export { BaseBridgeElement, LightningElement, profilerControl as __unstable__ProfilerControl, reportingControl as __unstable__ReportingControl, api$1 as api, computeShadowAndRenderMode, connectRootElement, createContextProviderWithRegister, createVM, disconnectRootElement, freezeTemplate, getAssociatedVMIfPresent, getComponentAPIVersion, getComponentConstructor, getComponentDef, getComponentHtmlPrototype, hydrateRoot, isComponentConstructor, parseFragment, parseSVGFragment, readonly, registerComponent, registerDecorators, registerTemplate, runFormAssociatedCallback, runFormDisabledCallback, runFormResetCallback, runFormStateRestoreCallback, sanitizeAttribute, shouldBeFormAssociated, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
|
|
8380
|
-
/** version: 8.12.
|
|
8423
|
+
/** version: 8.12.5 */
|
|
8381
8424
|
//# sourceMappingURL=index.js.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/engine-core",
|
|
7
|
-
"version": "8.12.
|
|
7
|
+
"version": "8.12.5",
|
|
8
8
|
"description": "Core LWC engine APIs.",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"lwc"
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lwc/features": "8.12.
|
|
50
|
-
"@lwc/shared": "8.12.
|
|
51
|
-
"@lwc/signals": "8.12.
|
|
49
|
+
"@lwc/features": "8.12.5",
|
|
50
|
+
"@lwc/shared": "8.12.5",
|
|
51
|
+
"@lwc/signals": "8.12.5"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"observable-membrane": "2.0.0"
|