Conversation
Co-authored-by: Justin Fagnani <justin@fagnani.com>
Co-authored-by: Justin Fagnani <justin@fagnani.com>
🦋 Changeset detectedLatest commit: b3d4fb0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📊 Tachometer Benchmark ResultsSummarynop-update
render
update
update-reflect
Resultsthis-change
render
update
update-reflect
this-change, tip-of-tree, previous-release
render
update
nop-update
this-change, tip-of-tree, previous-release
render
update
this-change, tip-of-tree, previous-release
render
update
update-reflect
|
|
The size of lit-html.js and lit-core.min.js are as expected. |
skipInitial property optionuseDefault property option
Co-authored-by: Justin Fagnani <justinfagnani@google.com>
|
We are encountering an issue in the Chromium codebase as part of migrating to using the Please see https://issues.chromium.org/issues/389737066#comment12 for more context or directly see this minimal Lit playground repro
Completely ignoring the initial value would probably not work for us, as we are already getting failed tests when migrating to the Having said that, if this option indeed solves our issue (tried it on the minimal repro in the playground, but didn't, perhaps not rolled out yet?), we would still need to add |
|
@freshp86 can you open an issue? It seems like the issues is that with experimental decorators and auto-accessors, the initial value isn't reflected? I'll have to check our tests for that case. @sorvell on the linked playground, adding |
No issue is needed. This change corrects this behavior. @freshp86 This PR should also fix your issue, regardless of using As @justinfagnani mentioned, while waiting for this release, you can add |
Thanks for the quick response! I verified that adding
Do you have any estimate on when the next release will come out? In Chromium we still use v3.0.2 here, which is already behind latest 3.2.1, so we'll need to roll forward a few versions to get this fix. In the meantime, do you think locally patching these lines that you referernced in our Chromium copy of Lit would be sufficient to fix the issue, without us having to update to later releases (and without having to add |
I think it's probably simpler to use the undocumented |
* Adds skipping initial attribute reflection for default values.
|
Might have found an even easier fix for us, which does not require updating client code with |
If you have a base class, probably the simplest way would be: static createProperty(name, options) {
super.createProperty(name, {...options, wrapped: true});
} |
Don't we need to check for |
It's only strictly needed there, but you don't need to discriminate it. Setting
No, it should not be based on the value of |
|
Thanks for the info! I will update my CL and tests at https://chromium-review.googlesource.com/c/chromium/src/+/6349561 and I might add you as a reviewer as well if you don't mind. Thanks! |
So, while writing tests to test changed properties as well, discovered that there is still a difference in behavior between non-accessor and acessor properties on first load. Minimal repro here. In short willUpdate(changedProperties: PropertyValues<this>) {
super.willUpdate(changedProperties);
// expecting 'undefined', but instead initial value is reported as the "previous" value.
console.log(changedProperties.get('someAccessorProperty'));
} |
Yeah, I should have mentioned that. This is also fixed in this change, and you can patch it in if you need, but it's also technically safe to do in your base class like this (since override protected performUpdate() {
if (!this.isUpdatePending) {
return;
}
// this loop is duplicated in the super call but the work won't occur twice due to the
// `_$changedProperties` check
if (!this.hasUpdated) {
const {elementProperties} = (this.constructor as typeof ReactiveElement);
for (const [p, options] of elementProperties) {
if (options.wrapped === true && !this._$changedProperties.has(p) &&
this[p as keyof this] !== undefined) {
this._$changeProperty(p, undefined, options);
}
}
}
super.performUpdate();
} |
|
Thanks for the detailed response, this is indeed very helpful and does fix the issue! Having said that, fixing the issue in our override performUpdate() {
if (!this.isUpdatePending) {
return;
}
if (!this.hasUpdated) {
interface WithInternalApis extends CrLitElement {
// minified name for $changedProperties
_$AL: PropertyValues;
// minified name for _$changeProperty()
C(p: PropertyKey, v: any, options: any): void;
}
const {elementProperties} = this.constructor as typeof ReactiveElement;
for (const [p, options] of elementProperties) {
if ((options as {wrapped?: boolean}).wrapped === true &&
!(this as unknown as WithInternalApis)._$AL.has(p) &&
this[p as keyof this] !== undefined) {
(this as unknown as WithInternalApis).C(p, undefined, options);
}
}
}
super.performUpdate();
}I think this qualifies as a hack :> You can see the complete change at https://chromium-review.googlesource.com/c/chromium/src/+/6349561/7/third_party/lit/v3_0/cr_lit_element.ts. So, the sooner we can get the official fix the sooner we can remove this hack. Rolling our Lit version to the latest Lit version is also blocked by #4943, so the current plan is
Thanks again! |
This is necessary to workaround a bug when the 'accessor' keyword is used where Lit doesn't reflect the initial value when 'reflect: true' is used, nor does it populate `changedProperties` correctly (see minimal repro at [1] and [2] respectively). The bug has been recently fixed in Lit at [3] but is not available in any Lit release yet. These workarounds here were mentioned in the discussion at [3]. Workaround#1: Add the undocumented `wrapped: true` property option for properties that are using the 'accessor' keyword. Workaround#2: Modify `changedProperties` previous value to be `undefined` to match the behavior of normal (non-wrapped) properties. The plan is to remove these workarounds when the fixes are available in an upcoming Lit release. [1] http://shortn/_FCrUJIGsR7 [2] http://shortn/_5l2Q3hBfr0 [3] lit/lit#4934 Bug: 389737066 Change-Id: Ib032ce41c9c1fa9647a0ec7c9e629a869cc3892d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6349561 Reviewed-by: Rebekah Potter <rbpotter@chromium.org> Commit-Queue: Demetrios Papadopoulos <dpapad@chromium.org> Cr-Commit-Position: refs/heads/main@{#1432900}
|
@sorvell Unfortunately discovered one more difference in changed properties behavior between wrapped and non-wrapped properties, when a value is passed from the parent, see new minimal repro here, where the 'previous' value of the 1st Note that the problem happens even if the if (options.wrapped === true && !this._$changedProperties.has(p) && this[p] !== undefined) {
this._$changeProperty(p, undefined, options);
}and the Do you know if the fix in this PR addresses this, or if this is just a problem with the temporary workaround we discussed in earlier comments. Is there a way to make these cases behave identically across wrapped and non-wrapped properties? Update: Possible refinement to our workaround is to directly call Perhaps calling both as follows is necessary? this._$changeProperty(p, undefined, options);
this._$changedProperties.set(p, undefined);Ultimately I think we need a way to skip the if check at this line https://github.com/lit/lit/blob/main/packages/reactive-element/src/reactive-element.ts#L1338. |
No, see #4916 where I linked your comment. Maybe best to continue, if needed, there. |
Fixes a regression from #4934 which collapsed all converted nullish values to null.
* fromAttribute can set the property to either null or undefined. Fixes a regression from #4934 which collapsed all converted nullish values to null. * Update .changeset/many-grapes-rest.md Co-authored-by: Augustine Kim <augustjkim@gmail.com>
Note: This is an alternative to #4895, only one should be merged.
Adds support for lit/rfcs#36 and helps facilitate shoelace-style/shoelace#2339.
Spawning an initial attribute can cause a NextJS hydration error, see repro.
To use, set
useDefaultin property options, and make sure to set an initial value in the field/accessor.Note, using
accessoris encouraged but not required. This setting can also be used instatic propertiesand on custom getters/setters.Previously, this would spawn a
variant="foo"attribute. With this PR and the above settings, it will not.In addition, the initial value will be set when the attribute is removed.