Skip to content

Commit

Permalink
fix: skip hydration validation when static parts have static classes (#…
Browse files Browse the repository at this point in the history
…4278)


---------

Co-authored-by: Nolan Lawson <[email protected]>
  • Loading branch information
jmsjtu and nolanlawson authored Jun 11, 2024
1 parent 752cc83 commit 345c68d
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 2 deletions.
12 changes: 10 additions & 2 deletions packages/@lwc/engine-core/src/framework/hydration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ function haveCompatibleStaticParts(vnode: VStatic, renderer: RendererAPI) {
return true;
}

const shouldValidateAttr = (data: VStaticPartData, attrName: string) => attrName in data;
// The validation here relies on 2 key invariants:
// 1. It's never the case that `parts` is undefined on the server but defined on the client (or vice-versa)
// 2. It's never the case that `parts` has one length on the server but another on the client
Expand All @@ -826,8 +827,15 @@ function haveCompatibleStaticParts(vnode: VStatic, renderer: RendererAPI) {
}
const { data } = part;
const hasMatchingAttrs = validateAttrs(vnode, elm, data, renderer, () => true);
const hasMatchingStyleAttr = validateStyleAttr(vnode, elm, data, renderer);
const hasMatchingClass = validateClassAttr(vnode, elm, data, renderer);
// Explicitly skip hydration validation when static parts don't contain `style` or `className`.
// This means the style/class attributes are either static or don't exist on the element and
// cannot be affected by hydration.
const hasMatchingStyleAttr = shouldValidateAttr(data, 'style')
? validateStyleAttr(vnode, elm, data, renderer)
: true;
const hasMatchingClass = shouldValidateAttr(data, 'className')
? validateClassAttr(vnode, elm, data, renderer)
: true;
if (isFalse(hasMatchingAttrs && hasMatchingStyleAttr && hasMatchingClass)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default {
props: {
s1: 's1',
},
snapshot(target) {
const p = target.shadowRoot.querySelector('p');
return {
p,
classes: p.className,
};
},
test(target, snapshots, consoleCalls) {
const p = target.shadowRoot.querySelector('p');

expect(p).toBe(snapshots.p);
expect(p.className).toBe(snapshots.classes);
// static classes are skipped by hydration validation
expect(consoleCalls.error).toHaveSize(0);
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<template>
<!-- presence of a dynamic attribute creates a static part -->
<p class="c1" style={s1}>text</p>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { LightningElement, api } from 'lwc';

export default class Main extends LightningElement {
@api s1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default {
snapshot(target) {
const p = target.shadowRoot.querySelector('p');
return {
p,
classes: p.className,
};
},
test(target, snapshots) {
const p = target.shadowRoot.querySelector('p');

expect(p).toBe(snapshots.p);
expect(p.className).toBe(snapshots.classes);
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<p class="c1">text</p>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { LightningElement } from 'lwc';

export default class Main extends LightningElement {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default {
props: {
c1: 'c1',
},
snapshot(target) {
const p = target.shadowRoot.querySelector('p');
return {
p,
style: p.getAttribute('style'),
};
},
test(target, snapshots, consoleCalls) {
const p = target.shadowRoot.querySelector('p');

expect(p).toBe(snapshots.p);
expect(p.getAttribute('style')).toBe(snapshots.style);
// static classes are skipped by hydration validation
expect(consoleCalls.error).toHaveSize(0);
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<template>
<!-- presence of a dynamic attribute creates a static part -->
<p class={c1} style="background: blue">text</p>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { LightningElement, api } from 'lwc';

export default class Main extends LightningElement {
@api c1;
}

0 comments on commit 345c68d

Please sign in to comment.