Skip to content

Commit 47c46eb

Browse files
feat: refactored hydration logging and related tests (#5086)
* feat: refactored hydration logging, related test changes * fix: remove console usage * fix: stringify * fix: reduce nodes to nodeName for browser parity * fix: disable_static_content_optimization test exceptions, logging refactor * fix: changes for bundle size reduction * fix: remove redundant non-prod checks * fix: irregular naming, type guard * fix: review comments * fix: typing for static element comparison * fix: missing util * fix: move pretty print classes to util * fix: naming, attribute prettifier * fix: rename logging function
1 parent f080072 commit 47c46eb

File tree

47 files changed

+316
-270
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+316
-270
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright (c) 2024, Salesforce, Inc.
3+
* All rights reserved.
4+
* SPDX-License-Identifier: MIT
5+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
6+
*/
7+
import { ArrayPush, ArrayJoin, ArraySort, ArrayFrom, isNull, isUndefined } from '@lwc/shared';
8+
9+
import { assertNotProd } from './utils';
10+
11+
// Errors that occured during the hydration process
12+
let hydrationErrors: Array<HydrationError> = [];
13+
14+
// These values are the ones from Node.nodeType (https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType)
15+
const enum EnvNodeTypes {
16+
ELEMENT = 1,
17+
TEXT = 3,
18+
COMMENT = 8,
19+
}
20+
21+
interface HydrationError {
22+
type: string;
23+
serverRendered: any;
24+
clientExpected: any;
25+
}
26+
27+
export type Classes = Omit<Set<string>, 'add'>;
28+
29+
/*
30+
Prints attributes as null or "value"
31+
*/
32+
export function prettyPrintAttribute(attribute: string, value: any): string {
33+
assertNotProd(); // this method should never leak to prod
34+
return `${attribute}=${isNull(value) || isUndefined(value) ? value : `"${value}"`}`;
35+
}
36+
37+
/*
38+
Sorts and stringifies classes
39+
*/
40+
export function prettyPrintClasses(classes: Classes) {
41+
assertNotProd(); // this method should never leak to prod
42+
const value = JSON.stringify(ArrayJoin.call(ArraySort.call(ArrayFrom(classes)), ' '));
43+
return `class=${value}`;
44+
}
45+
46+
/*
47+
Hydration errors occur before the source node has been fully hydrated,
48+
queue them so they can be logged later against the mounted node.
49+
*/
50+
export function queueHydrationError(type: string, serverRendered?: any, clientExpected?: any) {
51+
assertNotProd(); // this method should never leak to prod
52+
ArrayPush.call(hydrationErrors, { type, serverRendered, clientExpected });
53+
}
54+
55+
/*
56+
Flushes (logs) any queued errors after the source node has been mounted.
57+
*/
58+
export function flushHydrationErrors(source?: Node | null) {
59+
assertNotProd(); // this method should never leak to prod
60+
for (const hydrationError of hydrationErrors) {
61+
logHydrationWarning(
62+
`Hydration ${hydrationError.type} mismatch on:`,
63+
source,
64+
`\n- rendered on server:`,
65+
hydrationError.serverRendered,
66+
`\n- expected on client:`,
67+
hydrationError.clientExpected || source
68+
);
69+
}
70+
hydrationErrors = [];
71+
}
72+
73+
export function isTypeElement(node?: Node): node is Element {
74+
const isCorrectType = node?.nodeType === EnvNodeTypes.ELEMENT;
75+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
76+
queueHydrationError('node', node);
77+
}
78+
return isCorrectType;
79+
}
80+
81+
export function isTypeText(node?: Node): node is Text {
82+
const isCorrectType = node?.nodeType === EnvNodeTypes.TEXT;
83+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
84+
queueHydrationError('node', node);
85+
}
86+
return isCorrectType;
87+
}
88+
89+
export function isTypeComment(node?: Node): node is Comment {
90+
const isCorrectType = node?.nodeType === EnvNodeTypes.COMMENT;
91+
if (process.env.NODE_ENV !== 'production' && !isCorrectType) {
92+
queueHydrationError('node', node);
93+
}
94+
return isCorrectType;
95+
}
96+
97+
/*
98+
logger.ts converts all args to a string, losing object referenences and has
99+
legacy bloat which would have meant more pathing.
100+
*/
101+
export function logHydrationWarning(...args: any) {
102+
assertNotProd(); // this method should never leak to prod
103+
/* eslint-disable-next-line no-console */
104+
console.warn('[LWC warn:', ...args);
105+
}

0 commit comments

Comments
 (0)